Java tutorial
/* * Copyright (c) 2009 - 2010. School of Information Technology and Electrical * Engineering, The University of Queensland. This software is being developed * for the "Phenomics Ontoogy Driven Data Management Project (PODD)" project. * PODD is a National e-Research Architecture Taskforce (NeAT) project * co-funded by ANDS and ARCS. * * PODD is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * PODD is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with PODD. If not, see <http://www.gnu.org/licenses/>. */ package podd.resources.services; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.json.JSONObject; import org.restlet.data.Status; import org.restlet.ext.fileupload.RestletFileUpload; import org.restlet.ext.json.JsonRepresentation; import org.restlet.representation.Representation; import org.restlet.representation.Variant; import org.restlet.resource.ResourceException; import podd.dataaccess.PoddObjectDAO; import podd.exception.DataAccessException; import podd.model.entity.PoddObject; import podd.resources.AccessControlledResource; import podd.resources.services.util.JsonHelper; import podd.resources.util.RemoteFileHelper; import podd.util.rdf.RDFHelper; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import static org.restlet.data.Status.CLIENT_ERROR_BAD_REQUEST; import static org.restlet.data.Status.CLIENT_ERROR_UNAUTHORIZED; import static org.restlet.data.Status.SERVER_ERROR_INTERNAL; import static podd.model.audit.AuditLog.ERROR; import static podd.model.audit.AuditLog.INSUFFICIENT_ACCESS; import static podd.resources.util.RemoteFileHelper.getShortName; import static podd.server.authz.UserAction.UPDATE; /** * @author Yuan-Fang Li * @version $Id$ */ public class LocalFileAttachmentService extends AccessControlledResource { @Deprecated private RDFHelper rdfHelper; private JsonHelper jsonHelper; private PoddObjectDAO objectDao; private RemoteFileHelper remoteFileHelper; private String objectURI; private Map<String, String> errorMap; private PoddObject poddObject; protected static final Pattern DESCRIPTION_NAME_PATTERN = Pattern.compile("desc(\\d*)$", Pattern.CASE_INSENSITIVE); protected static final Pattern FILE_NAME_PATTERN = Pattern.compile("file(\\d*)$", Pattern.CASE_INSENSITIVE); private Map<Integer, String> fileDescMap; private Map<Integer, FileItem> fileMap; public void setRdfHelper(RDFHelper rdfHelper) { this.rdfHelper = rdfHelper; } public void setJsonHelper(JsonHelper jsonHelper) { this.jsonHelper = jsonHelper; } public void setObjectDao(PoddObjectDAO objectDao) { this.objectDao = objectDao; } public void setRemoteFileHelper(RemoteFileHelper remoteFileHelper) { this.remoteFileHelper = remoteFileHelper; } @Override protected Representation doAuthenticatedGet(Variant variant) throws ResourceException { getResponse().setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED); final String msg = "GET method not supported. Please use POST instead."; errorMap.put("errorMessage", msg); auditLogHelper.auditAction(INSUFFICIENT_ACCESS, authenticatedUser, this.getRequest().getResourceRef().toString(), msg); return new JsonRepresentation(jsonHelper.convertSimpleErrorMap(errorMap)); } @Override protected boolean authoriseGet() { // if there is no object we still want the user to get error message, so allow access if (null == poddObject) { return true; } return manager.decide(authenticatedUser, poddObject, UPDATE); } @Override protected Representation doAuthenticatedPost(Representation entity, Variant variant) throws ResourceException { if (!errorMap.isEmpty()) { return new JsonRepresentation(jsonHelper.convertSimpleErrorMap(errorMap)); } try { if (!checkParameters()) { getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST); errorMap.put("errorMessage", "Files and descriptions not matching."); } else { remoteFileHelper.attachLocalFiles(poddObject, fileMap, fileDescMap, authenticatedUser.getUserName()); try { objectDao.update(poddObject); final JSONObject jsonObject = getAttachedFileURLs(fileMap); return new JsonRepresentation(jsonObject); } catch (DataAccessException e) { final String msg = "Error updating object: " + poddObject.getPid() + ". "; errorMap.put("errorMessage", msg); LOGGER.error(msg, e); auditLogHelper.auditAction(ERROR, authenticatedUser, "File Attachment Service: " + msg, e.toString()); objectDao.refresh(poddObject); } } } catch (Exception e) { getResponse().setStatus(SERVER_ERROR_INTERNAL); final String msg = "Error attaching files to object: " + poddObject + ". " + e.getMessage(); errorMap.put("errorMessage", msg); LOGGER.error(msg, e); auditLogHelper.auditAction(ERROR, authenticatedUser, "File Attachment Service: " + msg, e.toString()); } return new JsonRepresentation(jsonHelper.convertSimpleErrorMap(errorMap)); } private boolean checkParameters() { boolean valid = fileDescMap.keySet().equals(fileMap.keySet()); if (valid) { final Set<String> fileNames = new HashSet<String>(); for (FileItem item : fileMap.values()) { if (fileNames.contains(item.getName())) { errorMap.put("errorMessage", "Duplicate file attached: " + item.getName()); return false; } else { fileNames.add(item.getName()); } } } return valid; } private void loadFormData(Representation entity) { fileDescMap = new LinkedHashMap<Integer, String>(); fileMap = new LinkedHashMap<Integer, FileItem>(); RestletFileUpload upload = new RestletFileUpload(new DiskFileItemFactory()); try { List<FileItem> list = upload.parseRepresentation(entity); for (FileItem item : list) { final String fieldName = item.getFieldName().trim(); if (item.isFormField()) { if ("URI".equals(fieldName)) { objectURI = item.getString().trim(); } else { String intString = getFirstGroupMatched(DESCRIPTION_NAME_PATTERN, fieldName); if (null != intString) { fileDescMap.put(Integer.parseInt(intString), item.getString()); } } } else { String intString = getFirstGroupMatched(FILE_NAME_PATTERN, fieldName); if (null != intString) { fileMap.put(Integer.parseInt(intString), item); } } } } catch (FileUploadException e) { final String msg = "Error loading form data. "; LOGGER.error(msg, e); errorMap.put("errorMessage", msg); auditLogHelper.auditAction(ERROR, authenticatedUser, "File Attachment Service: " + msg, e.toString()); getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST); } } private JSONObject getAttachedFileURLs(Map<Integer, FileItem> fileMap) { Map<String, String> dataItemURLMap = new HashMap<String, String>(); for (Integer idx : fileMap.keySet()) { FileItem item = fileMap.get(idx); final String fileName = getShortName(item.getName()); if (objectURI.endsWith("/")) { dataItemURLMap.put("file" + idx, objectURI + fileName); } else { dataItemURLMap.put("file" + idx, objectURI + "/" + fileName); } } return new JSONObject(dataItemURLMap); } private String getFirstGroupMatched(Pattern pattern, String fieldName) { final Matcher matcher = pattern.matcher(fieldName); String intString = null; if (matcher.matches() && matcher.groupCount() > 0) { intString = matcher.group(1); } return intString; } @Override protected void prePostAuthorisation(Representation entity) { LOGGER.debug("File attachment service"); errorMap = new HashMap<String, String>(); String pid = ""; poddObject = null; try { loadFormData(entity); pid = RDFHelper.getLocalNameForURIString(objectURI); } catch (IllegalArgumentException e) { getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST); final String msg = "Invalid URI: " + objectURI + ". " + e.getMessage(); LOGGER.error(msg); errorMap.put("errorMessage", msg); auditLogHelper.auditAction(ERROR, authenticatedUser, "File Attachment Service: " + msg, e.toString()); } if (errorMap.isEmpty()) { poddObject = loadObject(pid); } } @Override protected Representation doUnauthenticatedGet(Variant variant) throws ResourceException { // if was have encountered any errors before validation, we want to be able to send the correct response code back to the user getResponse().setStatus(CLIENT_ERROR_UNAUTHORIZED); if (null == authenticatedUser) { errorMap.put("errorMessage", "User must be authenticated to attach files to objects."); } else { errorMap.put("errorMessage", "User not authorized to attach files to object: " + poddObject.getPid()); } return new JsonRepresentation(jsonHelper.convertSimpleErrorMap(errorMap)); } @Override protected void preGetAuthorisation() { } private PoddObject loadObject(String pid) { PoddObject object = null; try { object = objectDao.load(pid); if (null == object) { getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST); errorMap.put("errorMessage", "Cannot find object for pid: " + pid); LOGGER.error("Cannot find object for pid: " + pid); } } catch (DataAccessException e) { getResponse().setStatus(SERVER_ERROR_INTERNAL); final String msg = "Exception loading object: " + pid + ". " + e.getMessage(); LOGGER.error(msg); errorMap.put("errorMessage", msg); auditLogHelper.auditAction(ERROR, authenticatedUser, "File Attachment Service: " + msg, e.toString()); } return object; } }