| package org.apache.taverna.scufl2.annotation; |
| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.URI; |
| import java.util.Calendar; |
| import java.util.GregorianCalendar; |
| import java.util.Iterator; |
| import java.util.logging.Logger; |
| |
| import org.apache.jena.riot.Lang; |
| import org.apache.jena.riot.RDFDataMgr; |
| import org.apache.jena.riot.RDFLanguages; |
| import org.apache.taverna.scufl2.api.annotation.Annotation; |
| import org.apache.taverna.scufl2.api.common.Child; |
| import org.apache.taverna.scufl2.api.common.Scufl2Tools; |
| import org.apache.taverna.scufl2.api.common.URITools; |
| import org.apache.taverna.scufl2.api.container.WorkflowBundle; |
| import org.apache.taverna.scufl2.ucfpackage.UCFPackage.ResourceEntry; |
| |
| |
| import org.apache.jena.graph.Node; |
| import org.apache.jena.graph.NodeFactory; |
| import org.apache.jena.query.Dataset; |
| import org.apache.jena.query.DatasetFactory; |
| import org.apache.jena.rdf.model.Model; |
| import org.apache.jena.rdf.model.ModelFactory; |
| import org.apache.jena.sparql.core.Quad; |
| |
| public class AnnotationTools { |
| private static final String EXAMPLE_DATA_PREDICATE = "http://biocatalogue.org/attribute/exampleData"; |
| public static final URI EXAMPLE_DATA = URI.create(EXAMPLE_DATA_PREDICATE); |
| private static final String TITLE_PREDICATE = "http://purl.org/dc/terms/title"; |
| public static final URI TITLE = URI.create(TITLE_PREDICATE); |
| private static final String DESCRIPTION_PREDICATE = "http://purl.org/dc/terms/description"; |
| public static final URI DESCRIPTION = URI.create(DESCRIPTION_PREDICATE); |
| private static final String CREATOR_PREDICATE = "http://purl.org/dc/elements/1.1/creator"; |
| public static final URI CREATOR = URI.create(CREATOR_PREDICATE); |
| |
| private static Logger logger = Logger.getLogger(AnnotationTools.class |
| .getCanonicalName()); |
| |
| private Scufl2Tools scufl2Tools = new Scufl2Tools(); |
| private URITools uritools = new URITools(); |
| |
| public Dataset annotationDatasetFor(Child<?> workflowBean) { |
| Dataset dataset = DatasetFactory.createMem(); |
| for (Annotation ann : scufl2Tools.annotationsFor(workflowBean)) { |
| WorkflowBundle bundle = ann.getParent(); |
| URI annUri = uritools.uriForBean(ann); |
| String bodyUri = bundle.getGlobalBaseURI().resolve(ann.getBody()) |
| .toASCIIString(); |
| |
| if (ann.getBody().isAbsolute()) { |
| logger.info("Skipping absolute annotation body URI: " |
| + ann.getBody()); |
| // TODO: Optional loading of external annotation bodies |
| continue; |
| } |
| String path = ann.getBody().getPath(); |
| |
| ResourceEntry resourceEntry = bundle.getResources() |
| .getResourceEntry(path); |
| if (resourceEntry == null) { |
| logger.warning("Can't find annotation body: " + path); |
| continue; |
| } |
| String contentType = resourceEntry.getMediaType(); |
| Lang lang = RDFLanguages.contentTypeToLang(contentType); |
| if (lang == null) { |
| lang = RDFLanguages.filenameToLang(path); |
| } |
| if (lang == null) { |
| logger.warning("Can't find media type of annotation body: " |
| + ann.getBody()); |
| continue; |
| } |
| Model model = ModelFactory.createDefaultModel(); |
| try (InputStream inStream = bundle.getResources() |
| .getResourceAsInputStream(path)) { |
| RDFDataMgr.read(model, inStream, bodyUri, lang); |
| } catch (IOException e) { |
| logger.warning("Can't read annotation body: " + path); |
| continue; |
| } |
| dataset.addNamedModel(annUri.toString(), model); |
| } |
| |
| return dataset; |
| } |
| |
| public String getTitle(Child<?> workflowBean) { |
| return getLiteral(workflowBean, TITLE_PREDICATE); |
| } |
| |
| private String getLiteral(Child<?> workflowBean, String propertyUri) { |
| Dataset annotations = annotationDatasetFor(workflowBean); |
| URI beanUri = uritools.uriForBean(workflowBean); |
| Node subject = NodeFactory.createURI(beanUri.toString()); |
| Node property = NodeFactory.createURI(propertyUri); |
| |
| Iterator<Quad> found = annotations.asDatasetGraph().find(null, subject, |
| property, null); |
| if (!found.hasNext()) { |
| return null; |
| } |
| return found.next().getObject().toString(false); |
| } |
| |
| public String getCreator(Child<?> workflowBean) { |
| return getLiteral(workflowBean, CREATOR_PREDICATE); |
| } |
| |
| public String getExampleValue(Child<?> workflowBean) { |
| return getLiteral(workflowBean, EXAMPLE_DATA_PREDICATE); |
| } |
| |
| public String getDescription(Child<?> workflowBean) { |
| return getLiteral(workflowBean, DESCRIPTION_PREDICATE); |
| } |
| |
| /** |
| * Create a new annotation attached to the given |
| * @param workflowBundle |
| * @param subject |
| * @param predicate |
| * @param value |
| * @return |
| * @throws IOException |
| */ |
| public Annotation createNewAnnotation(WorkflowBundle workflowBundle, |
| Child<?> subject, URI predicate, String value) throws IOException { |
| Object parent = subject.getParent(); |
| while (parent instanceof Child) |
| parent = ((Child<?>) parent).getParent(); |
| if (parent != workflowBundle) |
| throw new IllegalStateException( |
| "annotations can only be added to bundles that their subjects are already a member of"); |
| if (predicate == null) |
| throw new IllegalArgumentException( |
| "annotation predicate must be non-null"); |
| if (value == null) |
| throw new IllegalArgumentException( |
| "annotation value must be non-null"); |
| |
| // Add the annotation |
| Annotation annotation = new Annotation(); |
| Calendar now = new GregorianCalendar(); |
| annotation.setParent(workflowBundle); |
| |
| String path = "annotation/" + annotation.getName() + ".ttl"; |
| URI bodyURI = URI.create(path); |
| |
| annotation.setTarget(subject); |
| annotation.setAnnotatedAt(now); |
| // annotation.setAnnotator();//FIXME |
| annotation.setSerializedAt(now); |
| URI annotatedSubject = uritools.relativeUriForBean(subject, annotation); |
| StringBuilder turtle = new StringBuilder(); |
| turtle.append("<"); |
| turtle.append(annotatedSubject.toASCIIString()); |
| turtle.append("> "); |
| |
| turtle.append("<"); |
| turtle.append(predicate.toASCIIString()); |
| turtle.append("> "); |
| |
| // A potentially multi-line string |
| turtle.append("\"\"\""); |
| // Escape existing \ to \\ |
| String escaped = value.replace("\\", "\\\\"); |
| // Escape existing " to \" (beware Java's escaping of \ and " below) |
| escaped = escaped.replace("\"", "\\\""); |
| turtle.append(escaped); |
| turtle.append("\"\"\""); |
| turtle.append(" ."); |
| try { |
| workflowBundle.getResources().addResource(turtle.toString(), path, |
| "text/turtle"); |
| } catch (IOException e) { |
| workflowBundle.getAnnotations().remove(annotation); |
| throw e; |
| } |
| annotation.setBody(bodyURI); |
| return annotation; |
| } |
| } |