org.apache.taverna.robundle.manifest.RDFToManifest Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of taverna-robundle Show documentation
Show all versions of taverna-robundle Show documentation
API for dealing with RO Bundles
package org.apache.taverna.robundle.manifest;
/*
* 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 static com.hp.hpl.jena.ontology.OntModelSpec.OWL_DL_MEM_RULE_INF;
import static com.hp.hpl.jena.rdf.model.ModelFactory.createOntologyModel;
import static org.apache.taverna.robundle.utils.PathHelper.relativizeFromBase;
import static org.apache.taverna.robundle.utils.RDFUtils.literalAsFileTime;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.logging.Logger;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;
import org.apache.jena.riot.RiotException;
import org.apache.taverna.robundle.Bundles;
import com.hp.hpl.jena.ontology.DatatypeProperty;
import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.ObjectProperty;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntResource;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
public class RDFToManifest {
public static class ClosableIterable implements AutoCloseable,
Iterable {
private ExtendedIterator iterator;
public ClosableIterable(ExtendedIterator iterator) {
this.iterator = iterator;
}
@Override
public void close() {
iterator.close();
}
@Override
public ExtendedIterator iterator() {
return iterator;
}
}
private static final String BUNDLE = "http://purl.org/wf4ever/bundle#";
private static final String BUNDLE_RDF = "/ontologies/bundle.owl";
private static final String DCT = "http://purl.org/dc/terms/";
private static final String FOAF_0_1 = "http://xmlns.com/foaf/0.1/";
private static final String FOAF_RDF = "/ontologies/foaf.rdf";
private static Logger logger = Logger.getLogger(RDFToManifest.class
.getCanonicalName());
private static final String OA = "http://www.w3.org/ns/oa#";
private static final String OA_RDF = "/ontologies/oa.rdf";
private static final String ORE = "http://www.openarchives.org/ore/terms/";
private static final String PAV = "http://purl.org/pav/";
private static final String PAV_RDF = "/ontologies/pav.rdf";
private static final String PROV = "http://www.w3.org/ns/prov#";
private static final String PROV_AQ_RDF = "/ontologies/prov-aq.rdf";
private static final String PROV_O = "http://www.w3.org/ns/prov-o#";
private static final String PROV_O_RDF = "/ontologies/prov-o.rdf";
@SuppressWarnings("unused")
private static final String RO = "http://purl.org/wf4ever/ro#";
static {
setCachedHttpClientInJsonLD();
}
public static ClosableIterable iterate(ExtendedIterator iterator) {
return new ClosableIterable(iterator);
}
protected static Model jsonLdAsJenaModel(InputStream jsonIn, URI base)
throws IOException, RiotException {
Model model = ModelFactory.createDefaultModel();
RDFDataMgr.read(model, jsonIn, base.toASCIIString(), Lang.JSONLD);
return model;
//
// Object input = JSONUtils.fromInputStream(jsonIn);
// JSONLDTripleCallback callback = new JenaTripleCallback();
// Model model = (Model)JSONLD.toRDF(input, callback, new
// Options(base.toASCIIString()));
// return model;
}
protected static URI makeBaseURI() throws URISyntaxException {
return new URI("app", UUID.randomUUID().toString(), "/", (String) null);
}
/**
* Use a JarCacheStorage so that our JSON-LD @context can be loaded from our
* classpath and not require network connectivity
*
*/
protected static void setCachedHttpClientInJsonLD() {
// JarCacheStorage cacheStorage = new JarCacheStorage(
// RDFToManifest.class.getClassLoader());
// synchronized (DocumentLoader.class) {
// HttpClient oldHttpClient = DocumentLoader.getHttpClient();
// CachingHttpClient wrappedHttpClient = new CachingHttpClient(
// oldHttpClient, cacheStorage, cacheStorage.getCacheConfig());
// DocumentLoader.setHttpClient(wrappedHttpClient);
// }
// synchronized (JSONUtils.class) {
// HttpClient oldHttpClient = JSONUtilsSub.getHttpClient();
// CachingHttpClient wrappedHttpClient = new CachingHttpClient(
// oldHttpClient, cacheStorage, cacheStorage.getCacheConfig());
// JSONUtilsSub.setHttpClient(wrappedHttpClient);
// }
}
private ObjectProperty aggregates;
private OntClass aggregation;
private ObjectProperty authoredBy;
private DatatypeProperty authoredOn;
private OntModel bundle;
private ObjectProperty conformsTo;
private ObjectProperty createdBy;
private DatatypeProperty createdOn;
private OntModel dct;
private OntModel foaf;
private DatatypeProperty foafName;
private DatatypeProperty format;
private ObjectProperty hasAnnotation;
private ObjectProperty hasBody;
private ObjectProperty hasProvenance;
private ObjectProperty hasProxy;
private ObjectProperty hasTarget;
private ObjectProperty inFolder;
private ObjectProperty isDescribedBy;
private OntModel oa;
private OntModel ore;
private OntModel pav;
private OntModel prov;
private OntModel provaq;
private ObjectProperty proxyFor;
private ObjectProperty proxyIn;
private OntClass standard;
public RDFToManifest() {
loadOntologies();
}
private void checkNotNull(Object... possiblyNulls) {
int i = 0;
for (Object check : possiblyNulls) {
if (check == null)
throw new IllegalStateException("Could not load item #" + i);
i++;
}
}
private Individual findRO(OntModel model, URI base) {
try (ClosableIterable extends OntResource> instances = iterate(aggregation
.listInstances())) {
for (OntResource o : instances)
// System.out.println("Woo " + o);
return o.asIndividual();
}
// Fallback - resolve as "/"
// TODO: Ensure it's an Aggregation?
return model.getIndividual(base.toString());
}
private List getAgents(URI base, Individual in,
ObjectProperty property) {
List creators = new ArrayList<>();
for (Individual agent : listObjectProperties(in, property)) {
Agent a = new Agent();
if (agent.getURI() != null)
a.setUri(relativizeFromBase(agent.getURI(), base));
RDFNode name = agent.getPropertyValue(foafName);
if (name != null && name.isLiteral())
a.setName(name.asLiteral().getLexicalForm());
creators.add(a);
}
return creators;
}
protected OntModel getOntModel() {
OntModel ontModel = createOntologyModel(OWL_DL_MEM_RULE_INF);
ontModel.setNsPrefix("foaf", FOAF_0_1);
ontModel.setNsPrefix("prov", PROV);
ontModel.setNsPrefix("ore", ORE);
ontModel.setNsPrefix("pav", PAV);
ontModel.setNsPrefix("dct", DCT);
// ontModel.getDocumentManager().loadImports(foaf.getOntModel());
return ontModel;
}
private Set listObjectProperties(OntResource ontResource,
ObjectProperty prop) {
LinkedHashSet results = new LinkedHashSet<>();
try (ClosableIterable props = iterate(ontResource
.listPropertyValues(prop))) {
for (RDFNode node : props) {
if (!node.isResource() || !node.canAs(Individual.class))
continue;
results.add(node.as(Individual.class));
}
}
return results;
}
protected synchronized void loadBundle() {
if (bundle != null)
return;
OntModel ontModel = loadOntologyFromClasspath(BUNDLE_RDF, BUNDLE);
hasProxy = ontModel.getObjectProperty(BUNDLE + "hasProxy");
hasAnnotation = ontModel.getObjectProperty(BUNDLE + "hasAnnotation");
inFolder = ontModel.getObjectProperty(BUNDLE + "inFolder");
checkNotNull(hasProxy, hasAnnotation, inFolder);
bundle = ontModel;
}
protected synchronized void loadDCT() {
if (dct != null)
return;
OntModel ontModel = loadOntologyFromClasspath(
"/ontologies/dcterms_od.owl",
"http://purl.org/wf4ever/dcterms_od");
// properties from dct
standard = ontModel.getOntClass(DCT + "Standard");
conformsTo = ontModel.getObjectProperty(DCT + "conformsTo");
// We'll cheat dc:format in
format = ontModel
.createDatatypeProperty("http://purl.org/dc/elements/1.1/"
+ "format");
checkNotNull(standard, conformsTo, format);
dct = ontModel;
}
//
protected synchronized void loadFOAF() {
if (foaf != null)
return;
OntModel ontModel = loadOntologyFromClasspath(FOAF_RDF, FOAF_0_1);
// properties from foaf
foafName = ontModel.getDatatypeProperty(FOAF_0_1 + "name");
checkNotNull(foafName);
foaf = ontModel;
}
protected synchronized void loadOA() {
if (oa != null)
return;
OntModel ontModel = loadOntologyFromClasspath(OA_RDF, OA);
hasTarget = ontModel.getObjectProperty(OA + "hasTarget");
hasBody = ontModel.getObjectProperty(OA + "hasBody");
checkNotNull(hasTarget, hasBody);
oa = ontModel;
}
protected void loadOntologies() {
loadDCT();
loadORE();
loadFOAF();
loadPROVO();
loadPAV();
loadPROVAQ();
loadOA();
loadBundle();
}
protected OntModel loadOntologyFromClasspath(String classPathUri, String uri) {
OntModel ontModel = createOntologyModel();
// Load from classpath
InputStream inStream = getClass().getResourceAsStream(classPathUri);
if (inStream == null)
throw new IllegalArgumentException("Can't load " + classPathUri);
// Ontology ontology = ontModel.createOntology(uri);
ontModel.read(inStream, uri);
try {
inStream.close();
} catch (IOException e) {
// Shouldn't happen
}
return ontModel;
}
protected synchronized void loadORE() {
if (ore != null)
return;
OntModel ontModel = loadOntologyFromClasspath(
"/ontologies/ore-owl.owl", "http://purl.org/wf4ever/ore-owl");
aggregation = ontModel.getOntClass(ORE + "Aggregation");
aggregates = ontModel.getObjectProperty(ORE + "aggregates");
proxyFor = ontModel.getObjectProperty(ORE + "proxyFor");
proxyIn = ontModel.getObjectProperty(ORE + "proxyIn");
isDescribedBy = ontModel.getObjectProperty(ORE + "isDescribedBy");
checkNotNull(aggregation, aggregates, proxyFor, proxyIn, isDescribedBy);
ore = ontModel;
}
protected synchronized void loadPAV() {
if (pav != null)
return;
OntModel ontModel = loadOntologyFromClasspath(PAV_RDF, PAV);
// properties from foaf
createdBy = ontModel.getObjectProperty(PAV + "createdBy");
createdOn = ontModel.getDatatypeProperty(PAV + "createdOn");
authoredBy = ontModel.getObjectProperty(PAV + "authoredBy");
authoredOn = ontModel.getDatatypeProperty(PAV + "authoredOn");
checkNotNull(createdBy, createdOn, authoredBy, authoredOn);
pav = ontModel;
}
protected synchronized void loadPROVAQ() {
if (provaq != null)
return;
OntModel ontModel = loadOntologyFromClasspath(PROV_AQ_RDF, PAV);
// properties from foaf
hasProvenance = ontModel.getObjectProperty(PROV + "has_provenance");
checkNotNull(hasProvenance);
provaq = ontModel;
}
protected synchronized void loadPROVO() {
if (prov != null)
return;
OntModel ontModel = loadOntologyFromClasspath(PROV_O_RDF, PROV_O);
checkNotNull(ontModel);
prov = ontModel;
}
@SuppressWarnings("deprecation")
private static void setPathProxy(PathMetadata meta, URI proxy) {
meta.setProxy(proxy);
}
public void readTo(InputStream manifestResourceAsStream, Manifest manifest,
URI manifestResourceBaseURI) throws IOException, RiotException {
OntModel model = new RDFToManifest().getOntModel();
model.add(jsonLdAsJenaModel(manifestResourceAsStream,
manifestResourceBaseURI));
// model.write(System.out, "TURTLE");
// System.out.println();
URI root = manifestResourceBaseURI.resolve("/");
Individual ro = findRO(model, root);
if (ro == null)
throw new IOException("root ResearchObject not found - "
+ "Not a valid RO Bundle manifest");
for (Individual manifestResource : listObjectProperties(ro,
isDescribedBy)) {
String uriStr = manifestResource.getURI();
if (uriStr == null) {
logger.warning("Skipping manifest without URI: "
+ manifestResource);
continue;
}
// URI relative = relativizeFromBase(uriStr, root);
Path path = manifest.getBundle().getFileSystem().provider()
.getPath(URI.create(uriStr));
manifest.getManifest().add(path);
}
List creators = getAgents(root, ro, createdBy);
if (!creators.isEmpty()) {
manifest.setCreatedBy(creators.get(0));
if (creators.size() > 1)
logger.warning("Ignoring additional createdBy agents");
}
RDFNode created = ro.getPropertyValue(createdOn);
manifest.setCreatedOn(literalAsFileTime(created));
List history = new ArrayList ();
for (Individual histItem : listObjectProperties (ro, hasProvenance))
history.add (Bundles.uriToBundlePath (manifest.getBundle (), relativizeFromBase(histItem.getURI (), root)));
manifest.setHistory (history);
List authors = getAgents(root, ro, authoredBy);
if (!authors.isEmpty())
manifest.setAuthoredBy(authors);
RDFNode authored = ro.getPropertyValue(authoredOn);
manifest.setAuthoredOn(literalAsFileTime(authored));
for (Individual aggrResource : listObjectProperties(ro, aggregates)) {
String uriStr = aggrResource.getURI();
// PathMetadata meta = new PathMetadata();
if (uriStr == null) {
logger.warning("Skipping aggregation without URI: "
+ aggrResource);
continue;
}
PathMetadata meta = manifest.getAggregation(relativizeFromBase(
uriStr, root));
Set proxies = listObjectProperties(aggrResource,
hasProxy);
if (!proxies.isEmpty()) {
// We can only deal with the first one
Individual proxy = proxies.iterator().next();
String proxyUri = null;
if (proxy.getURI() != null)
proxyUri = proxy.getURI();
else if (proxy.getSameAs() != null)
proxyUri = proxy.getSameAs().getURI();
if (proxyUri != null)
setPathProxy(meta, relativizeFromBase(proxyUri, root));
}
creators = getAgents(root, aggrResource, createdBy);
if (!creators.isEmpty()) {
meta.setCreatedBy(creators.get(0));
if (creators.size() > 1)
logger.warning("Ignoring additional createdBy agents for "
+ meta);
}
meta.setCreatedOn(literalAsFileTime(aggrResource
.getPropertyValue(createdOn)));
for (Individual standard : listObjectProperties(aggrResource,
conformsTo))
if (standard.getURI() != null)
meta.setConformsTo(relativizeFromBase(standard.getURI(),
root));
RDFNode mediaType = aggrResource.getPropertyValue(format);
if (mediaType != null && mediaType.isLiteral())
meta.setMediatype(mediaType.asLiteral().getLexicalForm());
}
for (Individual ann : listObjectProperties(ro, hasAnnotation)) {
/*
* Normally just one body per annotation, but just in case we'll
* iterate and split them out (as our PathAnnotation can only keep a
* single setContent() at a time)
*/
for (Individual body : listObjectProperties(
model.getOntResource(ann), hasBody)) {
if (body.getURI() == null) {
logger.warning("Can't find annotation body for anonymous "
+ body);
continue;
}
PathAnnotation pathAnn = new PathAnnotation();
pathAnn.setContent(relativizeFromBase(body.getURI(), root));
if (ann.getURI() != null)
pathAnn.setUri(relativizeFromBase(ann.getURI(), root));
else if (ann.getSameAs() != null
&& ann.getSameAs().getURI() != null)
pathAnn.setUri(relativizeFromBase(ann.getSameAs().getURI(),
root));
// Handle multiple about/hasTarget
for (Individual target : listObjectProperties(ann, hasTarget))
if (target.getURI() != null)
pathAnn.getAboutList().add(
relativizeFromBase(target.getURI(), root));
manifest.getAnnotations().add(pathAnn);
}
}
}
}