/** * PODD is an OWL ontology database used for scientific project management * * Copyright (C) 2009-2013 The University Of Queensland * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * This program 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 * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. */ package com.github.podd.resources; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.Map; import org.openrdf.OpenRDFException; import org.openrdf.model.Model; import org.openrdf.model.URI; import org.openrdf.rio.RDFFormat; import org.openrdf.rio.RDFHandlerException; import org.openrdf.rio.RDFParseException; import org.openrdf.rio.RDFWriter; import org.openrdf.rio.Rio; import org.openrdf.rio.UnsupportedRDFormatException; import org.restlet.data.MediaType; import org.restlet.data.Status; import org.restlet.representation.ByteArrayRepresentation; import org.restlet.representation.Representation; import org.restlet.representation.Variant; import org.restlet.resource.Get; import org.restlet.resource.Post; import org.restlet.resource.ResourceException; import org.restlet.security.User; import org.semanticweb.owlapi.model.IRI; import org.semanticweb.owlapi.model.OWLException; import com.github.podd.api.DataReferenceVerificationPolicy; import com.github.podd.api.PoddArtifactManager; import com.github.podd.exception.DataReferenceVerificationException; import com.github.podd.exception.OntologyNotInProfileException; import com.github.podd.exception.PoddException; import com.github.podd.exception.RepositoryNotFoundException; import com.github.podd.exception.SchemaManifestException; import com.github.podd.exception.UnmanagedArtifactIRIException; import com.github.podd.exception.UnmanagedArtifactVersionException; import com.github.podd.exception.UnmanagedSchemaIRIException; import com.github.podd.restlet.PoddAction; import com.github.podd.restlet.RestletUtils; import com.github.podd.utils.InferredOWLOntologyID; import com.github.podd.utils.OntologyUtils; import com.github.podd.utils.PODD; import com.github.podd.utils.PoddObjectLabel; import com.github.podd.utils.PoddWebConstants; /** * * Attach a data reference to a PODD artifact * * @author kutila * */ public class DataReferenceAttachResourceImpl extends AbstractPoddResourceImpl { /** * @param entity * @param artifactUri * @param versionUri * @param verificationPolicy * @return * @throws ResourceException * @throws IOException * @throws UnsupportedRDFormatException * @throws RDFParseException * @throws UnmanagedArtifactIRIException * @throws UnmanagedSchemaIRIException */ private InferredOWLOntologyID attachDataReference(final Representation entity, final String artifactUriString, final String versionUriString, final DataReferenceVerificationPolicy verificationPolicy) throws ResourceException, RDFParseException, UnsupportedRDFormatException, IOException, UnmanagedArtifactIRIException, UnmanagedSchemaIRIException { // get input stream containing RDF statements InputStream inputStream = null; try { inputStream = entity.getStream(); } catch(final IOException e) { throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "There was a problem with the input", e); } final RDFFormat inputFormat = Rio.getParserFormatForMIMEType(entity.getMediaType().getName(), RDFFormat.RDFXML); final Model model = Rio.parse(inputStream, "", inputFormat); final URI artifactUri = PODD.VF.createURI(artifactUriString); final URI versionUri = PODD.VF.createURI(versionUriString); final PoddArtifactManager artifactManager = this.getPoddArtifactManager(); InferredOWLOntologyID artifact; try { artifact = artifactManager.getArtifact(IRI.create(artifactUri), IRI.create(versionUri)); } catch(final UnmanagedArtifactVersionException e1) { artifact = artifactManager.getArtifact(IRI.create(artifactUri)); } InferredOWLOntologyID artifactMap = null; try { artifactMap = this.getPoddArtifactManager().attachDataReferences(artifact, model, verificationPolicy); } catch(final DataReferenceVerificationException e) { this.log.error("File reference validation errors: {}", e.getValidationFailures()); throw new ResourceException(Status.SERVER_ERROR_BAD_GATEWAY, "File reference(s) failed verification", e); } catch(final OntologyNotInProfileException e) { this.log.error("The ontology was not suitable for our reasoner after the changes: {}", e.getProfileReport()); throw new ResourceException( Status.CLIENT_ERROR_BAD_REQUEST, "Ontology was not consistent after the changes. Was the parent object correct before the submission.", e); } catch(OpenRDFException | PoddException | IOException | OWLException e) { throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "Could not attach file references", e); } this.log.info("Successfully attached file reference to artifact {}", artifactMap); return artifactMap; } @Get public Representation attachDataReferencePageHtml(final Representation entity) throws ResourceException { // check mandatory parameter: artifact IRI final String artifactUriString = this.getQuery().getFirstValue(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER, true); if(artifactUriString == null) { this.log.error("Artifact ID not submitted"); throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Artifact IRI not submitted"); } // check mandatory parameter: object IRI final String objectUri = this.getQuery().getFirstValue(PoddWebConstants.KEY_OBJECT_IDENTIFIER, true); if(objectUri == null) { this.log.error("Object IRI not submitted"); throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Object IRI not submitted"); } final URI artifactUri = PODD.VF.createURI(artifactUriString); this.checkAuthentication(PoddAction.ARTIFACT_EDIT, artifactUri); InferredOWLOntologyID artifact; try { artifact = this.getPoddArtifactManager().getArtifact(IRI.create(artifactUri)); } catch(final UnmanagedArtifactIRIException | UnmanagedSchemaIRIException e) { this.log.error("Artifact IRI not recognised"); throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Artifact IRI not recognised", e); } this.log.info("attachFileRefHtml"); final User user = this.getRequest().getClientInfo().getUser(); this.log.info("authenticated user: {}", user); PoddObjectLabel parentDetails; try { parentDetails = RestletUtils.getParentDetails(this.getPoddArtifactManager(), artifact, objectUri); } catch(final OpenRDFException | UnmanagedSchemaIRIException | SchemaManifestException | UnsupportedRDFormatException | IOException | UnmanagedArtifactIRIException | UnmanagedArtifactVersionException | RepositoryNotFoundException e) { this.log.error("Could not find parent details", e); throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Could not find parent details", e); } final Map<String, Object> dataModel = RestletUtils.getBaseDataModel(this.getRequest()); dataModel.put("contentTemplate", "attachDataReference.html.ftl"); dataModel.put("pageTitle", "Attach Data Reference"); dataModel.put("artifactIri", artifact.getOntologyIRI().toString()); dataModel.put("versionIri", artifact.getVersionIRI().toString()); dataModel.put("parentObject", parentDetails); dataModel.put("objectUri", objectUri); // Output the base template, with contentTemplate from the dataModel // defining the // template to use for the content in the body of the page return RestletUtils.getHtmlRepresentation( this.getPoddApplication().getPropertyUtil() .get(PoddWebConstants.PROPERTY_TEMPLATE_BASE, PoddWebConstants.DEFAULT_TEMPLATE_BASE), dataModel, MediaType.TEXT_HTML, this.getPoddApplication().getTemplateConfiguration()); } @Post(":rdf|rj|ttl") public Representation attachDataReferenceRdf(final Representation entity, final Variant variant) throws ResourceException { // check mandatory parameter: artifact IRI final String artifactUri = this.getQuery().getFirstValue(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER, true); if(artifactUri == null) { this.log.error("Artifact ID not submitted"); throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Artifact IRI not submitted"); } this.checkAuthentication(PoddAction.ARTIFACT_EDIT, PODD.VF.createURI(artifactUri)); // check mandatory parameter: artifact version IRI final String versionUri = this.getQuery().getFirstValue(PoddWebConstants.KEY_ARTIFACT_VERSION_IDENTIFIER, true); if(versionUri == null) { this.log.error("Artifact Version IRI not submitted"); throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Artifact Version IRI not submitted"); } // check optional parameter: whether file references should be verified. // Defaults to NO final String verifyFileRefs = this.getQuery().getFirstValue(PoddWebConstants.KEY_VERIFICATION_POLICY, true); DataReferenceVerificationPolicy verificationPolicy = DataReferenceVerificationPolicy.DO_NOT_VERIFY; if(verifyFileRefs != null && Boolean.valueOf(verifyFileRefs)) { verificationPolicy = DataReferenceVerificationPolicy.VERIFY; } this.log.info("@Post attachFileReference ({})", entity.getMediaType().getName()); InferredOWLOntologyID artifactMap; try { artifactMap = this.attachDataReference(entity, artifactUri, versionUri, verificationPolicy); } catch(final UnmanagedArtifactIRIException | UnmanagedSchemaIRIException e1) { this.log.error("Artifact IRI not managed"); throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Artifact IRI not managed"); } catch(final UnsupportedRDFormatException e1) { this.log.error("Unsupported format: " + entity.getMediaType().getName()); throw new ResourceException(Status.CLIENT_ERROR_UNSUPPORTED_MEDIA_TYPE, "Cannot parse the given format: " + entity.getMediaType().getName()); } catch(final RDFParseException e1) { this.log.error("Artifact not parsed correctly"); throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Artifact not parsed correctly"); } catch(final IOException e1) { this.log.error("Artifact not parsed due to IO exception"); throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Artifact not parsed due to IO exception"); } // prepare output: Artifact ID, object URI, file reference URI final ByteArrayOutputStream output = new ByteArrayOutputStream(8096); final RDFWriter writer = Rio.createWriter(Rio.getWriterFormatForMIMEType(variant.getMediaType().getName(), RDFFormat.RDFXML), output); try { writer.startRDF(); OntologyUtils.ontologyIDsToHandler(Arrays.asList(artifactMap), writer); writer.endRDF(); } catch(final RDFHandlerException e) { throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "Could not create response"); } return new ByteArrayRepresentation(output.toByteArray(), MediaType.valueOf(writer.getRDFFormat() .getDefaultMIMEType())); } }