T3-1109 Avoid network-dependency for bundle context
jsonld dependency 0.3 instead of 0.2.99-mygrid
diff --git a/pom.xml b/pom.xml
index 2538cc8..1b0d3cb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<scufl2.version>0.11.0</scufl2.version>
- <jsonld.version>0.2.99-mygrid</jsonld.version>
+ <jsonld.version>0.3</jsonld.version>
<!-- Raven: Jena and Jackson versions must match dependencies
from jsonld *and* scufl2 -->
<jena.version>2.11.0</jena.version>
@@ -74,7 +74,12 @@
<type>bundle</type>
</dependency>
-->
-
+
+ <dependency>
+ <groupId>uk.org.taverna.httpclientjarcache</groupId>
+ <artifactId>httpclient-jarcache</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </dependency>
</dependencies>
<scm>
diff --git a/src/main/java/org/purl/wf4ever/robundle/manifest/Manifest.java b/src/main/java/org/purl/wf4ever/robundle/manifest/Manifest.java
index 99f365c..961aae0 100644
--- a/src/main/java/org/purl/wf4ever/robundle/manifest/Manifest.java
+++ b/src/main/java/org/purl/wf4ever/robundle/manifest/Manifest.java
@@ -12,7 +12,6 @@
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.LinkedHashMap;
diff --git a/src/main/java/org/purl/wf4ever/robundle/manifest/RDFToManifest.java b/src/main/java/org/purl/wf4ever/robundle/manifest/RDFToManifest.java
index f1b02c3..9b24e2d 100644
--- a/src/main/java/org/purl/wf4ever/robundle/manifest/RDFToManifest.java
+++ b/src/main/java/org/purl/wf4ever/robundle/manifest/RDFToManifest.java
@@ -14,9 +14,14 @@
import java.util.UUID;
import java.util.logging.Logger;
+import org.apache.http.client.HttpClient;
+import org.apache.http.impl.client.cache.CachingHttpClient;
import org.apache.jena.riot.RDFDataMgr;
import org.apache.jena.riot.RiotException;
+import uk.org.taverna.httpclient.jarcache.JarCacheStorage;
+
+import com.github.jsonldjava.core.DocumentLoader;
import com.github.jsonldjava.jena.JenaJSONLD;
import com.hp.hpl.jena.datatypes.xsd.XSDDateTime;
import com.hp.hpl.jena.ontology.DatatypeProperty;
@@ -33,409 +38,440 @@
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
public class RDFToManifest {
- private static Logger logger = Logger.getLogger(RDFToManifest.class.getCanonicalName());
-
- private static final String PROV = "http://www.w3.org/ns/prov#";
- private static final String PROV_O = "http://www.w3.org/ns/prov-o#";
- private static final String FOAF_0_1 = "http://xmlns.com/foaf/0.1/";
- private static final String PAV = "http://purl.org/pav/";
+
+ private static Logger logger = Logger.getLogger(RDFToManifest.class
+ .getCanonicalName());
- private static final String DCT = "http://purl.org/dc/terms/";
- //private static final String RO = "http://purl.org/wf4ever/ro#";
- private static final String ORE = "http://www.openarchives.org/ore/terms/";
- private static final String OA = "http://www.w3.org/ns/oa#";
- private static final String FOAF_RDF = "/ontologies/foaf.rdf";
- private static final String PAV_RDF = "/ontologies/pav.rdf";
- private static final String PROV_O_RDF = "/ontologies/prov-o.rdf";
- private static final String PROV_AQ_RDF = "/ontologies/prov-aq.rdf";
- private OntModel ore;
- private ObjectProperty aggregates;
- private ObjectProperty proxyFor;
- private ObjectProperty proxyIn;
+ static {
+ setCachedHttpClientInJsonLD();
+ }
+
+ private static final String PROV = "http://www.w3.org/ns/prov#";
+ private static final String PROV_O = "http://www.w3.org/ns/prov-o#";
+ private static final String FOAF_0_1 = "http://xmlns.com/foaf/0.1/";
+ private static final String PAV = "http://purl.org/pav/";
- private OntClass aggregation;
- private OntModel foaf;
- private DatatypeProperty foafName;
- private OntModel pav;
- private ObjectProperty createdBy;
- private OntModel prov;
- private OntModel provaq;
- private ObjectProperty hasProvenance;
- private OntModel dct;
- private ObjectProperty conformsTo;
- private OntClass standard;
- private ObjectProperty authoredBy;
- private DatatypeProperty createdOn;
- private DatatypeProperty authoredOn;
+ private static final String DCT = "http://purl.org/dc/terms/";
+ // private static final String RO = "http://purl.org/wf4ever/ro#";
+ private static final String ORE = "http://www.openarchives.org/ore/terms/";
+ private static final String OA = "http://www.w3.org/ns/oa#";
+ private static final String FOAF_RDF = "/ontologies/foaf.rdf";
+ private static final String PAV_RDF = "/ontologies/pav.rdf";
+ private static final String PROV_O_RDF = "/ontologies/prov-o.rdf";
+ private static final String PROV_AQ_RDF = "/ontologies/prov-aq.rdf";
+ private OntModel ore;
+ private ObjectProperty aggregates;
+ private ObjectProperty proxyFor;
+ private ObjectProperty proxyIn;
- private DatatypeProperty format;
+ private OntClass aggregation;
+ private OntModel foaf;
+ private DatatypeProperty foafName;
+ private OntModel pav;
+ private ObjectProperty createdBy;
+ private OntModel prov;
+ private OntModel provaq;
+ private ObjectProperty hasProvenance;
+ private OntModel dct;
+ private ObjectProperty conformsTo;
+ private OntClass standard;
+ private ObjectProperty authoredBy;
+ private DatatypeProperty createdOn;
+ private DatatypeProperty authoredOn;
- private OntModel oa;
+ private DatatypeProperty format;
- private ObjectProperty hasBody;
+ private OntModel oa;
- private ObjectProperty hasTarget;
+ private ObjectProperty hasBody;
- public RDFToManifest() {
- loadOntologies();
- }
-
- protected void loadOntologies() {
- loadDCT();
- loadORE();
- loadFOAF();
- loadPROVO();
- loadPAV();
- loadPROVAQ();
- loadOA();
- }
+ private ObjectProperty hasTarget;
+ public RDFToManifest() {
+ loadOntologies();
+ }
- protected OntModel loadOntologyFromClasspath(String classPathUri, String uri) {
- OntModel ontModel = ModelFactory.createOntologyModel();
+ protected void loadOntologies() {
+ loadDCT();
+ loadORE();
+ loadFOAF();
+ loadPROVO();
+ loadPAV();
+ loadPROVAQ();
+ loadOA();
+ }
- // 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);
- return ontModel;
- }
+ protected OntModel loadOntologyFromClasspath(String classPathUri, String uri) {
+ OntModel ontModel = ModelFactory.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);
+ return ontModel;
+ }
-
-
- protected static Model jsonLdAsJenaModel(InputStream jsonIn, URI base) throws IOException,
- RiotException {
- JenaJSONLD.init();
- Model model = ModelFactory.createDefaultModel();
- RDFDataMgr.read(model, jsonIn, base.toASCIIString(), JenaJSONLD.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;
- }
-
- private void checkNotNull(Object... possiblyNulls) {
- int i=0;
- for (Object check : possiblyNulls) {
- if (check == null) {
- throw new IllegalStateException("Could not load item #" + i);
- }
- i++;
- }
-
- }
+
+
+ protected static Model jsonLdAsJenaModel(InputStream jsonIn, URI base)
+ throws IOException, RiotException {
+ JenaJSONLD.init();
+ Model model = ModelFactory.createDefaultModel();
+ RDFDataMgr.read(model, jsonIn, base.toASCIIString(), JenaJSONLD.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 OntModel getOntModel() {
- OntModel ontModel = ModelFactory.createOntologyModel();
- 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;
- }
-//
- protected synchronized void loadFOAF() {
- if (foaf != null) {
- return;
- }
+ /**
+ * 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);
+ }
+ }
- OntModel ontModel = loadOntologyFromClasspath(FOAF_RDF, FOAF_0_1);
-
- // properties from foaf
- foafName = ontModel.getDatatypeProperty(FOAF_0_1 + "name");
- checkNotNull(foafName);
-
- foaf = ontModel;
- }
-
+ private void checkNotNull(Object... possiblyNulls) {
+ int i = 0;
+ for (Object check : possiblyNulls) {
+ if (check == null) {
+ throw new IllegalStateException("Could not load item #" + i);
+ }
+ i++;
+ }
- 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 OntModel getOntModel() {
+ OntModel ontModel = ModelFactory.createOntologyModel();
+ 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;
+ }
- protected synchronized void loadPROVO() {
- if (prov != null) {
- return;
- }
- OntModel ontModel = loadOntologyFromClasspath(PROV_O_RDF, PROV_O);
-
- checkNotNull(ontModel);
-
- prov = ontModel;
- }
+ //
+ protected synchronized void loadFOAF() {
+ if (foaf != null) {
+ return;
+ }
+ OntModel ontModel = loadOntologyFromClasspath(FOAF_RDF, FOAF_0_1);
- 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;
- }
+ // properties from foaf
+ foafName = ontModel.getDatatypeProperty(FOAF_0_1 + "name");
+ checkNotNull(foafName);
+ foaf = ontModel;
+ }
- protected synchronized void loadDCT() {
- if (dct != null) {
- return;
- }
+ protected synchronized void loadPAV() {
+ if (pav != 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");
+ 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);
- // 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 loadOA() {
- if (oa != null) {
- return;
- }
- OntModel ontModel = loadOntologyFromClasspath("/ontologies/oa.rdf", OA);
- hasTarget = ontModel.getObjectProperty(OA + "hasTarget");
- hasBody = ontModel.getObjectProperty(OA + "hasBody");
- checkNotNull(hasTarget, hasBody);
- oa = 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");
+ pav = ontModel;
+ }
- aggregates = ontModel.getObjectProperty(ORE + "aggregates");
- proxyFor = ontModel.getObjectProperty(ORE + "proxyFor");
- proxyIn = ontModel.getObjectProperty(ORE + "proxyIn");
-
- checkNotNull(aggregation, aggregates, proxyFor, proxyIn);
-
-
- ore = ontModel;
- }
-
- public static <T> ClosableIterable<T> iterate(ExtendedIterator<T> iterator) {
- return new ClosableIterable<T>(iterator);
- }
-
- public static class ClosableIterable<T> implements AutoCloseable, Iterable<T> {
+ protected synchronized void loadPROVO() {
+ if (prov != null) {
+ return;
+ }
+ OntModel ontModel = loadOntologyFromClasspath(PROV_O_RDF, PROV_O);
- private ExtendedIterator<T> iterator;
+ checkNotNull(ontModel);
- public ClosableIterable(ExtendedIterator<T> iterator) {
- this.iterator = iterator;
- }
+ prov = ontModel;
+ }
- @Override
- public void close() {
- iterator.close();
- }
+ protected synchronized void loadPROVAQ() {
+ if (provaq != null) {
+ return;
+ }
+ OntModel ontModel = loadOntologyFromClasspath(PROV_AQ_RDF, PAV);
- @Override
- public ExtendedIterator<T> iterator() {
- return iterator;
- }
- }
+ // properties from foaf
+ hasProvenance = ontModel.getObjectProperty(PROV + "has_provenance");
+ checkNotNull(hasProvenance);
- public void readTo(InputStream resourceAsStream, Manifest manifest) throws IOException, RiotException {
- OntModel model = new RDFToManifest().getOntModel();
- URI base;
- try {
- base = makeBaseURI();
- } catch (URISyntaxException e) {
- throw new IllegalStateException("Can't make base URI of form app://{uuid}/", e);
- }
-
- model.add(jsonLdAsJenaModel(resourceAsStream, base));
-
- Individual ro = findRO(model, base);
-
+ provaq = ontModel;
+ }
+ protected synchronized void loadDCT() {
+ if (dct != null) {
+ return;
+ }
- List<Agent> creators = getAgents(base, ro, createdBy);
- if (! creators.isEmpty()) {
- manifest.setCreatedBy(creators);
- }
- RDFNode created = ro.getPropertyValue(createdOn);
- manifest.setCreatedOn(literalAsFileTime(created));
+ OntModel ontModel = loadOntologyFromClasspath(
+ "/ontologies/dcterms_od.owl",
+ "http://purl.org/wf4ever/dcterms_od");
- List<Agent> authors = getAgents(base, 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, base));
-
- Resource proxy = aggrResource.getPropertyResourceValue(proxyFor);
- if (proxy != null && proxy.getURI() != null) {
- meta.setProxy(relativizeFromBase(proxy.getURI(), base));
- }
+ // 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);
-
- creators = getAgents(base, aggrResource, createdBy);
- if (! creators.isEmpty()) {
- meta.setCreatedBy(creators);
- }
- meta.setCreatedOn(literalAsFileTime(aggrResource.getPropertyValue(createdOn)));
+ dct = ontModel;
-
- for (Individual standard : listObjectProperties(aggrResource, conformsTo)) {
- if (standard.getURI() != null) {
- meta.setConformsTo(relativizeFromBase(standard.getURI(), base));
- }
- }
-
- RDFNode mediaType = aggrResource.getPropertyValue(format);
- if (mediaType != null && mediaType.isLiteral()) {
- meta.setMediatype(mediaType.asLiteral().getLexicalForm());
- }
-
-
- }
-
- try (ClosableIterable<Resource> annotations = iterate( model.listResourcesWithProperty(hasTarget) )) {
- for (Resource ann : annotations) {
- //System.out.println("Found annotation " + ann);
-
- // Normally just one body per annotation, but just in case we'll iterate
- // and split them out
- for (Individual body : listObjectProperties(model.getOntResource(ann), hasBody)) {
- PathAnnotation pathAnn = new PathAnnotation();
-
- if (ann.getURI() != null) {
- pathAnn.setAnnotation(relativizeFromBase(ann.getURI(), base));
- }
-
- Resource target = ann.getPropertyResourceValue(hasTarget);
- if (target != null && target.getURI() != null) {
- pathAnn.setAbout(relativizeFromBase(target.getURI(), base));
- }
- if (body.getURI() != null) {
- pathAnn.setContent(relativizeFromBase(body.getURI(), base));
- } else {
- logger.warning("Can't find annotation body for anonymous " + body);
- }
- manifest.getAnnotations().add(pathAnn);
- }
- }
- }
-
-// model.write(System.out, "TURTLE");
-
- }
+ }
- private FileTime literalAsFileTime(RDFNode rdfNode) {
- if (rdfNode == null) {
- return null;
- }
- if (! rdfNode.isLiteral()) {
- logger.warning("Expected literal. not " + rdfNode);
- }
- Literal literal = rdfNode.asLiteral();
- Object value = literal.getValue();
- if (! (value instanceof XSDDateTime)) {
- logger.warning("Literal not an XSDDateTime, but: " + value.getClass() + " " + value);
- return null;
- }
- XSDDateTime dateTime = (XSDDateTime) value;
- long millis = dateTime.asCalendar().getTimeInMillis();
- return FileTime.fromMillis(millis);
- }
+ protected synchronized void loadOA() {
+ if (oa != null) {
+ return;
+ }
+ OntModel ontModel = loadOntologyFromClasspath("/ontologies/oa.rdf", OA);
+ hasTarget = ontModel.getObjectProperty(OA + "hasTarget");
+ hasBody = ontModel.getObjectProperty(OA + "hasBody");
+ checkNotNull(hasTarget, hasBody);
+ oa = ontModel;
+ }
- private List<Agent> getAgents(URI base, Individual in, ObjectProperty property) {
- List<Agent> 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 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");
- protected static URI makeBaseURI() throws URISyntaxException {
- return new URI("app", UUID.randomUUID().toString(), "/", (String)null);
- }
+ aggregates = ontModel.getObjectProperty(ORE + "aggregates");
+ proxyFor = ontModel.getObjectProperty(ORE + "proxyFor");
+ proxyIn = ontModel.getObjectProperty(ORE + "proxyIn");
+ checkNotNull(aggregation, aggregates, proxyFor, proxyIn);
+ ore = ontModel;
+ }
+ public static <T> ClosableIterable<T> iterate(ExtendedIterator<T> iterator) {
+ return new ClosableIterable<T>(iterator);
+ }
- private Set<Individual> listObjectProperties(OntResource ontResource,
- ObjectProperty prop) {
- LinkedHashSet<Individual> results = new LinkedHashSet<>();
- try (ClosableIterable<RDFNode> 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;
- }
+ public static class ClosableIterable<T> implements AutoCloseable,
+ Iterable<T> {
- 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 ExtendedIterator<T> iterator;
+
+ public ClosableIterable(ExtendedIterator<T> iterator) {
+ this.iterator = iterator;
+ }
+
+ @Override
+ public void close() {
+ iterator.close();
+ }
+
+ @Override
+ public ExtendedIterator<T> iterator() {
+ return iterator;
+ }
+ }
+
+ public void readTo(InputStream resourceAsStream, Manifest manifest)
+ throws IOException, RiotException {
+ OntModel model = new RDFToManifest().getOntModel();
+ URI base;
+ try {
+ base = makeBaseURI();
+ } catch (URISyntaxException e) {
+ throw new IllegalStateException(
+ "Can't make base URI of form app://{uuid}/", e);
+ }
+
+ model.add(jsonLdAsJenaModel(resourceAsStream, base));
+
+ Individual ro = findRO(model, base);
+
+ List<Agent> creators = getAgents(base, ro, createdBy);
+ if (!creators.isEmpty()) {
+ manifest.setCreatedBy(creators);
+ }
+ RDFNode created = ro.getPropertyValue(createdOn);
+ manifest.setCreatedOn(literalAsFileTime(created));
+
+ List<Agent> authors = getAgents(base, 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, base));
+
+ Resource proxy = aggrResource.getPropertyResourceValue(proxyFor);
+ if (proxy != null && proxy.getURI() != null) {
+ meta.setProxy(relativizeFromBase(proxy.getURI(), base));
+ }
+
+ creators = getAgents(base, aggrResource, createdBy);
+ if (!creators.isEmpty()) {
+ meta.setCreatedBy(creators);
+ }
+ meta.setCreatedOn(literalAsFileTime(aggrResource
+ .getPropertyValue(createdOn)));
+
+ for (Individual standard : listObjectProperties(aggrResource,
+ conformsTo)) {
+ if (standard.getURI() != null) {
+ meta.setConformsTo(relativizeFromBase(standard.getURI(),
+ base));
+ }
+ }
+
+ RDFNode mediaType = aggrResource.getPropertyValue(format);
+ if (mediaType != null && mediaType.isLiteral()) {
+ meta.setMediatype(mediaType.asLiteral().getLexicalForm());
+ }
+
+ }
+
+ try (ClosableIterable<Resource> annotations = iterate(model
+ .listResourcesWithProperty(hasTarget))) {
+ for (Resource ann : annotations) {
+ // System.out.println("Found annotation " + ann);
+
+ // Normally just one body per annotation, but just in case we'll
+ // iterate
+ // and split them out
+ for (Individual body : listObjectProperties(
+ model.getOntResource(ann), hasBody)) {
+ PathAnnotation pathAnn = new PathAnnotation();
+
+ if (ann.getURI() != null) {
+ pathAnn.setAnnotation(relativizeFromBase(ann.getURI(),
+ base));
+ }
+
+ Resource target = ann.getPropertyResourceValue(hasTarget);
+ if (target != null && target.getURI() != null) {
+ pathAnn.setAbout(relativizeFromBase(target.getURI(),
+ base));
+ }
+ if (body.getURI() != null) {
+ pathAnn.setContent(relativizeFromBase(body.getURI(),
+ base));
+ } else {
+ logger.warning("Can't find annotation body for anonymous "
+ + body);
+ }
+ manifest.getAnnotations().add(pathAnn);
+ }
+ }
+ }
+
+ // model.write(System.out, "TURTLE");
+
+ }
+
+ private FileTime literalAsFileTime(RDFNode rdfNode) {
+ if (rdfNode == null) {
+ return null;
+ }
+ if (!rdfNode.isLiteral()) {
+ logger.warning("Expected literal. not " + rdfNode);
+ }
+ Literal literal = rdfNode.asLiteral();
+ Object value = literal.getValue();
+ if (!(value instanceof XSDDateTime)) {
+ logger.warning("Literal not an XSDDateTime, but: "
+ + value.getClass() + " " + value);
+ return null;
+ }
+ XSDDateTime dateTime = (XSDDateTime) value;
+ long millis = dateTime.asCalendar().getTimeInMillis();
+ return FileTime.fromMillis(millis);
+ }
+
+ private List<Agent> getAgents(URI base, Individual in,
+ ObjectProperty property) {
+ List<Agent> 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 static URI makeBaseURI() throws URISyntaxException {
+ return new URI("app", UUID.randomUUID().toString(), "/", (String) null);
+ }
+
+ private Set<Individual> listObjectProperties(OntResource ontResource,
+ ObjectProperty prop) {
+ LinkedHashSet<Individual> results = new LinkedHashSet<>();
+ try (ClosableIterable<RDFNode> 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;
+ }
+
+ 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());
+ }
}
diff --git a/src/main/resources/contexts/bundle.jsonld b/src/main/resources/contexts/bundle.jsonld
new file mode 100644
index 0000000..3a5c031
--- /dev/null
+++ b/src/main/resources/contexts/bundle.jsonld
@@ -0,0 +1,110 @@
+{
+ "@context": {
+ "ao": "http://purl.org/ao/",
+ "oa": "http://www.w3.org/ns/oa#",
+ "dc": "http://purl.org/dc/elements/1.1/",
+ "dct": "http://purl.org/dc/terms/",
+ "ore": "http://www.openarchives.org/ore/terms/",
+ "ro": "http://purl.org/wf4ever/ro#",
+ "roterms": "http://purl.org/wf4ever/roterms#",
+ "bundle": "http://purl.org/wf4ever/bundle#",
+ "prov": "http://www.w3.org/ns/prov#",
+ "pav": "http://purl.org/pav/",
+ "xsd": "http://www.w3.org/2001/XMLSchema#",
+ "foaf": "http://xmlns.com/foaf/0.1/",
+
+ "id": "@id",
+ "file": "@id",
+ "uri": "@id",
+ "annotation": "@id",
+
+ "manifest": {
+ "@id": "ore:isDescribedBy",
+ "@type": "@id"
+ },
+
+ "createdOn": {
+ "@id": "pav:createdOn",
+ "@type": "xsd:dateTime"
+ },
+ "createdBy": {
+ "@id": "pav:createdBy",
+ "@type": "@id"
+ },
+ "authoredOn": {
+ "@id": "pav:authoredOn",
+ "@type": "xsd:dateTime"
+ },
+ "authoredBy": {
+ "@id": "pav:authoredBy",
+ "@type": "@id"
+ },
+ "curatedOn": {
+ "@id": "pav:curatedOn",
+ "@type": "xsd:dateTime"
+ },
+ "curatedBy": {
+ "@id": "pav:curatedBy",
+ "@type": "@id"
+ },
+ "contributedOn": {
+ "@id": "pav:contributedOn",
+ "@type": "xsd:dateTime"
+ },
+ "contributedBy": {
+ "@id": "pav:contributedBy",
+ "@type": "@id"
+ },
+ "name": {
+ "@id": "foaf:name"
+ },
+ "orcid": {
+ "@id": "roterms:orcid",
+ "@type": "@id"
+ },
+ "history": {
+ "@id": "prov:has_provenance",
+ "@type": "@id"
+ },
+ "aggregates": {
+ "@id": "ore:aggregates",
+ "@type": "@id"
+ },
+ "mediatype": {
+ "@id": "dc:format"
+ },
+ "folder": {
+ "@id": "bundle:inFolder",
+ "@type": "@id"
+ },
+ "proxy": {
+ "@id": "bundle:hasProxy",
+ "@type": "@id"
+ },
+ "bundledAs": {
+ "@id": "bundle:name",
+ "@type": "@id"
+ },
+ "conformsTo": {
+ "@id": "dct:conformsTo",
+ "@type": "@id"
+ },
+ "annotations": {
+ "@id": "bundle:hasAnnotation",
+ "@type": "@id"
+ },
+ "content": {
+ "@id": "oa:hasBody",
+ "@type": "@id"
+ },
+ "about": {
+ "@id": "oa:hasTarget",
+ "@type": "@id"
+ }
+
+
+ },
+ "http://purl.org/pav/retrievedFrom": {
+ "@id": "https://w3id.org/bundle/context"
+ }
+}
diff --git a/src/main/resources/jarcache.json b/src/main/resources/jarcache.json
new file mode 100644
index 0000000..34df158
--- /dev/null
+++ b/src/main/resources/jarcache.json
@@ -0,0 +1,8 @@
+[
+ {
+ "Content-Location": "https://w3id.org/bundle/context",
+ "X-Classpath": "contexts/bundle.jsonld",
+ "Content-Type": "application/ld+json"
+ }
+]
+
diff --git a/src/test/java/org/purl/wf4ever/robundle/manifest/TestRDFToManifest.java b/src/test/java/org/purl/wf4ever/robundle/manifest/TestRDFToManifest.java
new file mode 100644
index 0000000..3747b46
--- /dev/null
+++ b/src/test/java/org/purl/wf4ever/robundle/manifest/TestRDFToManifest.java
@@ -0,0 +1,23 @@
+package org.purl.wf4ever.robundle.manifest;
+
+import static org.junit.Assert.*;
+
+import java.net.URL;
+import java.util.Map;
+
+import org.junit.Test;
+
+import com.github.jsonldjava.core.DocumentLoader;
+
+public class TestRDFToManifest {
+ private static final String CONTEXT = "https://w3id.org/bundle/context";
+
+ @Test
+ public void contextLoadedFromJarCache() throws Exception {
+ RDFToManifest.makeBaseURI(); // trigger static{} block
+ Map<String, Object> context = (Map<String, Object>) DocumentLoader.fromURL(new URL(CONTEXT));
+ Object retrievedFrom = context.get("http://purl.org/pav/retrievedFrom");
+ assertNotNull("Did not load context from cache: " + CONTEXT, retrievedFrom);
+
+ }
+}