podd.resources.services.TabImportService.java Source code

Java tutorial

Introduction

Here is the source code for podd.resources.services.TabImportService.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.DiskFileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.json.JSONException;
import org.json.JSONObject;
import org.restlet.data.Form;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import podd.client.PoddWebServiceException;
import podd.resources.AccessControlledResource;
import podd.resources.services.util.JsonHelper;
import podd.resources.util.FileUploadHelper;
import podd.resources.util.TabImporterFactory;
import podd.resources.util.error.SerivceErrorHandler;
import podd.tab.PoddTabException;
import podd.tab.Tab;
import podd.tab.TabImporter;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.restlet.data.Status.SERVER_ERROR_INTERNAL;
import static org.restlet.data.Status.SUCCESS_OK;
import static podd.model.audit.AuditLog.ERROR;

/**
 * Tab import service
 * 
 * Ensure that only one tab import can be executed for each user. That is, if a user attempts to perform multiple
 * submissions against the same service, reject all additional submissions.
 * 
 * @author Philip Wu
 *
 */
public class TabImportService extends AccessControlledResource {

    private static final Logger LOGGER = LoggerFactory.getLogger(TabImportService.class);
    private static final boolean _INFO = LOGGER.isInfoEnabled();
    private static final boolean _DEBUG = LOGGER.isDebugEnabled();
    private static final boolean _TRACE = LOGGER.isTraceEnabled();

    /**
     * Parameters required for this service
     */
    public static final String PARAM_ATTACHMENT = "attachment";
    public static final String PARAM_TAB = "tabFile";

    protected static final String GENERAL_MESSAGE_ID = "general-message";
    /**
     * JSON return parameters
     */
    protected static final String JSON_NUM_OBJECTS_COMPLETED = "numObjectsCompleted";
    protected static final String JSON_TOTAL_NUM_OBJECTS = "totalNumObjects";
    protected static final String JSON_ERROR = "error";

    /**
     * Get types 
     */
    public static final String GET_TYPE = "type";
    public static final String GET_TYPE_STATUS = "status";
    public static final String GET_TYPE_PROCESSING_ORDER = "processingOrder";
    public static final String GET_TYPE_IDS = "ids";
    public static final String GET_TYPE_RESET = "reset";
    public static final String GET_TYPE_ROLLBACK = "rollback";

    /**
     * The request converted into a Transfer object
     */
    private Tab tab;
    /**
     * Map of all the errors
     */
    protected Map<String, Map<String, List<String>>> errorMap;

    protected JsonHelper jsonHelper;
    protected SerivceErrorHandler errorHandler;
    /**
     * The tab Importer
     */
    protected TabImporter tabImporter;

    public JsonHelper getJsonHelper() {
        return jsonHelper;
    }

    public void setJsonHelper(JsonHelper jsonHelper) {
        this.jsonHelper = jsonHelper;
    }

    @Override
    public void doInit() throws ResourceException {
        super.doInit();
        errorMap = new HashMap<String, Map<String, List<String>>>();
        errorHandler = new SerivceErrorHandler();
        errorHandler.setAllObjectsErrorMap(errorMap);
    }

    @Override
    protected boolean authoriseGet() {
        // Any authenticated user can submit TAB files
        if (authenticatedUser != null) {
            return true;
        }
        return false;
    }

    /**
     * Report on the current progress of the tab submission
     */
    @Override
    protected Representation doAuthenticatedGet(Variant variant) throws ResourceException {

        JSONObject json = null;

        Form form = this.getRequest().getResourceRef().getQueryAsForm();
        String type = form.getFirstValue(GET_TYPE);
        if (type == null) // default to status
            type = GET_TYPE_STATUS;
        if (_DEBUG) {
            LOGGER.debug("get type = " + type);
        }
        if (type.equals(GET_TYPE_STATUS)) {

            if (_INFO) {
                LOGGER.info("Status request");
            }

            json = createJsonStatus();
            getResponse().setStatus(Status.SUCCESS_OK);
        } else if (type.equals(GET_TYPE_PROCESSING_ORDER)) {
            json = createJsonProcessingOrder();
        } else if (type.equals(GET_TYPE_IDS)) {
            json = createJsonIdMap();
        } else if (type.equals(GET_TYPE_RESET)) {
            boolean reset = reset();
            if (!reset) {
                getResponse().setStatus(Status.CLIENT_ERROR_CONFLICT);
            } else {
                json = new JSONObject(); // empty json response             
            }
        } else if (type.equals(GET_TYPE_ROLLBACK)) {
            if (_INFO) {
                LOGGER.info("Got request to rollback");
            }

            if (tabImporter != null)
                tabImporter.rollbackCreatedObjects();
        }

        Representation representation = null;
        // If there are any errors, report the errors
        if (!errorMap.isEmpty()) {
            representation = new JsonRepresentation(jsonHelper.convertErrorMap(errorMap));
            if (_DEBUG) {
                LOGGER.debug("Error: " + errorMap.toString());
            }
        } else {
            if (_DEBUG) {
                LOGGER.debug("get json response: " + json);
            }
            representation = new JsonRepresentation(json);
        }

        return representation;
    }

