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.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; } }