diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 30b7012..457e8ad 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -17,7 +17,7 @@ jobs: - name: Set up JDK, for pushing into github package registry uses: actions/setup-java@v5 with: - java-version: '25' + java-version: '21' distribution: 'temurin' cache: maven diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index df45c47..0c05581 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -16,10 +16,10 @@ jobs: steps: - uses: actions/checkout@v6 - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v5 with: - java-version: '17' + java-version: '21' distribution: 'temurin' cache: maven diff --git a/cli/src/main/java/de/wwu/scdh/annotation/selection/cli/NormalizeWADM.java b/cli/src/main/java/de/wwu/scdh/annotation/selection/cli/NormalizeWADM.java index 68eb2ef..5e2c4e6 100644 --- a/cli/src/main/java/de/wwu/scdh/annotation/selection/cli/NormalizeWADM.java +++ b/cli/src/main/java/de/wwu/scdh/annotation/selection/cli/NormalizeWADM.java @@ -1,13 +1,12 @@ package de.wwu.scdh.annotation.selection.cli; import com.apicatalog.jsonld.JsonLd; +import com.apicatalog.jsonld.JsonLdEmbed; +import com.apicatalog.jsonld.JsonLdOptions; import com.apicatalog.jsonld.api.FramingApi; -import com.apicatalog.jsonld.document.Document; import com.apicatalog.jsonld.document.JsonDocument; -import com.apicatalog.jsonld.document.RdfDocument; -import com.apicatalog.jsonld.lang.Keywords; -import com.apicatalog.rdf.RdfDataset; import de.wwu.scdh.annotation.selection.Resource; +import de.wwu.scdh.annotation.selection.utils.StaticDocumentLoader; import de.wwu.scdh.annotation.selection.wadm.NormalizeAnnotation; import jakarta.json.Json; import jakarta.json.JsonArray; @@ -30,9 +29,11 @@ import org.apache.jena.riot.RDFLanguages; import org.apache.jena.riot.RDFWriterRegistry; import org.apache.jena.riot.WriterDatasetRIOT; -import org.apache.jena.riot.system.JenaTitanium; import org.apache.jena.riot.system.PrefixMap; import org.apache.jena.riot.system.PrefixMapZero; +import org.apache.jena.riot.system.jsonld.JenaToTitanium; +import org.apache.jena.sparql.core.DatasetGraph; +import org.apache.jena.sparql.core.DatasetGraphFactory; import org.apache.jena.sparql.core.DatasetImpl; import org.apache.jena.sparql.util.Context; import picocli.CommandLine; @@ -123,17 +124,19 @@ public Integer call() throws Exception { // do the framing and serialization with Titanium try { - RdfDataset rdfds = JenaTitanium.convert(ds.asDatasetGraph()); - Document rdfdoc = RdfDocument.of(rdfds); - // The Titanium API for framing does not allow - // RdfDocuments. Thus, we make a JsonDocument - // representing the graph like for plain output - JsonArray array = JsonLd.fromRdf(rdfdoc).get(); - JsonObject jsonStructure = - Json.createObjectBuilder().add(Keywords.GRAPH, array).build(); - JsonDocument jsonDocument = JsonDocument.of(jsonStructure); + // use titanium for framing + JsonLdOptions options = new JsonLdOptions(); + // options.setBase(null); + options.setDocumentLoader(new StaticDocumentLoader()); + options.setOmitGraph(true); + options.setEmbed(JsonLdEmbed.ALWAYS); + // add more options here! + DatasetGraph dsg = DatasetGraphFactory.create(model.getGraph()); + JsonArray ja = JenaToTitanium.convert(dsg, options); + JsonDocument jDoc = JsonDocument.of(ja); // do the framing - FramingApi api = JsonLd.frame(jsonDocument, JsonDocument.of(framingUri.openStream())); + FramingApi api = JsonLd.frame(jDoc, JsonDocument.of(framingUri.openStream())); + api.loader(options.getDocumentLoader()); // important to set loader! final JsonObject output = api.get(); // JsonOutput.print(System.out, true); diff --git a/core/src/main/java/de/wwu/scdh/annotation/selection/utils/StaticDocumentLoader.java b/core/src/main/java/de/wwu/scdh/annotation/selection/utils/StaticDocumentLoader.java new file mode 100644 index 0000000..ac06cdc --- /dev/null +++ b/core/src/main/java/de/wwu/scdh/annotation/selection/utils/StaticDocumentLoader.java @@ -0,0 +1,148 @@ +package de.wwu.scdh.annotation.selection.utils; + +import com.apicatalog.jsonld.JsonLdError; +import com.apicatalog.jsonld.JsonLdOptions; +import com.apicatalog.jsonld.document.Document; +import com.apicatalog.jsonld.loader.DocumentLoader; +import com.apicatalog.jsonld.loader.DocumentLoaderOptions; +import com.apicatalog.jsonld.loader.FileLoader; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; +import jakarta.json.JsonStructure; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link StaticDocumentLoader} is a {@link DocumentLoader} that returns local assets instead of remote one. + * It is configured with a resource mapping that maps URIs to local assets. Its purpose is to speed up + * JSON-LD processing with version pinned contexts, as for Web Annotations.

+ * + * The loader delegated to a fallback loader when the requested URI is not in the resource mapping.

+ * + * The structure of the resource mapping JSON file: + * + *

+ *     {
+ *       "https://www.w3.org/ns/anno.jsonld": {
+ *         "path": "anno.jsonld"
+ *       },
+ *       "http://www.w3.org/ns/anno.jsonld": {
+ *         "path": "anno.jsonld"
+ *       }
+ *     }
+ * 
+ */ +public class StaticDocumentLoader implements DocumentLoader { + + private static final Logger LOG = LoggerFactory.getLogger(StaticDocumentLoader.class); + + /** + * A default context mapping resource. + */ + public static final URL CONTEXT_MAPPING = StaticDocumentLoader.class.getResource("/context/context-map.json"); + + private final DocumentLoader fallbackLoader; + + private final Map contextMapping; + + private final boolean delegateOnError; + + /** + * Creates a new {@link StaticDocumentLoader} from a resource mapping given by {@link File}. + * @param contextMap - a JSON {@link File>} with the resource mapping + * @param fallbackLoader - a {@link DocumentLoader} used to handle request for non-mapped resources + * @param delegateOnError - whether to delegate the request to the fallback, when loading of a local asset failed. + */ + public StaticDocumentLoader(final File contextMap, final DocumentLoader fallbackLoader, boolean delegateOnError) { + this.fallbackLoader = fallbackLoader; + this.delegateOnError = delegateOnError; + contextMapping = setup(contextMap); + } + + /** + * Creates a new {@link StaticDocumentLoader} from the {@link StaticDocumentLoader#CONTEXT_MAPPING}. + */ + public StaticDocumentLoader() { + fallbackLoader = (new JsonLdOptions()).getDocumentLoader(); // default loader + delegateOnError = true; + File defaultContextMapping = new File(CONTEXT_MAPPING.getPath()); + contextMapping = setup(defaultContextMapping); + } + + /** + * {@inheritDoc} + */ + @Override + public Document loadDocument(URI url, DocumentLoaderOptions options) throws JsonLdError { + if (contextMapping.containsKey(url)) { + URI file = contextMapping.get(url); + FileLoader fileLoader = new FileLoader(); + try { + return fileLoader.loadDocument(file, options); + } catch (JsonLdError e) { + LOG.error("failed to load static asset for {}: {}", url, e.getMessage()); + if (delegateOnError) { + return fallbackLoader.loadDocument(url, options); + } else { + throw new JsonLdError(e.getCode(), e.getMessage()); + } + } + } else { + // delegate to fallback loader + return fallbackLoader.loadDocument(url, options); + } + } + + private Map setup(File contextMap) { + Path path = contextMap.toPath().getParent(); + Map assets = new HashMap<>(); + + try { + JsonReader jsonReader = Json.createReader(new FileReader(contextMap)); + JsonStructure jsonStructure = jsonReader.read(); + JsonObject root = jsonStructure.asJsonObject(); + for (String url : root.keySet()) { + try { + URI remote = new URI(url); + String relative = root.get(url).asJsonObject().getString("path"); + File resolved = path.resolve(relative).toFile(); + if (resolved.isFile()) { + assets.put(remote, resolved.toURI()); + } else { + LOG.error( + "context map entry {} configures file {}, which resolves to {}. File not present", + url, + relative, + resolved); + } + } catch (URISyntaxException e) { + LOG.error("context map entry {} is not a valid URI. Continuing without this entry", url); + } catch (Exception e) { + LOG.error("invalid context map entry {}. Continuing without this entry", url); + } + } + } catch (FileNotFoundException e) { + LOG.error("file not found: {}\nContinuing without context map", contextMap); + } + return Map.copyOf(assets); // makes map unmodifiable + } + + /** + * Tells whether this instance has a local version for a URI. + * @param uri - the remote URI + * @return - true if a local version is available. + */ + public boolean hasLocal(URI uri) { + return contextMapping.containsKey(uri); + } +} diff --git a/core/src/main/java/de/wwu/scdh/annotation/selection/wadm/NormalizeAnnotation.java b/core/src/main/java/de/wwu/scdh/annotation/selection/wadm/NormalizeAnnotation.java index 77521bd..dc7793a 100644 --- a/core/src/main/java/de/wwu/scdh/annotation/selection/wadm/NormalizeAnnotation.java +++ b/core/src/main/java/de/wwu/scdh/annotation/selection/wadm/NormalizeAnnotation.java @@ -1,18 +1,17 @@ package de.wwu.scdh.annotation.selection.wadm; +import com.apicatalog.jsonld.JsonLdOptions; import de.wwu.scdh.annotation.selection.*; +import de.wwu.scdh.annotation.selection.utils.StaticDocumentLoader; import java.io.InputStream; import java.net.URI; import java.util.Optional; import java.util.function.Consumer; -import org.apache.jena.ontology.OntModelSpec; -import org.apache.jena.ontology.impl.OntModelImpl; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ResIterator; import org.apache.jena.rdf.model.Resource; -import org.apache.jena.riot.Lang; -import org.apache.jena.riot.RDFDataMgr; -import org.apache.jena.riot.RDFLanguages; +import org.apache.jena.riot.*; +import org.apache.jena.riot.system.jsonld.TitaniumJsonLdOptions; import org.apache.jena.vocabulary.OA; import org.apache.jena.vocabulary.RDF; import org.slf4j.Logger; @@ -134,7 +133,12 @@ public static Model rewrite( /** * Normalize all annotations in a {@link Model} given by a URI * as {@link String} which may reference a local file (file URI) - * or an online resource. + * or an online resource.

+ * + * Note, that this method sets options to the RDF parser, e.g., the {@link StaticDocumentLoader} as JSON-LD + * document loader. If you want full control over RDF parsing, the use + * {@link NormalizeAnnotation#normalize(de.wwu.scdh.annotation.selection.Resource, URI, RewriterFactory, RewriterConfig, Model)} + * instead. * * @param resource - the resource the rewriting has to done with * @param iri - the IRI of sources (oa:hasSource) the rewriting has to done on @@ -151,12 +155,10 @@ public static Model normalize( RewriterConfig normalizerConfig, String graph, Optional lang) { - Model model; - if (lang.isEmpty()) { - model = RDFDataMgr.loadModel(graph); - } else { - model = RDFDataMgr.loadModel(graph, RDFLanguages.nameToLang(lang.get())); - } + RDFParserBuilder parserBuilder = RDFParser.source(graph); + setParserOptions(parserBuilder); + lang.ifPresent(l -> parserBuilder.lang(RDFLanguages.nameToLang(l))); + Model model = parserBuilder.toModel(); return normalize(resource, iri, rewriterFactory, normalizerConfig, model); } @@ -164,7 +166,12 @@ public static Model normalize( * Rewrite all annotations in the provided {@link Model}. In contrast to * {@link NormalizeAnnotation#normalize(de.wwu.scdh.annotation.selection.Resource, URI, RewriterFactory, RewriterConfig, String, Optional)} * this method also rewrites the oa:hasSource property and is thus suitable for transforming selectors - * between representations. + * between representations.

+ * + * Note, that this method sets options to the RDF parser, e.g., the {@link StaticDocumentLoader} as JSON-LD + * document loader. If you want full control over RDF parsing, the use + * {@link NormalizeAnnotation#rewrite(de.wwu.scdh.annotation.selection.Resource, URI, URI, RewriterFactory, RewriterConfig, Model)} + * instead. * * @param resource - the resource the rewriting has to done with. Should be a {@link MappedResource}. * @param iri - the IRI of sources (oa:hasSource) the rewriting has to done on @@ -183,18 +190,21 @@ public static Model rewrite( RewriterConfig normalizerConfig, String graph, Optional lang) { - Model model; - if (lang.isEmpty()) { - model = RDFDataMgr.loadModel(graph); - } else { - model = RDFDataMgr.loadModel(graph, RDFLanguages.nameToLang(lang.get())); - } + RDFParserBuilder parserBuilder = RDFParser.source(graph); + setParserOptions(parserBuilder); + lang.ifPresent(l -> parserBuilder.lang(RDFLanguages.nameToLang(l))); + Model model = parserBuilder.toModel(); return rewrite(resource, iri, rewriteIri, rewriterFactory, normalizerConfig, model); } /** * Normalize all annotations in a {@link Model} which is read from - * an {@link InputStream}. + * an {@link InputStream}.

+ * + * Note, that this method sets options to the RDF parser, e.g., the {@link StaticDocumentLoader} as JSON-LD + * document loader. If you want full control over RDF parsing, the use + * {@link NormalizeAnnotation#normalize(de.wwu.scdh.annotation.selection.Resource, URI, RewriterFactory, RewriterConfig, Model)} + * instead. * * @param resource - the resource the rewriting has to done with * @param iri - the IRI of sources (oa:hasSource) the rewriting has to done on @@ -213,18 +223,20 @@ public static Model normalize( InputStream input, Optional lang, Optional modelBase) { - Model model = new OntModelImpl(OntModelSpec.OWL_DL_MEM); - Lang langHint; - if (lang.isEmpty()) { - - langHint = RDFLanguages.nameToLang(lang.get()); + RDFParserBuilder parserBuilder = RDFParser.source(input); + modelBase.ifPresent(parserBuilder::base); + setParserOptions(parserBuilder); + if (lang.isPresent()) { + parserBuilder.lang(RDFLanguages.nameToLang(lang.get())); } else { - langHint = RDFLanguages.NTRIPLES; + parserBuilder.lang(Lang.NTRIPLES); } - if (modelBase.isEmpty()) { - RDFDataMgr.read(model, input, langHint); - } else { - RDFDataMgr.read(model, input, modelBase.get(), langHint); + Model model = parserBuilder.toModel(); + try { + input.close(); + LOG.warn("closed input stream"); + } catch (Exception ignored) { + LOG.warn("failed to close input stream"); } return normalize(resource, iri, rewriterFactory, normalizerConfig, model); } @@ -233,8 +245,13 @@ public static Model normalize( * Rewrite all annotations in the provided {@link Model}. In contrast to * {@link NormalizeAnnotation#normalize(de.wwu.scdh.annotation.selection.Resource, URI, RewriterFactory, RewriterConfig, InputStream, Optional, Optional)} * this method also rewrites the oa:hasSource property and is thus suitable for transforming selectors - * between representations. + * between representations.

* + * Note, that this method sets options to the RDF parser, e.g., the {@link StaticDocumentLoader} as JSON-LD + * document loader. If you want full control over RDF parsing, the use + * {@link NormalizeAnnotation#rewrite(de.wwu.scdh.annotation.selection.Resource, URI, URI, RewriterFactory, RewriterConfig, Model)} + * instead. + * * * @param resource - the resource the rewriting has to done with. Should be a {@link MappedResource}. * @param iri - the IRI of sources (oa:hasSource) the rewriting has to done on * @param rewriterFactory - a factory that returns a rewriter for a point @@ -253,19 +270,25 @@ public static Model rewrite( InputStream input, Optional lang, Optional modelBase) { - Model model = new OntModelImpl(OntModelSpec.OWL_DL_MEM); - Lang langHint; - if (lang.isEmpty()) { - - langHint = RDFLanguages.nameToLang(lang.get()); - } else { - langHint = RDFLanguages.NTRIPLES; - } - if (modelBase.isEmpty()) { - RDFDataMgr.read(model, input, langHint); + RDFParserBuilder parserBuilder = RDFParser.source(input); + modelBase.ifPresent(parserBuilder::base); + setParserOptions(parserBuilder); + if (lang.isPresent()) { + parserBuilder.lang(RDFLanguages.nameToLang(lang.get())); } else { - RDFDataMgr.read(model, input, modelBase.get(), langHint); + parserBuilder.lang(Lang.NTRIPLES); } + Model model = parserBuilder.toModel(); return rewrite(resource, iri, rewriteIri, rewriterFactory, normalizerConfig, model); } + + /** + * Sets RDF parser options. + * @param parserBuilder - the Apache Jena {@link RDFParserBuilder} + */ + private static void setParserOptions(RDFParserBuilder parserBuilder) { + JsonLdOptions options = new JsonLdOptions(); + options.setDocumentLoader(new StaticDocumentLoader()); + parserBuilder.set(TitaniumJsonLdOptions.JSONLD_OPTIONS, options); + } } diff --git a/core/src/main/resources/context/anno.jsonld b/core/src/main/resources/context/anno.jsonld new file mode 100644 index 0000000..1bd517e --- /dev/null +++ b/core/src/main/resources/context/anno.jsonld @@ -0,0 +1,126 @@ +{ + "@context": { + "oa": "http://www.w3.org/ns/oa#", + "dc": "http://purl.org/dc/elements/1.1/", + "dcterms": "http://purl.org/dc/terms/", + "dctypes": "http://purl.org/dc/dcmitype/", + "foaf": "http://xmlns.com/foaf/0.1/", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", + "skos": "http://www.w3.org/2004/02/skos/core#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "iana": "http://www.iana.org/assignments/relation/", + "owl": "http://www.w3.org/2002/07/owl#", + "as": "http://www.w3.org/ns/activitystreams#", + "schema": "http://schema.org/", + + "id": {"@type": "@id", "@id": "@id"}, + "type": {"@type": "@id", "@id": "@type"}, + + "Annotation": "oa:Annotation", + "Dataset": "dctypes:Dataset", + "Image": "dctypes:StillImage", + "Video": "dctypes:MovingImage", + "Audio": "dctypes:Sound", + "Text": "dctypes:Text", + "TextualBody": "oa:TextualBody", + "ResourceSelection": "oa:ResourceSelection", + "SpecificResource": "oa:SpecificResource", + "FragmentSelector": "oa:FragmentSelector", + "CssSelector": "oa:CssSelector", + "XPathSelector": "oa:XPathSelector", + "TextQuoteSelector": "oa:TextQuoteSelector", + "TextPositionSelector": "oa:TextPositionSelector", + "DataPositionSelector": "oa:DataPositionSelector", + "SvgSelector": "oa:SvgSelector", + "RangeSelector": "oa:RangeSelector", + "TimeState": "oa:TimeState", + "HttpRequestState": "oa:HttpRequestState", + "CssStylesheet": "oa:CssStyle", + "Choice": "oa:Choice", + "Person": "foaf:Person", + "Software": "as:Application", + "Organization": "foaf:Organization", + "AnnotationCollection": "as:OrderedCollection", + "AnnotationPage": "as:OrderedCollectionPage", + "Audience": "schema:Audience", + + "Motivation": "oa:Motivation", + "bookmarking": "oa:bookmarking", + "classifying": "oa:classifying", + "commenting": "oa:commenting", + "describing": "oa:describing", + "editing": "oa:editing", + "highlighting": "oa:highlighting", + "identifying": "oa:identifying", + "linking": "oa:linking", + "moderating": "oa:moderating", + "questioning": "oa:questioning", + "replying": "oa:replying", + "reviewing": "oa:reviewing", + "assessing": "oa:assessing", + "tagging": "oa:tagging", + + "auto": "oa:autoDirection", + "ltr": "oa:ltrDirection", + "rtl": "oa:rtlDirection", + + "body": {"@type": "@id", "@id": "oa:hasBody"}, + "target": {"@type": "@id", "@id": "oa:hasTarget"}, + "source": {"@type": "@id", "@id": "oa:hasSource"}, + "selector": {"@type": "@id", "@id": "oa:hasSelector"}, + "state": {"@type": "@id", "@id": "oa:hasState"}, + "scope": {"@type": "@id", "@id": "oa:hasScope"}, + "refinedBy": {"@type": "@id", "@id": "oa:refinedBy"}, + "startSelector": {"@type": "@id", "@id": "oa:hasStartSelector"}, + "endSelector": {"@type": "@id", "@id": "oa:hasEndSelector"}, + "renderedVia": {"@type": "@id", "@id": "oa:renderedVia"}, + "creator": {"@type": "@id", "@id": "dcterms:creator"}, + "generator": {"@type": "@id", "@id": "as:generator"}, + "rights": {"@type": "@id", "@id": "dcterms:rights"}, + "homepage": {"@type": "@id", "@id": "foaf:homepage"}, + "via": {"@type": "@id", "@id": "oa:via"}, + "canonical": {"@type": "@id", "@id": "oa:canonical"}, + "stylesheet": {"@type": "@id", "@id": "oa:styledBy"}, + "cached": {"@type": "@id", "@id": "oa:cachedSource"}, + "conformsTo": {"@type": "@id", "@id": "dcterms:conformsTo"}, + "items": {"@type": "@id", "@id": "as:items", "@container": "@list"}, + "partOf": {"@type": "@id", "@id": "as:partOf"}, + "first": {"@type": "@id", "@id": "as:first"}, + "last": {"@type": "@id", "@id": "as:last"}, + "next": {"@type": "@id", "@id": "as:next"}, + "prev": {"@type": "@id", "@id": "as:prev"}, + "audience": {"@type": "@id", "@id": "schema:audience"}, + "motivation": {"@type": "@vocab", "@id": "oa:motivatedBy"}, + "purpose": {"@type": "@vocab", "@id": "oa:hasPurpose"}, + "textDirection": {"@type": "@vocab", "@id": "oa:textDirection"}, + + "accessibility": "schema:accessibilityFeature", + "bodyValue": "oa:bodyValue", + "format": "dc:format", + "language": "dc:language", + "processingLanguage": "oa:processingLanguage", + "value": "rdf:value", + "exact": "oa:exact", + "prefix": "oa:prefix", + "suffix": "oa:suffix", + "styleClass": "oa:styleClass", + "name": "foaf:name", + "email": "foaf:mbox", + "email_sha1": "foaf:mbox_sha1sum", + "nickname": "foaf:nick", + "label": "rdfs:label", + + "created": {"@id": "dcterms:created", "@type": "xsd:dateTime"}, + "modified": {"@id": "dcterms:modified", "@type": "xsd:dateTime"}, + "generated": {"@id": "dcterms:issued", "@type": "xsd:dateTime"}, + "sourceDate": {"@id": "oa:sourceDate", "@type": "xsd:dateTime"}, + "sourceDateStart": {"@id": "oa:sourceDateStart", "@type": "xsd:dateTime"}, + "sourceDateEnd": {"@id": "oa:sourceDateEnd", "@type": "xsd:dateTime"}, + + "start": {"@id": "oa:start", "@type": "xsd:nonNegativeInteger"}, + "end": {"@id": "oa:end", "@type": "xsd:nonNegativeInteger"}, + "total": {"@id": "as:totalItems", "@type": "xsd:nonNegativeInteger"}, + "startIndex": {"@id": "as:startIndex", "@type": "xsd:nonNegativeInteger"} + } +} diff --git a/core/src/main/resources/context/context-map.json b/core/src/main/resources/context/context-map.json new file mode 100644 index 0000000..22a9b71 --- /dev/null +++ b/core/src/main/resources/context/context-map.json @@ -0,0 +1,8 @@ +{ + "https://www.w3.org/ns/anno.jsonld": { + "path": "anno.jsonld" + }, + "http://www.w3.org/ns/anno.jsonld": { + "path": "anno.jsonld" + } +} \ No newline at end of file diff --git a/core/src/test/java/de/wwu/scdh/annotation/selection/utils/TestStaticDocumentLoader.java b/core/src/test/java/de/wwu/scdh/annotation/selection/utils/TestStaticDocumentLoader.java new file mode 100644 index 0000000..9ba47c4 --- /dev/null +++ b/core/src/test/java/de/wwu/scdh/annotation/selection/utils/TestStaticDocumentLoader.java @@ -0,0 +1,26 @@ +package de.wwu.scdh.annotation.selection.utils; + +import static org.junit.jupiter.api.Assertions.*; + +import java.net.URI; +import java.net.URISyntaxException; +import org.junit.jupiter.api.Test; + +public class TestStaticDocumentLoader { + + @Test + public void testDefaultContextMapping() { + assertNotNull(StaticDocumentLoader.CONTEXT_MAPPING, "context mapping exists and is accessible"); + } + + @Test + public void testNoArgumentConstructor() throws URISyntaxException { + StaticDocumentLoader loader = new StaticDocumentLoader(); + assertTrue( + loader.hasLocal(new URI("https://www.w3.org/ns/anno.jsonld")), + "has local version of Web Annotations context (https)"); + assertTrue( + loader.hasLocal(new URI("http://www.w3.org/ns/anno.jsonld")), + "has local version of Web Annotations context (http)"); + } +} diff --git a/pom.xml b/pom.xml index 0a0a989..eb0354b 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,7 @@ 4.5.1 1.4.01 3.18.0 - 5.2.0 + 6.0.0 6.0.1 3.4.0 2.90.0