/** * 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.util.Collections; import java.util.List; 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.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.ResourceException; import org.restlet.security.User; import org.semanticweb.owlapi.model.IRI; 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.FreemarkerUtil; import com.github.podd.utils.InferredOWLOntologyID; import com.github.podd.utils.PODD; import com.github.podd.utils.PoddObjectLabel; import com.github.podd.utils.PoddWebConstants; /** * * Get an artifact from PODD. This resource handles requests for asserted statements as well as * inferred statements. * * @author kutila * */ public class GetArtifactResourceImpl extends AbstractPoddResourceImpl { @Get(":html") public Representation getArtifactHtml(final Representation entity) throws ResourceException { this.log.debug("getArtifactHtml"); final String artifactString = this.getQuery().getFirstValue(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER, true); if(artifactString == null) { throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Artifact ID not submitted"); } final String versionString = this.getQuery().getFirstValue(PoddWebConstants.KEY_ARTIFACT_VERSION_IDENTIFIER, true); // optional parameter for inner objects final String objectToView = this.getQuery().getFirstValue(PoddWebConstants.KEY_OBJECT_IDENTIFIER, true); this.log.debug("requesting get artifact (HTML): {}, {}, {}", artifactString, versionString, objectToView); final UnmanagedArtifactIRIException foundException = null; InferredOWLOntologyID ontologyID = null; try { if(versionString == null) { ontologyID = this.getPoddArtifactManager().getArtifact(IRI.create(artifactString)); } else { ontologyID = this.getPoddArtifactManager() .getArtifact(IRI.create(artifactString), IRI.create(versionString)); if(ontologyID == null) { ontologyID = this.getPoddArtifactManager().getArtifact(IRI.create(artifactString)); } } } catch(final UnmanagedArtifactIRIException | UnmanagedArtifactVersionException | UnmanagedSchemaIRIException e) { if(this.getRequest().getClientInfo().isAuthenticated()) { throw new ResourceException(Status.CLIENT_ERROR_NOT_FOUND, "Could not find the given artifact", foundException); } else { // Make them authenticate first so that only authenticated users // see 404 messages this.checkAuthentication(PoddAction.UNPUBLISHED_ARTIFACT_READ, null, true); // Should never hit here, but putting it here to avoid possible // NPEs further on throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "Something went wrong"); } } if(ontologyID == null) { throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Could not find the given artifact"); } // FIXME: Test this after publish artifact is implemented boolean isPublished = false; try { isPublished = this.getPoddArtifactManager().isPublished(ontologyID); if(isPublished) { this.checkAuthentication(PoddAction.PUBLISHED_ARTIFACT_READ, ontologyID.getOntologyIRI().toOpenRDFURI()); } else { this.checkAuthentication(PoddAction.UNPUBLISHED_ARTIFACT_READ, ontologyID.getOntologyIRI() .toOpenRDFURI()); } } catch(final OpenRDFException e) { throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "Repository exception", e); } // completed checking authorization final User user = this.getRequest().getClientInfo().getUser(); this.log.debug("authenticated user: {}", user); final Map<String, Object> dataModel = RestletUtils.getBaseDataModel(this.getRequest()); dataModel.put( "contentTemplate", this.getPoddApplication() .getPropertyUtil() .get(PoddWebConstants.PROPERTY_TEMPLATE_OBJECT_DETAILS, PoddWebConstants.DEFAULT_TEMPLATE_OBJECT_DETAILS)); dataModel.put("pageTitle", "View Artifact"); try { this.populateDataModelWithArtifactData(ontologyID, objectToView, dataModel, isPublished); } catch(final OpenRDFException | UnmanagedSchemaIRIException | SchemaManifestException | UnsupportedRDFormatException | IOException | UnmanagedArtifactIRIException | UnmanagedArtifactVersionException | RepositoryNotFoundException e) { throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "Failed to populate data model", e); } return RestletUtils.getHtmlRepresentation( this.getPoddApplication().getPropertyUtil() .get(PoddWebConstants.PROPERTY_TEMPLATE_BASE, PoddWebConstants.DEFAULT_TEMPLATE_BASE), dataModel, MediaType.TEXT_HTML, this.getPoddApplication().getTemplateConfiguration()); } @Get(":rdf|rj|json|ttl") public Representation getArtifactRdf(final Representation entity, final Variant variant) throws ResourceException { // FIXME: Some Firefox requests get sent with Accept: */*, and Restlet // chooses this method // instead of HTML as default // To fix this we need to check whether Accept is exactly "*/*" and // response with HTML // variant instead of an RDF variant this.log.debug("getArtifactRdf"); final ByteArrayOutputStream stream = new ByteArrayOutputStream(); try { final String artifactString = this.getQuery().getFirstValue(PoddWebConstants.KEY_ARTIFACT_IDENTIFIER, true); if(artifactString == null) { this.log.error("Artifact ID not submitted"); throw new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST, "Artifact ID not submitted"); } final String versionString = this.getQuery().getFirstValue(PoddWebConstants.KEY_ARTIFACT_VERSION_IDENTIFIER, true); this.log.debug("requesting get artifact ({}): {}", variant.getMediaType().getName(), artifactString); // FIXME: The artifact may be published here this.checkAuthentication(PoddAction.UNPUBLISHED_ARTIFACT_READ, PODD.VF.createURI(artifactString)); // completed checking authorization final User user = this.getRequest().getClientInfo().getUser(); this.log.debug("authenticated user: {}", user); InferredOWLOntologyID ontologyID = null; if(versionString == null) { ontologyID = this.getPoddArtifactManager().getArtifact(IRI.create(artifactString)); } else { ontologyID = this.getPoddArtifactManager() .getArtifact(IRI.create(artifactString), IRI.create(versionString)); } final String includeInferredString = this.getRequest().getResourceRef().getQueryAsForm() .getFirstValue(PoddWebConstants.KEY_INCLUDE_INFERRED, true); final boolean includeInferred = Boolean.valueOf(includeInferredString); this.getPoddApplication() .getPoddArtifactManager() .exportArtifact(ontologyID, stream, RDFFormat.forMIMEType(variant.getMediaType().getName(), RDFFormat.RDFJSON), includeInferred); } catch(final UnmanagedArtifactIRIException e) { throw new ResourceException(Status.CLIENT_ERROR_NOT_FOUND, "Could not find the given artifact", e); } catch(OpenRDFException | PoddException | IOException e) { throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "Failed to export artifact", e); } return new ByteArrayRepresentation(stream.toByteArray()); } /** * This method retrieves necessary info about the object being viewed via SPARQL queries and * populates the data model. * * @param ontologyID * The artifact to be viewed * @param objectToView * An optional internal object to view * @param ontologyGraphs * The schema ontology graphs that should be part of the context for SPARQL * @param dataModel * Freemarker data model to be populated * @param isPublished * True if the Project is Published * @throws OpenRDFException * @throws UnmanagedSchemaIRIException * @throws IOException * @throws UnsupportedRDFormatException * @throws SchemaManifestException * @throws ResourceException * @throws UnmanagedArtifactVersionException * @throws UnmanagedArtifactIRIException * @throws RepositoryNotFoundException */ private void populateDataModelWithArtifactData(final InferredOWLOntologyID ontologyID, final String objectToView, final Map<String, Object> dataModel, final boolean isPublished) throws OpenRDFException, UnmanagedSchemaIRIException, SchemaManifestException, UnsupportedRDFormatException, IOException, UnmanagedArtifactIRIException, UnmanagedArtifactVersionException, ResourceException, RepositoryNotFoundException { final PoddObjectLabel theObject = RestletUtils.getParentDetails(this.getPoddArtifactManager(), ontologyID, objectToView); // set title & description of object to display dataModel.put("poddObject", theObject); final URI objectUri = theObject.getObjectURI(); final Map<String, String> parentMap = RestletUtils.populateParentDetails(this.getPoddArtifactManager(), ontologyID, objectUri); dataModel.put("parentObject", parentMap); // find the object's type final List<PoddObjectLabel> objectTypes = this.getPoddArtifactManager().getObjectTypes(ontologyID, objectUri); if(objectTypes == null || objectTypes.isEmpty()) { throw new ResourceException(Status.SERVER_ERROR_INTERNAL, "Could not determine type of object"); } // Get label for the object type final PoddObjectLabel label = objectTypes.get(0); dataModel.put("objectType", label); if(PODD.PODD_SCIENCE_PROJECT.equals(label.getObjectURI())) { dataModel.put("isProject", true); } // populate the properties of the object final List<URI> orderedProperties = this.getPoddArtifactManager().getOrderedProperties(ontologyID, objectUri, false); final Model allNeededStatementsForDisplay = this.getPoddArtifactManager().getObjectDetailsForDisplay(ontologyID, objectUri); dataModel.put("artifactUri", ontologyID.getOntologyIRI().toOpenRDFURI()); dataModel.put("versionIri", ontologyID.getVersionIRI().toOpenRDFURI()); dataModel.put("propertyList", orderedProperties); dataModel.put("completeModel", allNeededStatementsForDisplay); final int childrenCount = this.getPoddArtifactManager().getChildObjects(ontologyID, objectUri).size(); dataModel.put("childCount", childrenCount); if(!isPublished && this.checkAuthentication(PoddAction.ARTIFACT_EDIT, ontologyID.getOntologyIRI().toOpenRDFURI(), false)) { dataModel.put("canEditObject", true); dataModel.put("canDelete", true); dataModel.put("canAddChildren", true); } else { dataModel.put("canDelete", false); dataModel.put("canEditObject", false); dataModel.put("canAddChildren", false); } if(!isPublished && this.checkAuthentication(PoddAction.PROJECT_ROLE_EDIT, ontologyID.getOntologyIRI().toOpenRDFURI(), false)) { dataModel.put("canEditRoles", true); } if(!isPublished && this.checkAuthentication(PoddAction.UNPUBLISHED_ARTIFACT_DELETE, ontologyID.getOntologyIRI() .toOpenRDFURI(), false)) { dataModel.put("canDeleteProject", true); } dataModel.put("selectedObjectCount", 0); dataModel.put("childHierarchyList", Collections.emptyList()); dataModel.put("util", new FreemarkerUtil()); // FIXME: No support currently for interactive editing of data // references, so hide the edit // button to avoid users clicking on it for(final PoddObjectLabel nextType : objectTypes) { if(nextType.getObjectURI().equals(PODD.PODD_BASE_DATA_REFERENCE_TYPE) || nextType.getObjectURI().equals(PODD.PODD_BASE_DATA_REFERENCE_TYPE_SPARQL) || nextType.getObjectURI().equals(PODD.PODD_BASE_FILE_REFERENCE_TYPE_SSH)) { dataModel.put("canEditObject", false); dataModel.put("canAddChildren", false); } } } }