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 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.server.authz.UserAction.UPDATE; import static podd.util.fedora.FedoraRepositoryUtil.getCurrentTimeAsString; import java.io.IOException; import java.net.URI; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; 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.OWLAnnotation; import org.semanticweb.owl.model.OWLClass; import org.semanticweb.owl.model.OWLClassAssertionAxiom; import org.semanticweb.owl.model.OWLDataMaxCardinalityRestriction; import org.semanticweb.owl.model.OWLDataProperty; import org.semanticweb.owl.model.OWLDescription; import org.semanticweb.owl.model.OWLEntity; import org.semanticweb.owl.model.OWLEntityAnnotationAxiom; import org.semanticweb.owl.model.OWLIndividual; import org.semanticweb.owl.model.OWLIndividualAxiom; import org.semanticweb.owl.model.OWLOntology; import org.semanticweb.owl.model.OWLOntologyChangeException; import org.semanticweb.owl.model.OWLOntologyCreationException; import org.semanticweb.owl.model.OWLPropertyExpression; import podd.exception.DataAccessException; import podd.exception.OntologyHandlingException; import podd.model.entity.PoddObject; import podd.util.owl.OntologyRegistry; /** * @author Faith Davies * @version $Id$ */ public class EditObjectService extends ObjectService { private URI objectURI; private PoddObject origParent; private OntologyRegistry ontologyRegistry; public void setOntologyRegistry(OntologyRegistry ontologyRegistry) { this.ontologyRegistry = ontologyRegistry; } /** * Rather than overwriting the existing ontology, should we do a merge of the ontologies instead? */ private boolean doMerge = false; @Override protected Representation doAuthenticatedPost(Representation entity, Variant variant) throws ResourceException { Representation representation = null; boolean conceptUnchanged = conceptNotChanged(); boolean parentUnchanged = parentNotChanged(); if (conceptUnchanged && parentUnchanged) { OWLIndividual sbj = dataFactory.getOWLIndividual(objectURI); if (copyOntology(objectURI, sbj) && participantPopulator.populateProjectParticipants(poddObject, null) && consolidateObject() && 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)); } return representation; } @Override protected boolean copyOntology(URI objectURI, OWLIndividual sbj) { // Reset the data properties and annotation properties, but not any of the object properties // Object properties must be preserved to maintain consistency with the database. // Resolves Ticket #373 if (_INFO) { LOGGER.info("doMerge: " + doMerge); } if (!doMerge) { OWLOntology ontology = poddObject.getCurrentRelations(); try { ontologyHelper.removeAllEntityAnnotationPropertyAssertions(ontology, sbj.getURI()); ontologyHelper.removeAllEntityDataPropertyAssertions(ontology, sbj.getURI()); } catch (OWLOntologyChangeException e) { final String msg = "Error resetting data and annotation properties"; errorHandler.handleException(poddObject.getPid(), "Ontology Error", msg, e); auditLogHelper.auditAction(ERROR, authenticatedUser, "Edit Object Service: " + msg, e.toString()); e.printStackTrace(); return false; } } else { // Merging // Remove all overlapping singular properties with cardinality of 1 handleMergeDataProperties(sentOntology.getDataPropertiesInSignature()); //Retrieve the OWLIndividual definition from the sent ontology for (OWLIndividual sentOntologyIndividual : sentOntology.getIndividualsInSignature()) { if (sentOntologyIndividual.getURI().equals(objectURI)) { if (_INFO) { LOGGER.info("Found matching individual in sentOntology"); } try { OWLOntology[] ontologies = new OWLOntology[] { poddObject.getCurrentRelations(), poddObject.getConcept().getCurrentDefinition() }; OWLClass owlClass = ontologyRegistry.getIndividualType(sbj, ontologies); if (_INFO) { LOGGER.info("owlClass=" + owlClass); } handleMergeDataProperties(owlClass.getDataPropertiesInSignature()); } catch (OntologyHandlingException e) { LOGGER.error("Found ontology handling exception", e); } } } if (_INFO) { for (OWLIndividualAxiom axiom : sentOntology.getAxioms(sbj)) { LOGGER.info("axiom=" + axiom); //handleMergeAxioms(axiom); } } /* try { ontologyHelper.removeAxioms(poddObject.getCurrentRelations(), sentOntology.getEntityAnnotationAxioms(sbj)); } catch (OWLOntologyChangeException e) { LOGGER.error(e); e.printStackTrace(); }*/ Set<URI> annotationURIsForRemoval = new HashSet<URI>(); for (OWLEntityAnnotationAxiom axiom : sentOntology.getEntityAnnotationAxioms(sbj)) { OWLAnnotation annotation = axiom.getAnnotation(); URI annURI = annotation.getAnnotationURI(); if (_INFO) { LOGGER.info("axiom=" + axiom); //handleMergeAxioms(axiom); OWLEntity owlEntity = axiom.getSubject(); LOGGER.info("subject=" + owlEntity + " annotation=" + annotation + " annotationURI=" + annURI); } annotationURIsForRemoval.add(annURI); } // Remove all the properties that are to be replaced try { ontologyHelper.removeAxiomsByURIs(poddObject.getCurrentRelations(), sbj.getURI(), annotationURIsForRemoval); } catch (OWLOntologyChangeException e) { LOGGER.error("Found owl ontology change exception", e); e.printStackTrace(); } } return super.copyOntology(objectURI, sbj); } private void handleMergeDataProperties(Set<OWLDataProperty> dataProperties) { if (dataProperties == null) return; if (_INFO) { for (OWLDataProperty dataProperty : dataProperties) { OWLPropertyExpression propertyExpression = dataProperty; LOGGER.info("propertyExpression: " + propertyExpression.getClass().getName()); if (propertyExpression instanceof OWLDataMaxCardinalityRestriction) { OWLDataMaxCardinalityRestriction maxCardRestr = (OWLDataMaxCardinalityRestriction) propertyExpression; int cardinality = maxCardRestr.getCardinality(); LOGGER.info("cardinality: " + cardinality); } } } } @Override protected boolean saveObject() { try { poddObject.setLastModified(getCurrentTimeAsString()); poddObject.setLastModifier(authenticatedUser); objectDao.update(poddObject); if (_INFO) { LOGGER.info("Action: " + authenticatedUser.getUserName() + " updated object " + poddObject.getObjectName() + " with pid: " + poddObject.getPid()); } return true; } catch (DataAccessException e) { getResponse().setStatus(SERVER_ERROR_INTERNAL); final String msg = "Error occured while saving the object. "; errorHandler.handleException(poddObject.getPid(), "Saving Error", msg, e); auditLogHelper.auditAction(ERROR, authenticatedUser, "Edit Object Service: " + msg, e.toString()); return false; } } @Override protected boolean authoriseGet() { if (null != authenticatedUser && errorMap.isEmpty() && null != poddObject) { return manager.decide(authenticatedUser, poddObject, UPDATE); } return false; } @Override protected Representation doUnauthenticatedGet(Variant variant) throws ResourceException { if (null == authenticatedUser) { getResponse().setStatus(CLIENT_ERROR_UNAUTHORIZED); final String msg = "User must be authenticated to edit 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) { if (_DEBUG) { LOGGER.debug("Edit Object Service"); } errorMap = new HashMap<String, Map<String, List<String>>>(); errorHandler.setAllObjectsErrorMap(errorMap); poddObject = null; loadFormData(entity); if (null != objectURI && null != sentOntology) { try { poddObject = objectDao.load(objectURI.getFragment()); if (null != poddObject) { poddConcept = poddObject.getConcept(); origParent = poddObject.getContainer(); } else { getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST); errorHandler.handleError(GENERAL_MESSAGE_ID, "Invalid PID", "No object can be found with the given URI: " + objectURI); } } catch (DataAccessException e) { getResponse().setStatus(SERVER_ERROR_INTERNAL); final String msg = "Error loading object with URI: " + objectURI + ". "; errorHandler.handleException(GENERAL_MESSAGE_ID, "Loading Error", msg, e); auditLogHelper.auditAction(ERROR, authenticatedUser, "Edit Object Service: " + msg, e.toString()); } } else { if (null == objectURI) { getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST); errorHandler.handleError(GENERAL_MESSAGE_ID, "Invalid Parameters", "The object's URI must be sent in request with the key: URI"); } if (null == sentOntology) { getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST); errorHandler.handleError(GENERAL_MESSAGE_ID, "Invalid Parameters", "The ontology for the edited object must be sent in the request with the key: ontology"); } } } private void loadFormData(Representation entity) { objectURI = null; sentOntology = null; doMerge = false; RestletFileUpload upload = new RestletFileUpload(new DiskFileItemFactory()); try { List<FileItem> list = upload.parseRepresentation(entity); for (FileItem item : list) { if (item.isFormField()) { if (item.getFieldName().equals("URI")) { objectURI = URI.create(item.getString().trim()); } else if (item.getFieldName().equals("merge")) { doMerge = item.getString().equalsIgnoreCase("true") ? true : false; } } else { if (item.getFieldName().equals("ontology")) { 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, "Edit 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, "Edit 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, "Edit Object Service: " + msg, e.toString()); } } private boolean parentNotChanged() { PoddObject parentFromOntology = loadParentFromOntology(objectURI); if (null == origParent) { return null == parentFromOntology; } boolean parentUnchanged = origParent.equals(parentFromOntology); if (!parentUnchanged) { getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST); errorHandler.handleError(poddObject.getPid(), "Ontology Error", "The Parent of an object can not be changed using this service."); } return parentUnchanged; } private boolean conceptNotChanged() { String objectType = ""; // get the object type from the ontology OWLIndividual sbj = dataFactory.getOWLIndividual(objectURI); for (OWLClassAssertionAxiom assertion : ontologyHelper.getClassAssertions(sentOntology, sbj)) { OWLDescription owlDescription = assertion.getDescription(); if (!owlDescription.isOWLThing() && owlHelper.isPoddClasses(owlDescription, poddConcept.getCurrentDefinition())) { objectType = owlDescription.toString(); } } boolean conceptUnchanged = poddConcept.getLocalName().equals(objectType); if (!conceptUnchanged) { getResponse().setStatus(CLIENT_ERROR_BAD_REQUEST); errorHandler.handleError(poddObject.getPid(), "Ontology Error", "The Concept for an object can not be changed using this service."); } return conceptUnchanged; } }