    @Override
    protected void preGetAuthorisation() {
    }

    @Override
    protected Representation doAuthenticatedPost(Representation entity, Variant variant) throws ResourceException {
        JsonRepresentation representation = null;
        // Check to see if the tab importer is currently busy from a previous submission
        if (tabImporter != null && !tabImporter.isCompleted()) {
            getResponse().setStatus(Status.CLIENT_ERROR_CONFLICT);
            errorHandler.handleError(GENERAL_MESSAGE_ID, "TAB Conflict",
                    "The previous TAB submission is still working.");
            LOGGER.warn("Conflicting with a previous tab submission");
        } else {

            // No conflict with existing submission
            reset();

            tabImporter = TabImporterFactory.getInstance().createTabImporter(this.getRequest(), tab);

            // Run the tabImporter in a separate thread
            Thread t = new Thread() {

                public void run() {
                    try {
                        tabImporter.importTab();
                        getResponse().setStatus(SUCCESS_OK);
                        //representation = createJsonRepresentation();
                    } catch (PoddTabException e) {
                        LOGGER.error("Found podd tab exception", e);
                        e.printStackTrace();
                        if (e.isUserError())
                            getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
                        else
                            getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);

                        errorHandler.handleError(GENERAL_MESSAGE_ID, "TAB Error", e.getMessage());
                    } catch (PoddWebServiceException e) {
                        getResponse().setStatus(Status.valueOf(e.getStatus()));
                        LOGGER.error("Found podd webservice exception", e);
                        e.printStackTrace();
                        errorHandler.handleError(GENERAL_MESSAGE_ID, "Web Service Error", e.getMessage());
                        auditLogHelper.auditAction(ERROR, authenticatedUser,
                                "Tab import Service: " + e.getMessage(), e.toString());
                    }

                    // If there are any errors, report the errors

                    if (!errorMap.isEmpty()) {
                        // Roll back any objects that were created
                        if (tabImporter != null)
                            tabImporter.rollbackCreatedObjects();

                        if (_INFO) {
                            LOGGER.info("Error: " + errorMap.toString());
                        }
                    }
                }

            };

            t.start();
        }

        // If there are any errors, report the errors

        if (!errorMap.isEmpty()) {
            // Roll back any objects that were created
            if (tabImporter != null)
                tabImporter.rollbackCreatedObjects();
            representation = new JsonRepresentation(jsonHelper.convertErrorMap(errorMap));
            if (_INFO) {
                LOGGER.info("Error: " + errorMap.toString());
            }
        } else {
            // Send response back to user that the file has being processed
            JSONObject jsonObj = new JSONObject();
            try {
                jsonObj.put("success", "Check the status of the tab importer to report the progress");
                representation = new JsonRepresentation(jsonObj);
            } catch (JSONException e) {
                e.printStackTrace();
                LOGGER.error("Found JSON exception", e);
            }
        }

