podd.resources.services.CreateObjectService.java Source code

Java tutorial

Introduction

Here is the source code for podd.resources.services.CreateObjectService.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.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.semanticweb.owl.model.OWLClassAssertionAxiom;
import org.semanticweb.owl.model.OWLDescription;
import org.semanticweb.owl.model.OWLIndividual;
import org.semanticweb.owl.model.OWLOntologyChangeException;
import org.semanticweb.owl.model.OWLOntologyCreationException;

import podd.exception.DataAccessException;
import podd.exception.EntityException;
import podd.exception.RawDataHandlingException;
import podd.model.entity.Entity;
import podd.model.entity.PoddObject;
import podd.server.authz.UserAction;

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.CLIENT_ERROR_BAD_REQUEST;
import static org.restlet.data.Status.CLIENT_ERROR_UNAUTHORIZED;
import static org.restlet.data.Status.SERVER_ERROR_INTERNAL;
import static org.restlet.data.Status.SUCCESS_OK;
import static podd.model.audit.AuditLog.ERROR;
import static podd.model.audit.AuditLog.INSUFFICIENT_ACCESS;
import static podd.util.common.Constants.PODD_OBJECT_NAMESPACE;

/**
 * @author Faith Davies
 * @version $Id$
 */
public class CreateObjectService extends ObjectService {

    private static final String BLANK_NODE_ID = "#genid-";

    protected String objectType;
    protected String blankNodeId;
    protected String parentRelationship;

    protected PoddObject parentObject;

    @Override
    protected Representation doAuthenticatedPost(Representation entity, Variant variant) throws ResourceException {
        Representation representation = null;

        initalisePoddObject();
        if (null != poddConcept && null != poddObject) {
            URI sbjUri = URI.create(sentOntology.getURI().toString() + BLANK_NODE_ID + blankNodeId);
            OWLIndividual anonSbj = dataFactory.getOWLAnonymousIndividual(sbjUri);
            URI objectUri = URI.create(PODD_OBJECT_NAMESPACE + poddObject.getPid());

            if (copyOntology(objectUri, anonSbj)
                    && participantPopulator.populateProjectParticipants(poddObject, authenticatedUser)
                    && consolidateObject() && addParentChildRelationship() && validateObject() && saveObject()) {
                // return success
                getResponse().setStatus(SUCCESS_OK);
                representation = new JsonRepresentation(jsonHelper.convertPoddObjectToReference(poddObject));
            } else {
                // an error has occurred, rollback project participant info
                participantPopulator.rollbackProjectParticipants(poddObject);
            }
        }
        if (!errorMap.isEmpty()) {
            representation = new JsonRepresentation(jsonHelper.convertErrorMap(errorMap));
            LOGGER.debug("Error: " + errorMap.toString());
        }
        return representation;
    }

    private void initalisePoddObject() {
        try {
            poddConcept = createObjectHelper.getFirstEntity(conceptDao.loadByLocalName(objectType));
            if (null != poddConcept && null != poddObject) {
                poddObject.setConcept(poddConcept);
            } else if (null != poddObject) {
                getResponse().setStatus(SERVER_ERROR_INTERNAL);
                errorHandler.handleError(GENERAL_MESSAGE_ID, "Concept Error",
                        "Error loading concept with type: " + objectType + ".");
            } else if (null != poddConcept) {
                getResponse().setStatus(SERVER_ERROR_INTERNAL);
                errorHandler.handleError(GENERAL_MESSAGE_ID, "Object Error",
                        "Error loading object with type: " + objectType + " - " + poddConcept + ". ");
            } else {
                getResponse().setStatus(SERVER_ERROR_INTERNAL);
                errorHandler.handleError(GENERAL_MESSAGE_ID, "Object Error",
                        "Error loading object and concept " + "with type: " + objectType + ". ");
            }
        } catch (DataAccessException e) {
            getResponse().setStatus(SERVER_ERROR_INTERNAL);
            final String msg = "Error loading concept with type: " + objectType + " - " + poddConcept + ". ";
            errorHandler.handleException(GENERAL_MESSAGE_ID, "Concept Error", msg, e);
            auditLogHelper.auditAction(ERROR, authenticatedUser, "Create Object Service: " + msg, e.toString());
        }
    }

    private boolean addParentChildRelationship() {
        try {
            if (null != parentObject && !parentRelationship.equals("")) {
                parentObject = createObjectHelper.addChildObject(parentObject, poddObject, parentRelationship);
            }
            return true;
        } catch (OWLOntologyChangeException e) {
            getResponse().setStatus(SERVER_ERROR_INTERNAL);
            final String msg = "Error copying ontology. ";
            errorHandler.handleException(poddObject.getPid(), "ontologyError", msg, e);
            auditLogHelper.auditAction(ERROR, authenticatedUser, "Create Object Service: " + msg, e.toString());
        } catch (RawDataHandlingException e) {
            getResponse().setStatus(SERVER_ERROR_INTERNAL);
            final String msg = "Error adding parent-child relationship. ";
            errorHandler.handleException(poddObject.getPid(), "ontologyError", msg, e);
            auditLogHelper.auditAction(ERROR, authenticatedUser, "Create Object Service: " + msg, e.toString());
        }
        return false;
    }

    protected boolean saveObject() {
        try {
            String baseUrl = getRequest().getRootRef().toString();
            createObjectHelper.saveObject(poddObject, parentObject, authenticatedUser);
            createObjectHelper.sendNotificationEmail(poddObject, authenticatedUser, baseUrl);
            return true;
        } catch (DataAccessException e) {
            getResponse().setStatus(SERVER_ERROR_INTERNAL);
            final String msg = "Error occured while saving the object: " + poddObject.getPid();
            errorHandler.handleException(poddObject.getPid(), "Saving Error", msg, e);
            auditLogHelper.auditAction(ERROR, authenticatedUser, "Create Object Service: " + msg, e.toString());
            return false;
        }
    }

