podd.resources.services.LocalFileAttachmentService.java Source code

Java tutorial

Introduction

Here is the source code for podd.resources.services.LocalFileAttachmentService.java

Source

/*
 * 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;
    }
}