        if (_DEBUG) {
            LOGGER.debug("representation=" + representation);
            LOGGER.debug("status=" + getResponse().getStatus());
        }
        return representation;
    }

    /**
     * Once finished, cleanup state
     */
    protected boolean reset() {
        // Can only reset tab importer if it is not currently running
        if (tabImporter != null && !tabImporter.isCompleted()) {
            String msg = "Unable to reset tab importer service that is currently active";
            LOGGER.warn(msg);
            errorHandler.handleError(GENERAL_MESSAGE_ID, "Reset Error", msg);
            return false;
        }

        tabImporter = null;

        return true;
    }

    @Override
    protected void prePostAuthorisation(Representation entity) {
        this.tab = createTab(entity);
    }

    /**
     * Creates a Tab transfer object from the Restlet Representation
     * @param entity
     * @return
     */
    private Tab createTab(Representation entity) {
        Tab tab = new Tab();
        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setSizeThreshold(0); // always write to disk
        RestletFileUpload upload = new RestletFileUpload(factory);
        try {
            List<FileItem> list = upload.parseRepresentation(entity);
            for (FileItem item : list) {
                if (item.getFieldName().equals(PARAM_TAB) && !item.isFormField()) {
                    tab.setTabStream(item.getInputStream());
                }
                if (item.getFieldName().equals(PARAM_ATTACHMENT) && !item.isFormField()) {
                    DiskFileItem diskFileItem = (DiskFileItem) item;

                    if (_DEBUG) {
                        LOGGER.debug("isInMemory = " + diskFileItem.isInMemory() + " diskFileItem exists = "
                                + diskFileItem.getStoreLocation().exists());
                    }

                    // If the file is not on disk, force to disk
                    File copiedFile = FileUploadHelper.writeToDisk(diskFileItem, authenticatedUser);
                    if (_DEBUG) {
                        LOGGER.debug("copiedFile = " + copiedFile);
                    }

                    if (copiedFile != null)
                        tab.addAttachment(copiedFile.getName(), copiedFile);
                }
            }
        } catch (FileUploadException e) {
            getResponse().setStatus(SERVER_ERROR_INTERNAL);
            final String msg = "Error reading form data. ";
            errorHandler.handleException(GENERAL_MESSAGE_ID, "File Initialisation Error", msg, e);
            auditLogHelper.auditAction(ERROR, authenticatedUser, "Tab import Service: " + msg, e.toString());
        } catch (IOException e) {
            getResponse().setStatus(SERVER_ERROR_INTERNAL);
            final String msg = "Error reading file. ";
            errorHandler.handleException(GENERAL_MESSAGE_ID, "File Initalisation Error", msg, e);
            auditLogHelper.auditAction(ERROR, authenticatedUser, "Tab import Service: " + msg, e.toString());

        }
        return tab;
    }

    /**
     * Creates a JSON mapping temporary IDs to newly created Podd object IDs
     * @return
     */
    public JsonRepresentation createJsonRepresentation() {

        return new JsonRepresentation(createJsonIdMap());
    }

    /**
     * Creates a JSON object mapping temporary IDs to the newly created podd object IDs
     * @return
     */
    private JSONObject createJsonIdMap() {
        JSONObject json = new JSONObject();
        if (tabImporter != null) {
            try {
                Map<String, URI> tempIdMap = tabImporter.getTempIdMap();
                if (tempIdMap != null) {
                    for (Map.Entry<String, URI> entry : tempIdMap.entrySet()) {
                        if (entry.getClass() != null && entry.getValue() != null) {
                            json.put(entry.getKey(), entry.getValue().toString());
                        }
                    }
                }
            } catch (JSONException e) {
                final String msg = "Error creating JSON object map.  ";
                LOGGER.error(msg, e);
                auditLogHelper.auditAction(ERROR, authenticatedUser, "Tab import Service: " + msg, e.toString());
            }
        }
        if (_DEBUG) {
            LOGGER.debug("json = " + json);
        }
        return json;
    }

    /**
     * Creates a JSON object listing the current progress of the tab impoter
     * @return
     */
    private JSONObject createJsonStatus() {
        JSONObject json = new JSONObject();
        try {
            if (tabImporter != null) {
                json.put(JSON_NUM_OBJECTS_COMPLETED, tabImporter.getNumObjectsCompleted());
                json.put(JSON_TOTAL_NUM_OBJECTS, tabImporter.getTotalNumObjects());
                if (tabImporter.getError() != null)
                    json.put(JSON_ERROR, tabImporter.getError());
            } else {
                json.put(JSON_NUM_OBJECTS_COMPLETED, "0");
                json.put(JSON_TOTAL_NUM_OBJECTS, "0");
            }

            // If there are errors, report it back
            if (!errorMap.isEmpty()) {
                json.put(JSON_ERROR, errorMap.toString());
            }

        } catch (JSONException e) {
            final String msg = "Error creating JSON status. ";
            LOGGER.error(msg, e);
            e.printStackTrace();
            auditLogHelper.auditAction(ERROR, authenticatedUser, "Tab import Service: " + msg, e.toString());
        }
        return json;
    }

    /**
     * Creates a JSON object listing the order in which the objects were created
     * @return
     */
    private JSONObject createJsonProcessingOrder() {
        JSONObject json = new JSONObject();
        if (tabImporter != null) {
            try {
                int i = 0;
                for (URI objectURI : tabImporter.getProcessingOrder()) {
                    json.put(Integer.toString(i), objectURI.toString());
                    i++;
                }
            } catch (JSONException e) {
                final String msg = "Error creating JSON creation list. ";
                LOGGER.error(msg, e);
                e.printStackTrace();
                auditLogHelper.auditAction(ERROR, authenticatedUser, "Tab import Service: " + msg, e.toString());
            }
        }
        return json;
    }

}