    @Override
    protected boolean authoriseGet() {
        if (null != authenticatedUser && errorMap.isEmpty()) {
            try {
                poddObject = createObjectHelper.createObject(objectType, authenticatedUser);
                Class<? extends Entity> clazz = poddObject.getClass();
                return manager.decide(authenticatedUser, clazz, UserAction.CREATE, parentObject);
            } catch (EntityException e) {
                getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST);
                final String msg = "Error determining class for object type: " + objectType + ". ";
                errorHandler.handleException(GENERAL_MESSAGE_ID, "Object Type Error", msg, e);
                auditLogHelper.auditAction(ERROR, authenticatedUser, "Create Object Service: " + msg, e.toString());
            }
        }
        return false;
    }

    @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
        if (null == authenticatedUser) {
            getResponse().setStatus(CLIENT_ERROR_UNAUTHORIZED);
            final String msg = "User must be authenticated to create objects";
            errorHandler.handleError(GENERAL_MESSAGE_ID, "errorMessage", msg);
            auditLogHelper.auditAction(INSUFFICIENT_ACCESS, authenticatedUser,
                    this.getRequest().getResourceRef().toString(), msg);
        }
        if (!errorMap.isEmpty()) {
            return new JsonRepresentation(jsonHelper.convertErrorMap(errorMap));
        } else {
            return redirectErrorStatus(CLIENT_ERROR_UNAUTHORIZED);
        }
    }

    @Override
    protected void prePostAuthorisation(Representation entity) {
        LOGGER.debug("Create Object Service");
        errorMap = new HashMap<String, Map<String, List<String>>>();
        errorHandler.setAllObjectsErrorMap(errorMap);
        objectType = "";
        poddObject = null;
        poddConcept = null;
        parentObject = null;
        loadFormData(entity);

        if (!blankNodeId.equals("") && null != sentOntology) {
            objectType = getObjectTypeFromOntology();
            URI sbj = URI.create(sentOntology.getURI().toString() + BLANK_NODE_ID + blankNodeId);
            parentObject = loadParentFromOntology(sbj);
            if (null != parentObject && parentRelationship.equals("")) {
                getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST);
                errorHandler.handleError(GENERAL_MESSAGE_ID, "Invalid Parameters", "When the containing parent is "
                        + "specified in the ontology the parent relationship must be set with the key: parentRelationship");
            }
            if (null == parentObject && !parentRelationship.equals("")) {
                getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST);
                errorHandler.handleError(GENERAL_MESSAGE_ID, "Invalid Parameters",
                        "Parent relationship specified but not set with in the ontology");
            }
        } else {
            if (blankNodeId.equals("")) {
                getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST);
                errorHandler.handleError(GENERAL_MESSAGE_ID, "Invalid Parameters",
                        "ObjectId must be sent in request with the key: id");
            }
            if (null == sentOntology) {
                getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST);
                errorHandler.handleError(GENERAL_MESSAGE_ID, "Invalid Parameters",
                        "Ontology for the new object must be sent in the request with the key: ontology");
            }
        }
    }

    private void loadFormData(Representation entity) {
        blankNodeId = "";
        parentRelationship = "";
        // FIXME: Each instance of this class is used only once, why is the following required?
        sentOntology = null;
        RestletFileUpload upload = new RestletFileUpload(new DiskFileItemFactory());
        try {
            List<FileItem> list = upload.parseRepresentation(entity);
            for (FileItem item : list) {
                if (item.getFieldName().equals("id") && item.isFormField()) {
                    blankNodeId = item.getString().trim();
                }
                if (item.getFieldName().equals("parentRelationship") && item.isFormField()) {
                    parentRelationship = item.getString().trim();
                }
                if (item.getFieldName().equals("ontology") && !item.isFormField()) {
                    sentOntology = ontologyHelper.populateOntology(item.getInputStream());
                }
            }
        } catch (FileUploadException e) {
            getResponse().setStatus(SERVER_ERROR_INTERNAL);
            final String msg = "Error reading form data. ";
            errorHandler.handleException(GENERAL_MESSAGE_ID, "File Intialisation Error", msg, e);
            auditLogHelper.auditAction(ERROR, authenticatedUser, "Create Object 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, "Create Object Service: " + msg, e.toString());
        } catch (OWLOntologyCreationException e) {
            getResponse().setStatus(SERVER_ERROR_INTERNAL);
            final String msg = "Error creating ontology. ";
            errorHandler.handleException(GENERAL_MESSAGE_ID, "Ontology Creation Error", msg, e);
            auditLogHelper.auditAction(ERROR, authenticatedUser, "Create Object Service: " + msg, e.toString());
        }
    }

    private String getObjectTypeFromOntology() {
        // get the object type from the ontology
        URI sbj = URI.create(sentOntology.getURI().toString() + BLANK_NODE_ID + blankNodeId);
        OWLIndividual anonSbj = dataFactory.getOWLAnonymousIndividual(sbj);
        for (OWLClassAssertionAxiom assertion : ontologyHelper.getClassAssertions(sentOntology, anonSbj)) {
            OWLDescription owlDescription = assertion.getDescription();
            if (!owlDescription.isOWLThing() && owlHelper.isPoddClasses(owlDescription, null)) {
                return owlDescription.toString();
            }
        }
        getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST);
        errorHandler.handleError(GENERAL_MESSAGE_ID, "Invalid Ontology",
                "Class Assertion type must be set for blank node: " + blankNodeId);
        return "";
    }
}