From f02e3a15c285bde02d824d8983896d003f26cff8 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Mon, 17 Jun 2024 06:11:34 +0200 Subject: [PATCH 01/58] refactor: extracted from asquare rev. f4556f04cad137b90a6534e56b052f6bfac88689 --- .../asquare/cube/spel/NamedTemplate.java | 74 +++++ .../asquare/cube/spel/SpelConfiguration.java | 14 + .../urigenerator/UriGeneratorCalculator.java | 306 ++++++++++++++++++ .../cube/urigenerator/UriGeneratorResult.java | 50 +++ .../cube/urigenerator/UriReplacement.java | 29 ++ .../cube/urigenerator/json/UriGenerator.java | 54 ++++ .../urigenerator/json/UriGeneratorRoot.java | 74 +++++ .../UriGeneratorCalculatorTest.java | 30 ++ .../UriGeneratorCalculatorTestConfig.java | 26 ++ src/test/resources/urigenerator/model.ttl | 8 + .../urigenerator/uri-generators.json5 | 22 ++ 11 files changed, 687 insertions(+) create mode 100644 src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java create mode 100644 src/main/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java create mode 100644 src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java create mode 100644 src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java create mode 100644 src/test/resources/urigenerator/model.ttl create mode 100644 src/test/resources/urigenerator/uri-generators.json5 diff --git a/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java b/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java new file mode 100644 index 0000000..b4e4ce2 --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java @@ -0,0 +1,74 @@ +package zone.cogni.asquare.cube.spel; + +import org.springframework.core.io.Resource; +import zone.cogni.core.spring.ResourceHelper; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class NamedTemplate { + + /** + * might not be stable: uses filename for name !! + */ + public static List fromResources(Resource... resources) { + return Arrays.stream(resources) + .map(NamedTemplate::fromResource) + .collect(Collectors.toList()); + } + + public static NamedTemplate fromResource(Resource resource) { + return fromResource(resource, resource.getFilename()); + } + + public static NamedTemplate fromResource(Resource resource, String name) { + return fromString(ResourceHelper.toString(resource), name); + } + + public static NamedTemplate fromString(String template, String name) { + return new NamedTemplate(template, name); + } + + private final String template; + private final String name; + + private Object root; + private String result; + + protected NamedTemplate(String template, String name) { + this.template = template; + this.name = name; + } + + /** + * @return copy of template part, not result part + */ + public NamedTemplate copy() { + return new NamedTemplate(template, name); + } + + public String getTemplate() { + return template; + } + + public String getName() { + return name; + } + + public Object getRoot() { + return root; + } + + public void setRoot(Object root) { + this.root = root; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } +} diff --git a/src/main/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java b/src/main/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java new file mode 100644 index 0000000..38ad49c --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java @@ -0,0 +1,14 @@ +package zone.cogni.asquare.cube.spel; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SpelConfiguration { + + @Bean(name = "spelService") + public SpelService getSpelService() { + return new SpelService(); + } + +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java new file mode 100644 index 0000000..4d3f512 --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -0,0 +1,306 @@ +package zone.cogni.asquare.cube.urigenerator; + +import org.apache.commons.lang3.StringUtils; +import org.apache.jena.query.Query; +import org.apache.jena.query.QueryFactory; +import org.apache.jena.query.QuerySolutionMap; +import org.apache.jena.query.ResultSet; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.rdf.model.ResourceFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.Resource; +import zone.cogni.asquare.cube.spel.TemplateService; +import zone.cogni.asquare.cube.urigenerator.json.UriGenerator; +import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; +import zone.cogni.asquare.triplestore.RdfStoreService; +import zone.cogni.asquare.triplestore.jenamemory.InternalRdfStoreService; +import zone.cogni.sem.jena.template.JenaResultSetHandlers; + +import javax.annotation.Nonnull; +import java.io.StringWriter; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public class UriGeneratorCalculator { + private static final Logger log = LoggerFactory.getLogger(UriGeneratorCalculator.class); + + private final String newUriPrefix; + private final TemplateService templateService; + private final UriGeneratorRoot uriGeneratorRoot; + private final Map preparedStatements = new HashMap<>(); + + public UriGeneratorCalculator( + String newUriPrefix, + TemplateService templateService, + Resource uriGeneratorRootResource + ) { + this.newUriPrefix = newUriPrefix; + this.templateService = templateService; + this.uriGeneratorRoot = UriGeneratorRoot.load(uriGeneratorRootResource); + initPreparedStatements(); + } + + private void initPreparedStatements() { + preparedStatements.put("exists-uri", QueryFactory.create("ask { { ?x ?p ?o } union { ?s ?p ?x } } ")); + } + + public String createTemporaryUri() { + return newUriPrefix + "/" + UUID.randomUUID(); + } + + public boolean isNewUri(@Nonnull String uri) { + return uri.startsWith(newUriPrefix); + } + + public Model convert(Model model, Map context) { + RdfStoreService rdfStore = getRdfStore(model); + List results = getGeneratorResults(rdfStore); + + int replaceCount = inputValidations(model, results); + processReplacements(model, rdfStore, replaceCount, context, results); + + validate(model); + + return model; + } + + @Nonnull + private List getGeneratorResults(RdfStoreService rdfStore) { + return uriGeneratorRoot.getGenerators() + .stream() + .map(generator -> getUriGeneratorResult(rdfStore, generator)) + .collect(Collectors.toList()); + } + + @Nonnull + private UriGeneratorResult getUriGeneratorResult(RdfStoreService rdfStore, UriGenerator generator) { + UriGeneratorResult uriGeneratorResult = new UriGeneratorResult(); + uriGeneratorResult.setGenerator(generator); + uriGeneratorResult.setUris(getNewSelectorUris(rdfStore, generator)); + return uriGeneratorResult; + } + + /** + * @return number of uris to be replaces + */ + private int inputValidations(Model model, List results) { + Set incomingUris = getProblemUris(model); + + Set selectedUris = new HashSet<>(); + Set duplicates = results.stream() + .flatMap(result -> result.getUris().stream()) + .filter(uri -> !selectedUris.add(uri)) + .collect(Collectors.toSet()); + + if (!duplicates.isEmpty()) + log.error("some uris matched multiple selectors: {}", duplicates); + + int size = incomingUris.size(); + if (size != selectedUris.size()) + log.error("incoming uris and selected uris do not match up." + + "\n\t incoming: {}" + + "\n\t selected: {}", incomingUris, selectedUris); + + if (!duplicates.isEmpty() || size != selectedUris.size()) + throw new RuntimeException("some validations failed when converting new uris, check logs for more info"); + + + log.info("(uri generator) replacing {} uris", size); + return size; + } + + private void processReplacements(Model model, + RdfStoreService rdfStore, + int replaceCount, + Map context, + List results) { + int loopCount = 0; + while (true) { + int count = calculateReplacementUrisLoop(model, rdfStore, context, results); + replaceCount -= count; + + log.info("(uri generator) loop {} processed {} uris", ++loopCount, count); + + // stop loop when all uris are processed + if (replaceCount == 0) break; + + // stop loop when no replacement where processed + if (count == 0) break; + } + } + + private int calculateReplacementUrisLoop(Model model, + RdfStoreService rdfStore, + Map context, + List results) { + AtomicInteger count = new AtomicInteger(); + + results.forEach(result -> { + result.getUris().forEach(uri -> { + if (result.alreadyReplaced(uri)) return; + + Optional possibleNewUri = calculateNewUri(rdfStore, context, result, uri); + if (possibleNewUri.isPresent()) { + count.addAndGet(1); + result.addReplacement(uri, possibleNewUri.get()); + UriReplacement.replace(model, uri, possibleNewUri.get()); + } + }); + }); + + return count.get(); + } + + private Optional calculateNewUri(RdfStoreService rdfStore, + Map context, + UriGeneratorResult result, + String oldUri) { + if (log.isTraceEnabled()) log.trace("calculate new uri for {}", oldUri); + traceModel(rdfStore); + + Map variables = new HashMap<>(context); + variables.put("uri", oldUri); + + // variable template can also NOT exist: then this step is skipped! + String variableSelector = result.getGenerator().getFullVariableSelector(); + if (StringUtils.isNotBlank(variableSelector)) { + String variableTemplateQuery = uriGeneratorRoot.getPrefixQuery() + variableSelector; + String variableQuery = templateService.processTemplate(variableTemplateQuery, variables); + if (log.isTraceEnabled()) log.trace("query: {}", variableQuery); + + Supplier contextSupplier = () -> result.getGenerator().getId(); + Optional> variableMap = getQueryMap(contextSupplier, rdfStore, variableQuery); + + // if one of template variables is still a new URI we should skip calculation for now + if (!variableMap.isPresent()) return Optional.empty(); + + Map map = variableMap.get(); + if (log.isTraceEnabled()) log.trace("query result: {}", map); + variables.putAll(map); + } + if (log.isTraceEnabled()) log.debug("variables: {}", variables); + + String uriTemplate = result.getGenerator().getUriTemplate(); + String newUri = templateService.processTemplate(uriTemplate, variables); + + if (existsInModel(rdfStore, newUri)) + throw new RuntimeException("uri overlap found for " + newUri); + + return Optional.of(newUri); + } + + private void traceModel(RdfStoreService rdfStore) { + if (!log.isTraceEnabled()) return; + + Model trace = rdfStore.executeConstructQuery("construct {?s ?p ?o} where {?s ?p ?o}"); + StringWriter out = new StringWriter(); + trace.write(out, "ttl"); + log.trace("model: {}", out); + } + + private boolean existsInModel(RdfStoreService rdfStore, String newUri) { + QuerySolutionMap querySolution = new QuerySolutionMap(); + querySolution.add("x", ResourceFactory.createResource(newUri)); + + return rdfStore.executeAskQuery(preparedStatements.get("exists-uri"), querySolution); + } + + /** + * @return empty optional if one of resources start with a newUriPrefix ! + * else a map of variables to be used in uri template! + */ + private Optional> getQueryMap(Supplier context, + RdfStoreService rdfStore, + String variableQuery) { + List> rows = queryForListOfMaps(rdfStore, variableQuery); + if (rows.size() != 1) + throw new RuntimeException("[" + context.get() + "] expected 1 row, found " + rows); + + Map nodeMap = rows.get(0); + boolean isBadMatch = nodeMap.values() + .stream() + .peek(node -> nonNullCheck(nodeMap, node)) + .anyMatch(node -> node.isURIResource() + && node.asResource().getURI().startsWith(newUriPrefix)); + if (isBadMatch) return Optional.empty(); + + Map result = new HashMap<>(); + nodeMap.forEach((k, v) -> { + result.put(k, (v.isResource() ? v.asResource().getURI() : v.asLiteral().getString())); + }); + + return Optional.of(result); + } + + private void nonNullCheck(Map nodeMap, RDFNode node) { + if (node == null) throw new RuntimeException("variableSelector result has some null values: " + nodeMap); + } + + private List> queryForListOfMaps(RdfStoreService rdfStore, String variableQuery) { + try { + return rdfStore.executeSelectQuery(variableQuery, JenaResultSetHandlers.listOfMapsResolver); + } + catch (RuntimeException e) { + throw new RuntimeException("Query failed: \n" + variableQuery, e); + } + } + + private Set getNewSelectorUris(RdfStoreService rdfStore, UriGenerator generator) { + String query = uriGeneratorRoot.getPrefixQuery() + generator.getFullUriSelector(); + List uris = getUris(rdfStore, query); + return uris.stream() + .filter(uri -> uri.startsWith(newUriPrefix)) + .collect(Collectors.toSet()); + } + + private List getUris(RdfStoreService rdfStore, String query) { + try { + return rdfStore.executeSelectQuery(query, UriGeneratorCalculator::convertToList); + } + catch (RuntimeException e) { + throw new RuntimeException("problem with query: \n" + query, e); + } + } + + private static List convertToList(ResultSet resultSet) { + List result = new ArrayList<>(); + + resultSet.forEachRemaining(querySolution -> { + result.add(querySolution.get("uri").asResource().getURI()); + }); + + return result; + } + + private RdfStoreService getRdfStore(Model model) { + return new InternalRdfStoreService(model); + } + + private void validate(Model model) { + Set problemUris = getProblemUris(model); + + if (!problemUris.isEmpty()) throw new RuntimeException("some uris could not be replaced: " + problemUris); + } + + @Nonnull + private Set getProblemUris(Model model) { + Set problemUris = new HashSet<>(); + model.listStatements() + .forEachRemaining(statement -> { + if (statement.getSubject().getURI().startsWith(newUriPrefix)) { + problemUris.add(statement.getSubject().getURI()); + } + + if (statement.getObject().isURIResource() + && statement.getObject().asResource().getURI().startsWith(newUriPrefix)) { + problemUris.add(statement.getObject().asResource().getURI()); + } + }); + return problemUris; + } + +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java new file mode 100644 index 0000000..789fa05 --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java @@ -0,0 +1,50 @@ +package zone.cogni.asquare.cube.urigenerator; + + +import zone.cogni.asquare.cube.urigenerator.json.UriGenerator; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class UriGeneratorResult { + + private UriGenerator generator; + private Set uris; + private Map replacements = new HashMap<>(); + + public UriGeneratorResult() { + } + + public UriGenerator getGenerator() { + return generator; + } + + public void setGenerator(UriGenerator generator) { + this.generator = generator; + } + + public Set getUris() { + return uris; + } + + public void setUris(Set uris) { + this.uris = uris; + } + + public Map getReplacements() { + return replacements; + } + + public void setReplacements(Map replacements) { + this.replacements = replacements; + } + + public boolean alreadyReplaced(String oldUri) { + return replacements.containsKey(oldUri); + } + + public void addReplacement(String oldUri, String newUri) { + replacements.put(oldUri, newUri); + } +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java new file mode 100644 index 0000000..5d45f1b --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java @@ -0,0 +1,29 @@ +package zone.cogni.asquare.cube.urigenerator; + +import org.apache.jena.rdf.model.*; + +import java.util.List; + +public class UriReplacement { + + public static void replace(Model model, String original, String replacement) { + Resource originalResource = ResourceFactory.createResource(original); + Resource replacementResource = ResourceFactory.createResource(replacement); + + List leftStatements = model.listStatements(originalResource, null, (RDFNode) null).toList(); + model.remove(leftStatements); + + leftStatements.forEach(statement -> { + model.add(replacementResource, statement.getPredicate(), statement.getObject()); + }); + + + List rightStatements = model.listStatements(null, null, originalResource).toList(); + model.remove(rightStatements); + + rightStatements.forEach(statement -> { + model.add(statement.getSubject(), statement.getPredicate(), replacementResource); + }); + } + +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java new file mode 100644 index 0000000..a1fbe4b --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java @@ -0,0 +1,54 @@ +package zone.cogni.asquare.cube.urigenerator.json; + +public class UriGenerator { + + private String id; + private String uriSelector; + private String variableSelector; + private String uriTemplate; + + public UriGenerator() { + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUriSelector() { + return uriSelector; + } + + public void setUriSelector(String uriSelector) { + this.uriSelector = uriSelector; + } + + public String getVariableSelector() { + return variableSelector; + } + + public void setVariableSelector(String variableSelector) { + this.variableSelector = variableSelector; + } + + public String getUriTemplate() { + return uriTemplate; + } + + public void setUriTemplate(String uriTemplate) { + this.uriTemplate = uriTemplate; + } + + public String getFullUriSelector() { + if (uriSelector == null) return ""; + return uriSelector; + } + + public String getFullVariableSelector() { + if (variableSelector == null) return ""; + return variableSelector; + } +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java new file mode 100644 index 0000000..f45c84d --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java @@ -0,0 +1,74 @@ +package zone.cogni.asquare.cube.urigenerator.json; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.io.InputStreamSource; +import org.springframework.core.io.Resource; +import zone.cogni.asquare.cube.json5.Json5Light; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class UriGeneratorRoot { + + public static UriGeneratorRoot load(InputStreamSource resource) { + try { + ObjectMapper mapper = Json5Light.getJson5Mapper(); + UriGeneratorRoot result = mapper.readValue(resource.getInputStream(), UriGeneratorRoot.class); + +// result.validate(); + return result; + } + catch (IOException e) { + String extra = getPath(resource) != null ? " Path " + getPath(resource) : ""; + throw new RuntimeException("Unable to load uri generator configuration." + extra, e); + } + } + + private static String getPath(InputStreamSource resource) { + try { + if (resource instanceof Resource) { + Resource r = (Resource) resource; + return r.getFile().getPath(); + } + } + catch (IOException e) { + return null; + } + return null; + } + + private Map prefixes; + private List generators; + + public UriGeneratorRoot() { + } + + public Map getPrefixes() { + return prefixes; + } + + public void setPrefixes(Map prefixes) { + this.prefixes = prefixes; + } + + public List getGenerators() { + return generators; + } + + public void setGenerators(List generators) { + this.generators = generators; + } + + public String getPrefixQuery() { + return prefixes.entrySet() + .stream() + .map(e -> "PREFIX " + + StringUtils.rightPad(e.getKey() + ":", 8) + " <" + e.getValue() + ">\n") + .collect(Collectors.joining()) + + "\n"; + } + +} diff --git a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java new file mode 100644 index 0000000..2ef91f5 --- /dev/null +++ b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java @@ -0,0 +1,30 @@ +package zone.cogni.asquare.cube.urigenerator; + +import com.google.common.collect.ImmutableMap; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ResourceFactory; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.io.ClassPathResource; +import zone.cogni.sem.jena.JenaUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(classes = UriGeneratorCalculatorTestConfig.class) +public class UriGeneratorCalculatorTest { + + @Autowired + UriGeneratorCalculator uriCalculator; + + @Test + public void test_uris_converted() { + //given + Model model = JenaUtils.read(new ClassPathResource("urigenerator/model.ttl")); + //when + Model converted = uriCalculator.convert(model, ImmutableMap.of("baseUri", "http://asquare.cogni.zone")); + //then + assertThat(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/5"))); + assertThat(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/2021/0005"))); + } +} diff --git a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java new file mode 100644 index 0000000..ea38dab --- /dev/null +++ b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java @@ -0,0 +1,26 @@ +package zone.cogni.asquare.cube.urigenerator; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import zone.cogni.asquare.cube.spel.SpelService; + +@Configuration +@Import(SpelService.class) +public class UriGeneratorCalculatorTestConfig { + + @Autowired + private SpelService spelService; + + @Bean + public UriGeneratorCalculator uriCalculator() { + Resource uriGeneratorsResource = new ClassPathResource("urigenerator/uri-generators.json5"); + return new UriGeneratorCalculator("http://resource", + spelService, + uriGeneratorsResource); + } +} + diff --git a/src/test/resources/urigenerator/model.ttl b/src/test/resources/urigenerator/model.ttl new file mode 100644 index 0000000..efd8442 --- /dev/null +++ b/src/test/resources/urigenerator/model.ttl @@ -0,0 +1,8 @@ +@prefix demo: . + + a demo:One ; + demo:id "5" . + + a demo:Two ; + demo:year "2021" ; + demo:sequence "0005" . \ No newline at end of file diff --git a/src/test/resources/urigenerator/uri-generators.json5 b/src/test/resources/urigenerator/uri-generators.json5 new file mode 100644 index 0000000..ba71dad --- /dev/null +++ b/src/test/resources/urigenerator/uri-generators.json5 @@ -0,0 +1,22 @@ +{ + prefixes: { + demo: "http://demo.com/model#" + }, + generators: [ + { + id: "One", + uriSelector: "select ?uri { ?uri a demo:One }", + variableSelector: "select ?id where { <#{[uri]}> demo:id ?id }", + uriTemplate: "#{[baseUri]}/#{[id]}" + }, + { + id: "Two", + uriSelector: "select ?uri { ?uri a demo:Two }", + variableSelector: "select ?year ?sequence where { \ + <#{[uri]}> demo:year ?year ; \ + demo:sequence ?sequence \ + }", + uriTemplate: "#{[baseUri]}/#{[year]}/#{[sequence]}" + } + ] +} \ No newline at end of file From ec1d12262f19557d2957e51454c5f68d7019e947 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 19 Jun 2024 10:30:00 +0200 Subject: [PATCH 02/58] refactor: made independent on asquare --- .../asquare/cube/spel/NamedTemplate.java | 51 ---- .../urigenerator/UriGeneratorCalculator.java | 2 +- .../asquare/triplestore/RdfStoreService.java | 43 +++ .../jenamemory/InternalRdfStoreService.java | 124 +++++++++ .../cogni/core/spring/ResourceHelper.java | 46 ++++ .../java/zone/cogni/core/util/FileHelper.java | 45 ++++ .../java/zone/cogni/core/util/IOHelper.java | 24 ++ .../zone/cogni/sem/jena/AutoCloseModels.java | 26 ++ .../java/zone/cogni/sem/jena/JenaUtils.java | 251 ++++++++++++++++++ .../jena/template/JenaResultSetHandlers.java | 16 ++ 10 files changed, 576 insertions(+), 52 deletions(-) create mode 100644 src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java create mode 100644 src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java create mode 100644 src/main/java/zone/cogni/core/spring/ResourceHelper.java create mode 100644 src/main/java/zone/cogni/core/util/FileHelper.java create mode 100644 src/main/java/zone/cogni/core/util/IOHelper.java create mode 100644 src/main/java/zone/cogni/sem/jena/AutoCloseModels.java create mode 100644 src/main/java/zone/cogni/sem/jena/JenaUtils.java create mode 100644 src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java diff --git a/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java b/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java index b4e4ce2..a341aad 100644 --- a/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java +++ b/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java @@ -1,41 +1,10 @@ package zone.cogni.asquare.cube.spel; -import org.springframework.core.io.Resource; -import zone.cogni.core.spring.ResourceHelper; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - public class NamedTemplate { - /** - * might not be stable: uses filename for name !! - */ - public static List fromResources(Resource... resources) { - return Arrays.stream(resources) - .map(NamedTemplate::fromResource) - .collect(Collectors.toList()); - } - - public static NamedTemplate fromResource(Resource resource) { - return fromResource(resource, resource.getFilename()); - } - - public static NamedTemplate fromResource(Resource resource, String name) { - return fromString(ResourceHelper.toString(resource), name); - } - - public static NamedTemplate fromString(String template, String name) { - return new NamedTemplate(template, name); - } - private final String template; private final String name; - private Object root; - private String result; - protected NamedTemplate(String template, String name) { this.template = template; this.name = name; @@ -51,24 +20,4 @@ public NamedTemplate copy() { public String getTemplate() { return template; } - - public String getName() { - return name; - } - - public Object getRoot() { - return root; - } - - public void setRoot(Object root) { - this.root = root; - } - - public String getResult() { - return result; - } - - public void setResult(String result) { - this.result = result; - } } diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java index 4d3f512..497f01f 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -18,7 +18,7 @@ import zone.cogni.asquare.triplestore.jenamemory.InternalRdfStoreService; import zone.cogni.sem.jena.template.JenaResultSetHandlers; -import javax.annotation.Nonnull; +import jakarta.annotation.Nonnull; import java.io.StringWriter; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java b/src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java new file mode 100644 index 0000000..b3416db --- /dev/null +++ b/src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java @@ -0,0 +1,43 @@ +package zone.cogni.asquare.triplestore; + + +import org.apache.jena.query.Query; +import org.apache.jena.query.QueryFactory; +import org.apache.jena.query.QuerySolutionMap; +import org.apache.jena.query.Syntax; +import org.apache.jena.rdf.model.Model; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import zone.cogni.sem.jena.template.JenaResultSetHandler; + +import java.io.Closeable; + +public interface RdfStoreService extends Closeable { + + Logger log = LoggerFactory.getLogger(RdfStoreService.class); + + @Override + default void close() { + log.info("Closing RdfStoreService ({}) : {}", getClass().getName(), this); + } + + R executeSelectQuery(Query query, QuerySolutionMap bindings, JenaResultSetHandler resultSetHandler, String context); + + default R executeSelectQuery(String query, JenaResultSetHandler resultSetHandler, String context) { + Query parsedQuery = QueryFactory.create(query, Syntax.syntaxARQ); + return executeSelectQuery(parsedQuery, new QuerySolutionMap(), resultSetHandler, context); + } + + default R executeSelectQuery(String query, JenaResultSetHandler resultSetHandler) { + return executeSelectQuery(query, resultSetHandler, null); + } + + boolean executeAskQuery(Query query, QuerySolutionMap bindings); + + Model executeConstructQuery(Query query, QuerySolutionMap bindings); + + default Model executeConstructQuery(String query) { + Query parsedQuery = QueryFactory.create(query, Syntax.syntaxARQ); + return executeConstructQuery(parsedQuery, new QuerySolutionMap()); + } +} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java b/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java new file mode 100644 index 0000000..3954a0b --- /dev/null +++ b/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java @@ -0,0 +1,124 @@ +package zone.cogni.asquare.triplestore.jenamemory; + +import org.apache.commons.lang3.StringUtils; +import org.apache.jena.query.*; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.shared.Lock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.support.ResourcePatternResolver; +import zone.cogni.asquare.triplestore.RdfStoreService; +import zone.cogni.core.spring.ResourceHelper; +import zone.cogni.sem.jena.JenaUtils; +import zone.cogni.sem.jena.template.JenaResultSetHandler; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.function.Supplier; + +public class InternalRdfStoreService implements RdfStoreService { + + private static final Logger log = LoggerFactory.getLogger(InternalRdfStoreService.class); + + private final Model model; + + private ResourcePatternResolver resourcePatternResolver; + private String preLoadLocations; + private String savePath; + + private File storeFile; + private File tempStoreFile; + + public InternalRdfStoreService(Model model) { + this.model = model; + } + + @PostConstruct + private void init() { + if (StringUtils.isNotBlank(savePath)) { + storeFile = new File(savePath, "store.rdf"); + tempStoreFile = new File(savePath, "temp-store.rdf"); + storeFile.getParentFile().mkdirs(); + + if (storeFile.isFile()) JenaUtils.readInto(storeFile, model); + } + + if (resourcePatternResolver == null || StringUtils.isBlank(preLoadLocations)) return; + + Arrays.stream(StringUtils.split(preLoadLocations, ',')).forEach(location -> { + log.info("Loading RDF file {}.", location); + Arrays.stream(ResourceHelper.getResources(resourcePatternResolver, location)).forEach(resource -> { + try (InputStream inputStream = resource.getInputStream()) { + model.read(inputStream, null, JenaUtils.getLangByResourceName(location)); + } + catch (IOException e) { + throw new RuntimeException(e); + } + }); + }); + } + + @Override + public R executeSelectQuery(Query query, QuerySolutionMap bindings, JenaResultSetHandler resultSetHandler, String context) { + return executeInLock(Lock.READ, () -> { + if (log.isTraceEnabled()) log.trace("Select {} - {} \n{}", + context == null ? "" : "--- " + context + " --- ", + bindings, + query); + + try (QueryExecution queryExecution = QueryExecutionFactory.create(query, model, bindings)) { + ResultSet resultSet = queryExecution.execSelect(); + return resultSetHandler.handle(resultSet); + } + catch (RuntimeException e) { + log.error("Query failed: {}", query); + throw e; + } + }); + } + + @Override + public boolean executeAskQuery(Query query, QuerySolutionMap bindings) { + return executeInLock(Lock.READ, () -> { + try (QueryExecution queryExecution = QueryExecutionFactory.create(query, model, bindings)) { + return queryExecution.execAsk(); + } + catch (RuntimeException e) { + log.error("Query failed: {}", query); + throw e; + } + }); + } + + @Override + public Model executeConstructQuery(Query query, QuerySolutionMap bindings) { + return executeInLock(Lock.READ, () -> { + try (QueryExecution queryExecution = QueryExecutionFactory.create(query, model, bindings)) { + if (log.isTraceEnabled()) log.trace("Running construct query: \n{}", query); + return queryExecution.execConstruct(); + } + catch (RuntimeException e) { + log.error("Query failed: {}", query); + throw e; + } + }); + } + + private T executeInLock(boolean lock, Supplier executeInLock) { + model.enterCriticalSection(lock); + try { + return executeInLock.get(); + } + finally { + model.leaveCriticalSection(); + } + } + + public Model getModel() { + return model; + } + +} diff --git a/src/main/java/zone/cogni/core/spring/ResourceHelper.java b/src/main/java/zone/cogni/core/spring/ResourceHelper.java new file mode 100644 index 0000000..d194871 --- /dev/null +++ b/src/main/java/zone/cogni/core/spring/ResourceHelper.java @@ -0,0 +1,46 @@ +package zone.cogni.core.spring; + +import org.apache.commons.io.IOUtils; +import org.springframework.core.io.InputStreamSource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.ResourcePatternResolver; + +import java.io.IOException; +import java.io.InputStream; + +public class ResourceHelper { + + public static Resource[] getResources(ResourcePatternResolver applicationContext, String locationPattern) { + try { + return applicationContext.getResources(locationPattern); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static String toString(InputStreamSource resource) { + return toString(resource, "UTF-8"); + } + + public static String toString(InputStreamSource resource, String encoding) { + try (InputStream inputStream = resource.getInputStream()) { + return IOUtils.toString(inputStream, encoding); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static InputStream getInputStream(T resource) { + try { + return resource.getInputStream(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + private ResourceHelper() { + } +} diff --git a/src/main/java/zone/cogni/core/util/FileHelper.java b/src/main/java/zone/cogni/core/util/FileHelper.java new file mode 100644 index 0000000..cef687d --- /dev/null +++ b/src/main/java/zone/cogni/core/util/FileHelper.java @@ -0,0 +1,45 @@ +package zone.cogni.core.util; + +import com.google.common.io.Files; +import org.apache.commons.io.FileUtils; + +import javax.annotation.Nonnull; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +public class FileHelper { + private FileHelper() { + } + + public static FileInputStream openInputStream(File file) { + try { + return new FileInputStream(file); + } + catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } + + public static FileOutputStream openOutputStream(@Nonnull File file) { + try { + Files.createParentDirs(file); + return FileUtils.openOutputStream(file); + } + catch (IOException e) { + throw new RuntimeException( "Failed to open outputstream to " + file, e); + } + } + + @Deprecated + public static void writeStringToFile(File file, String data) { + try { + FileUtils.writeStringToFile(file, data); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/zone/cogni/core/util/IOHelper.java b/src/main/java/zone/cogni/core/util/IOHelper.java new file mode 100644 index 0000000..ad14e59 --- /dev/null +++ b/src/main/java/zone/cogni/core/util/IOHelper.java @@ -0,0 +1,24 @@ +package zone.cogni.core.util; + + +import java.io.Closeable; +import java.io.Flushable; +import java.io.IOException; + +public class IOHelper { + public static void flushAndClose(X closeFlusher) { + if (closeFlusher == null) return; + + try { + closeFlusher.flush(); + } + catch (IOException ignore) { + } + + try { + closeFlusher.close(); + } + catch (IOException ignore) { + } + } +} diff --git a/src/main/java/zone/cogni/sem/jena/AutoCloseModels.java b/src/main/java/zone/cogni/sem/jena/AutoCloseModels.java new file mode 100644 index 0000000..f9c982d --- /dev/null +++ b/src/main/java/zone/cogni/sem/jena/AutoCloseModels.java @@ -0,0 +1,26 @@ +package zone.cogni.sem.jena; + +import org.apache.jena.rdf.model.Model; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class AutoCloseModels implements AutoCloseable { + + private final Collection models = new ArrayList<>(); + + public AutoCloseModels(Model... models) { + this.models.addAll(Arrays.asList(models)); + } + + public Model add(Model model) { + models.add(model); + return model; + } + + @Override + public void close() { + JenaUtils.closeQuietly(models); + } +} diff --git a/src/main/java/zone/cogni/sem/jena/JenaUtils.java b/src/main/java/zone/cogni/sem/jena/JenaUtils.java new file mode 100644 index 0000000..415be2f --- /dev/null +++ b/src/main/java/zone/cogni/sem/jena/JenaUtils.java @@ -0,0 +1,251 @@ +package zone.cogni.sem.jena; + +import com.google.common.base.Preconditions; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.jena.rdf.model.AnonId; +import org.apache.jena.rdf.model.Literal; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.RDFErrorHandler; +import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.rdf.model.RDFReaderI; +import org.apache.jena.rdf.model.RDFVisitor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.Resource; +import zone.cogni.core.spring.ResourceHelper; +import zone.cogni.core.util.FileHelper; +import zone.cogni.core.util.IOHelper; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +@Deprecated +public class JenaUtils { + private static final Logger log = LoggerFactory.getLogger(JenaUtils.class); + private static final Map extensionToLanguageMap = Collections.synchronizedMap(new HashMap<>()); + + static { + extensionToLanguageMap.put("nt", "N-TRIPLE"); + extensionToLanguageMap.put("n3", "N3"); + extensionToLanguageMap.put("ttl", "TURTLE"); + extensionToLanguageMap.put("jsonld", "JSONLD"); + } + + private JenaUtils() { + } + + public static Model read(Resource... resources) { + return read(Arrays.asList(resources)); + } + + public static Model read(Iterable resources) { + return read(resources, null); + } + + public static Model read(Iterable resources, Map readerProperties) { + Model model = ModelFactory.createDefaultModel(); + + for (Resource resource : resources) { + InputStream inputstream = null; + try { + inputstream = ResourceHelper.getInputStream(resource); + InternalRdfErrorHandler errorHandler = new InternalRdfErrorHandler(resource.getDescription()); + + RDFReaderI rdfReader = getReader(model, resource, errorHandler, readerProperties); + rdfReader.read(model, inputstream, null); + + Preconditions.checkState(!errorHandler.isFailure(), errorHandler.getInfo()); + } + catch (RuntimeException e) { + closeQuietly(model); + + throw e; + } + finally { + IOUtils.closeQuietly(inputstream); + } + } + + return model; + } + + private static RDFReaderI getReader(Model model, Resource resource, RDFErrorHandler rdfErrorHandler, Map readerProperties) { + return getReader(model, rdfErrorHandler, readerProperties, getRdfSyntax(resource)); + } + + private static RDFReaderI getReader(Model model, RDFErrorHandler rdfErrorHandler, Map readerProperties, String language) { + RDFReaderI rdfReader = getReaderByRdfSyntax(model, language); + rdfReader.setErrorHandler(rdfErrorHandler); + if (readerProperties == null) return rdfReader; + + for (String propertyName : readerProperties.keySet()) { + rdfReader.setProperty(propertyName, readerProperties.get(propertyName)); + } + return rdfReader; + } + + private static RDFReaderI getReaderByRdfSyntax(Model model, String language) { + try { + return model.getReader(language); + } + catch (IllegalStateException ignored) { + return model.getReader(); + } + } + + private static String getRdfSyntax(org.springframework.core.io.Resource resource) { + String extension = StringUtils.lowerCase(StringUtils.substringAfterLast(resource.getFilename(), ".")); + + // when return value is null, fall back to RDF/XML + return extensionToLanguageMap.getOrDefault(extension, null); + } + + public static void write(Model model, File file) { + write(model, FileHelper.openOutputStream(file)); + } + + public static void write(Model model, OutputStream out) { + try { + model.write(out); + } + finally { + IOHelper.flushAndClose(out); + } + } + + public static String toString(Model model) { + return toString(model, "RDF/XML"); + } + + public static String toString(Model model, String language) { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + model.write(out, language); + + return out.toString("UTF-8"); + } + catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + + public static void closeQuietly(Model... models) { + Arrays.stream(models).filter(Objects::nonNull).filter(model -> !model.isClosed()).forEach(model -> { + try { + model.close(); + } + catch (Exception e) { + log.warn("Closing model failed.", e); + } + }); + } + + public static void closeQuietly(Iterable models) { + for (Model model : models) { + if (model == null) { + continue; + } + + if (model.isClosed()) { + log.warn("Closing an already closed model."); + continue; + } + + try { + model.close(); + } + catch (Exception e) { + log.warn("Closing model failed.", e); + } + } + } + + public static Model readInto(File file, Model model) { + return readInto(file, model, getLangByResourceName(file.getName())); + } + + public static String getLangByResourceName(String resourceName) { + String ext = FilenameUtils.getExtension(resourceName); + if (ext.equalsIgnoreCase("ttl")) return "TTL"; + //TODO: add other types + return null; + } + + public static Model readInto(File file, Model model, String lang) { + try (InputStream inputStream = FileHelper.openInputStream(file)) { + return readInto(inputStream, file.getAbsolutePath(), model, lang); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static Model readInto(InputStream inputStream, String streamName, Model model, String lang) { + try { + RDFReaderI reader = model.getReader(lang); + InternalRdfErrorHandler errorHandler = new InternalRdfErrorHandler(streamName); + reader.setErrorHandler(errorHandler); + reader.read(model, inputStream, null); + + Preconditions.checkState(errorHandler.isFailure(), errorHandler.getInfo()); + return model; + } + finally { + IOUtils.closeQuietly(inputStream); + } + } + + private static class InternalRdfErrorHandler implements RDFErrorHandler { + + private final String info; + private boolean failure; + + private InternalRdfErrorHandler(String loadedFile) { + info = "Load rdf file (" + loadedFile + ") problem."; + } + + public boolean isFailure() { + return failure; + } + + public String getInfo() { + return info; + } + + @Override + public void warning(Exception e) { + String message = e.getMessage(); + if (null != message && message.contains("ISO-639 does not define language:")) { + log.warn("{}: {}", info, message); + return; + } + log.warn(info, e); + } + + @Override + public void error(Exception e) { + failure = true; + log.error(info, e); + } + + @Override + public void fatalError(Exception e) { + failure = true; + log.error(info, e); + } + } +} + diff --git a/src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java b/src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java new file mode 100644 index 0000000..16a4809 --- /dev/null +++ b/src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java @@ -0,0 +1,16 @@ +package zone.cogni.sem.jena.template; + + +import org.apache.jena.rdf.model.RDFNode; + +import java.util.List; +import java.util.Map; + +public final class JenaResultSetHandlers { + + public static final JenaResultSetHandler>> listOfMapsResolver = JenaQueryUtils::convertToListOfMaps; + + private JenaResultSetHandlers() { + throw new AssertionError("Should not be initialized!"); + } +} From b31a121f7b98b84991eaeb501d671ce95702efc7 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 19 Jun 2024 11:58:13 +0200 Subject: [PATCH 03/58] refactor: simplification + removing buildtime dependency on Spring --- build.gradle.kts | 2 + .../asquare/cube/spel/NamedTemplate.java | 23 ---------- .../urigenerator/UriGeneratorCalculator.java | 12 +---- .../cube/urigenerator/UriGeneratorResult.java | 8 ---- .../jenamemory/InternalRdfStoreService.java | 46 ------------------- .../cogni/core/spring/ResourceHelper.java | 11 ----- .../zone/cogni/sem/jena/AutoCloseModels.java | 26 ----------- .../java/zone/cogni/sem/jena/JenaUtils.java | 20 -------- .../jena/template/JenaResultSetHandlers.java | 16 ------- .../asquare/cube/spel/SpelConfiguration.java | 0 10 files changed, 4 insertions(+), 160 deletions(-) delete mode 100644 src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java delete mode 100644 src/main/java/zone/cogni/sem/jena/AutoCloseModels.java delete mode 100644 src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java rename src/{main => test}/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java (100%) diff --git a/build.gradle.kts b/build.gradle.kts index 6d559b6..48f7d6c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -42,6 +42,8 @@ tasks.withType { dependencies { implementation("org.apache.jena:jena-arq:$jenaVersion") implementation("com.google.guava:guava:$guavaVersion") + implementation("org.springframework:spring-core:$springVersion") + implementation("org.springframework:spring-context:$springVersion") implementation("org.springframework:spring-expression:$springVersion") implementation("jakarta.annotation:jakarta.annotation-api:$jakartaAnnotationApiVersion") implementation("cz.cvut.kbss.jsonld:jb4jsonld-jackson:$jb4jsonldJacksonVersion") diff --git a/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java b/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java deleted file mode 100644 index a341aad..0000000 --- a/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java +++ /dev/null @@ -1,23 +0,0 @@ -package zone.cogni.asquare.cube.spel; - -public class NamedTemplate { - - private final String template; - private final String name; - - protected NamedTemplate(String template, String name) { - this.template = template; - this.name = name; - } - - /** - * @return copy of template part, not result part - */ - public NamedTemplate copy() { - return new NamedTemplate(template, name); - } - - public String getTemplate() { - return template; - } -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java index 497f01f..772b38d 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -16,7 +16,7 @@ import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; import zone.cogni.asquare.triplestore.RdfStoreService; import zone.cogni.asquare.triplestore.jenamemory.InternalRdfStoreService; -import zone.cogni.sem.jena.template.JenaResultSetHandlers; +import zone.cogni.sem.jena.template.JenaQueryUtils; import jakarta.annotation.Nonnull; import java.io.StringWriter; @@ -48,14 +48,6 @@ private void initPreparedStatements() { preparedStatements.put("exists-uri", QueryFactory.create("ask { { ?x ?p ?o } union { ?s ?p ?x } } ")); } - public String createTemporaryUri() { - return newUriPrefix + "/" + UUID.randomUUID(); - } - - public boolean isNewUri(@Nonnull String uri) { - return uri.startsWith(newUriPrefix); - } - public Model convert(Model model, Map context) { RdfStoreService rdfStore = getRdfStore(model); List results = getGeneratorResults(rdfStore); @@ -242,7 +234,7 @@ private void nonNullCheck(Map nodeMap, RDFNode node) { private List> queryForListOfMaps(RdfStoreService rdfStore, String variableQuery) { try { - return rdfStore.executeSelectQuery(variableQuery, JenaResultSetHandlers.listOfMapsResolver); + return rdfStore.executeSelectQuery(variableQuery, JenaQueryUtils::convertToListOfMaps); } catch (RuntimeException e) { throw new RuntimeException("Query failed: \n" + variableQuery, e); diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java index 789fa05..a91846e 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java @@ -32,14 +32,6 @@ public void setUris(Set uris) { this.uris = uris; } - public Map getReplacements() { - return replacements; - } - - public void setReplacements(Map replacements) { - this.replacements = replacements; - } - public boolean alreadyReplaced(String oldUri) { return replacements.containsKey(oldUri); } diff --git a/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java b/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java index 3954a0b..6f3531e 100644 --- a/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java +++ b/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java @@ -1,22 +1,13 @@ package zone.cogni.asquare.triplestore.jenamemory; -import org.apache.commons.lang3.StringUtils; import org.apache.jena.query.*; import org.apache.jena.rdf.model.Model; import org.apache.jena.shared.Lock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.core.io.support.ResourcePatternResolver; import zone.cogni.asquare.triplestore.RdfStoreService; -import zone.cogni.core.spring.ResourceHelper; -import zone.cogni.sem.jena.JenaUtils; import zone.cogni.sem.jena.template.JenaResultSetHandler; -import javax.annotation.PostConstruct; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; import java.util.function.Supplier; public class InternalRdfStoreService implements RdfStoreService { @@ -25,42 +16,10 @@ public class InternalRdfStoreService implements RdfStoreService { private final Model model; - private ResourcePatternResolver resourcePatternResolver; - private String preLoadLocations; - private String savePath; - - private File storeFile; - private File tempStoreFile; - public InternalRdfStoreService(Model model) { this.model = model; } - @PostConstruct - private void init() { - if (StringUtils.isNotBlank(savePath)) { - storeFile = new File(savePath, "store.rdf"); - tempStoreFile = new File(savePath, "temp-store.rdf"); - storeFile.getParentFile().mkdirs(); - - if (storeFile.isFile()) JenaUtils.readInto(storeFile, model); - } - - if (resourcePatternResolver == null || StringUtils.isBlank(preLoadLocations)) return; - - Arrays.stream(StringUtils.split(preLoadLocations, ',')).forEach(location -> { - log.info("Loading RDF file {}.", location); - Arrays.stream(ResourceHelper.getResources(resourcePatternResolver, location)).forEach(resource -> { - try (InputStream inputStream = resource.getInputStream()) { - model.read(inputStream, null, JenaUtils.getLangByResourceName(location)); - } - catch (IOException e) { - throw new RuntimeException(e); - } - }); - }); - } - @Override public R executeSelectQuery(Query query, QuerySolutionMap bindings, JenaResultSetHandler resultSetHandler, String context) { return executeInLock(Lock.READ, () -> { @@ -116,9 +75,4 @@ private T executeInLock(boolean lock, Supplier executeInLock) { model.leaveCriticalSection(); } } - - public Model getModel() { - return model; - } - } diff --git a/src/main/java/zone/cogni/core/spring/ResourceHelper.java b/src/main/java/zone/cogni/core/spring/ResourceHelper.java index d194871..114b067 100644 --- a/src/main/java/zone/cogni/core/spring/ResourceHelper.java +++ b/src/main/java/zone/cogni/core/spring/ResourceHelper.java @@ -2,23 +2,12 @@ import org.apache.commons.io.IOUtils; import org.springframework.core.io.InputStreamSource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.ResourcePatternResolver; import java.io.IOException; import java.io.InputStream; public class ResourceHelper { - public static Resource[] getResources(ResourcePatternResolver applicationContext, String locationPattern) { - try { - return applicationContext.getResources(locationPattern); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - public static String toString(InputStreamSource resource) { return toString(resource, "UTF-8"); } diff --git a/src/main/java/zone/cogni/sem/jena/AutoCloseModels.java b/src/main/java/zone/cogni/sem/jena/AutoCloseModels.java deleted file mode 100644 index f9c982d..0000000 --- a/src/main/java/zone/cogni/sem/jena/AutoCloseModels.java +++ /dev/null @@ -1,26 +0,0 @@ -package zone.cogni.sem.jena; - -import org.apache.jena.rdf.model.Model; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; - -public class AutoCloseModels implements AutoCloseable { - - private final Collection models = new ArrayList<>(); - - public AutoCloseModels(Model... models) { - this.models.addAll(Arrays.asList(models)); - } - - public Model add(Model model) { - models.add(model); - return model; - } - - @Override - public void close() { - JenaUtils.closeQuietly(models); - } -} diff --git a/src/main/java/zone/cogni/sem/jena/JenaUtils.java b/src/main/java/zone/cogni/sem/jena/JenaUtils.java index 415be2f..9dcc793 100644 --- a/src/main/java/zone/cogni/sem/jena/JenaUtils.java +++ b/src/main/java/zone/cogni/sem/jena/JenaUtils.java @@ -153,26 +153,6 @@ public static void closeQuietly(Model... models) { }); } - public static void closeQuietly(Iterable models) { - for (Model model : models) { - if (model == null) { - continue; - } - - if (model.isClosed()) { - log.warn("Closing an already closed model."); - continue; - } - - try { - model.close(); - } - catch (Exception e) { - log.warn("Closing model failed.", e); - } - } - } - public static Model readInto(File file, Model model) { return readInto(file, model, getLangByResourceName(file.getName())); } diff --git a/src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java b/src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java deleted file mode 100644 index 16a4809..0000000 --- a/src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java +++ /dev/null @@ -1,16 +0,0 @@ -package zone.cogni.sem.jena.template; - - -import org.apache.jena.rdf.model.RDFNode; - -import java.util.List; -import java.util.Map; - -public final class JenaResultSetHandlers { - - public static final JenaResultSetHandler>> listOfMapsResolver = JenaQueryUtils::convertToListOfMaps; - - private JenaResultSetHandlers() { - throw new AssertionError("Should not be initialized!"); - } -} diff --git a/src/main/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java b/src/test/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java similarity index 100% rename from src/main/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java rename to src/test/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java From 1fbe2cc91287519b16fa303441ed0576c39c1c2b Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 19 Jun 2024 14:59:04 +0200 Subject: [PATCH 04/58] refactor: simplification of the code --- .../urigenerator/UriGeneratorCalculator.java | 30 ++-- .../urigenerator/json/UriGeneratorRoot.java | 8 +- .../asquare/triplestore/RdfStoreService.java | 43 ----- .../jenamemory/InternalRdfStoreService.java | 78 --------- .../cogni/core/spring/ResourceHelper.java | 35 ---- .../java/zone/cogni/core/util/FileHelper.java | 45 ----- .../java/zone/cogni/core/util/IOHelper.java | 24 --- .../java/zone/cogni/sem/jena/JenaUtils.java | 159 ++++-------------- 8 files changed, 46 insertions(+), 376 deletions(-) delete mode 100644 src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java delete mode 100644 src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java delete mode 100644 src/main/java/zone/cogni/core/spring/ResourceHelper.java delete mode 100644 src/main/java/zone/cogni/core/util/FileHelper.java delete mode 100644 src/main/java/zone/cogni/core/util/IOHelper.java diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java index 772b38d..b4ce972 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -14,8 +14,8 @@ import zone.cogni.asquare.cube.spel.TemplateService; import zone.cogni.asquare.cube.urigenerator.json.UriGenerator; import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; -import zone.cogni.asquare.triplestore.RdfStoreService; -import zone.cogni.asquare.triplestore.jenamemory.InternalRdfStoreService; +import zone.cogni.asquare.triplestore.RdfStoreServiceAPI; +import zone.cogni.asquare.triplestore.InternalRdfStoreService; import zone.cogni.sem.jena.template.JenaQueryUtils; import jakarta.annotation.Nonnull; @@ -49,7 +49,7 @@ private void initPreparedStatements() { } public Model convert(Model model, Map context) { - RdfStoreService rdfStore = getRdfStore(model); + RdfStoreServiceAPI rdfStore = getRdfStore(model); List results = getGeneratorResults(rdfStore); int replaceCount = inputValidations(model, results); @@ -61,7 +61,7 @@ public Model convert(Model model, Map context) { } @Nonnull - private List getGeneratorResults(RdfStoreService rdfStore) { + private List getGeneratorResults(RdfStoreServiceAPI rdfStore) { return uriGeneratorRoot.getGenerators() .stream() .map(generator -> getUriGeneratorResult(rdfStore, generator)) @@ -69,7 +69,7 @@ private List getGeneratorResults(RdfStoreService rdfStore) { } @Nonnull - private UriGeneratorResult getUriGeneratorResult(RdfStoreService rdfStore, UriGenerator generator) { + private UriGeneratorResult getUriGeneratorResult(RdfStoreServiceAPI rdfStore, UriGenerator generator) { UriGeneratorResult uriGeneratorResult = new UriGeneratorResult(); uriGeneratorResult.setGenerator(generator); uriGeneratorResult.setUris(getNewSelectorUris(rdfStore, generator)); @@ -106,7 +106,7 @@ private int inputValidations(Model model, List results) { } private void processReplacements(Model model, - RdfStoreService rdfStore, + RdfStoreServiceAPI rdfStore, int replaceCount, Map context, List results) { @@ -126,7 +126,7 @@ private void processReplacements(Model model, } private int calculateReplacementUrisLoop(Model model, - RdfStoreService rdfStore, + RdfStoreServiceAPI rdfStore, Map context, List results) { AtomicInteger count = new AtomicInteger(); @@ -147,7 +147,7 @@ private int calculateReplacementUrisLoop(Model model, return count.get(); } - private Optional calculateNewUri(RdfStoreService rdfStore, + private Optional calculateNewUri(RdfStoreServiceAPI rdfStore, Map context, UriGeneratorResult result, String oldUri) { @@ -185,7 +185,7 @@ private Optional calculateNewUri(RdfStoreService rdfStore, return Optional.of(newUri); } - private void traceModel(RdfStoreService rdfStore) { + private void traceModel(RdfStoreServiceAPI rdfStore) { if (!log.isTraceEnabled()) return; Model trace = rdfStore.executeConstructQuery("construct {?s ?p ?o} where {?s ?p ?o}"); @@ -194,7 +194,7 @@ private void traceModel(RdfStoreService rdfStore) { log.trace("model: {}", out); } - private boolean existsInModel(RdfStoreService rdfStore, String newUri) { + private boolean existsInModel(RdfStoreServiceAPI rdfStore, String newUri) { QuerySolutionMap querySolution = new QuerySolutionMap(); querySolution.add("x", ResourceFactory.createResource(newUri)); @@ -206,7 +206,7 @@ private boolean existsInModel(RdfStoreService rdfStore, String newUri) { * else a map of variables to be used in uri template! */ private Optional> getQueryMap(Supplier context, - RdfStoreService rdfStore, + RdfStoreServiceAPI rdfStore, String variableQuery) { List> rows = queryForListOfMaps(rdfStore, variableQuery); if (rows.size() != 1) @@ -232,7 +232,7 @@ private void nonNullCheck(Map nodeMap, RDFNode node) { if (node == null) throw new RuntimeException("variableSelector result has some null values: " + nodeMap); } - private List> queryForListOfMaps(RdfStoreService rdfStore, String variableQuery) { + private List> queryForListOfMaps(RdfStoreServiceAPI rdfStore, String variableQuery) { try { return rdfStore.executeSelectQuery(variableQuery, JenaQueryUtils::convertToListOfMaps); } @@ -241,7 +241,7 @@ private List> queryForListOfMaps(RdfStoreService rdfStore, } } - private Set getNewSelectorUris(RdfStoreService rdfStore, UriGenerator generator) { + private Set getNewSelectorUris(RdfStoreServiceAPI rdfStore, UriGenerator generator) { String query = uriGeneratorRoot.getPrefixQuery() + generator.getFullUriSelector(); List uris = getUris(rdfStore, query); return uris.stream() @@ -249,7 +249,7 @@ private Set getNewSelectorUris(RdfStoreService rdfStore, UriGenerator ge .collect(Collectors.toSet()); } - private List getUris(RdfStoreService rdfStore, String query) { + private List getUris(RdfStoreServiceAPI rdfStore, String query) { try { return rdfStore.executeSelectQuery(query, UriGeneratorCalculator::convertToList); } @@ -268,7 +268,7 @@ private static List convertToList(ResultSet resultSet) { return result; } - private RdfStoreService getRdfStore(Model model) { + private RdfStoreServiceAPI getRdfStore(Model model) { return new InternalRdfStoreService(model); } diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java index f45c84d..395ab9d 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java @@ -16,10 +16,7 @@ public class UriGeneratorRoot { public static UriGeneratorRoot load(InputStreamSource resource) { try { ObjectMapper mapper = Json5Light.getJson5Mapper(); - UriGeneratorRoot result = mapper.readValue(resource.getInputStream(), UriGeneratorRoot.class); - -// result.validate(); - return result; + return mapper.readValue(resource.getInputStream(), UriGeneratorRoot.class); } catch (IOException e) { String extra = getPath(resource) != null ? " Path " + getPath(resource) : ""; @@ -29,8 +26,7 @@ public static UriGeneratorRoot load(InputStreamSource resource) { private static String getPath(InputStreamSource resource) { try { - if (resource instanceof Resource) { - Resource r = (Resource) resource; + if (resource instanceof Resource r) { return r.getFile().getPath(); } } diff --git a/src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java b/src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java deleted file mode 100644 index b3416db..0000000 --- a/src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java +++ /dev/null @@ -1,43 +0,0 @@ -package zone.cogni.asquare.triplestore; - - -import org.apache.jena.query.Query; -import org.apache.jena.query.QueryFactory; -import org.apache.jena.query.QuerySolutionMap; -import org.apache.jena.query.Syntax; -import org.apache.jena.rdf.model.Model; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import zone.cogni.sem.jena.template.JenaResultSetHandler; - -import java.io.Closeable; - -public interface RdfStoreService extends Closeable { - - Logger log = LoggerFactory.getLogger(RdfStoreService.class); - - @Override - default void close() { - log.info("Closing RdfStoreService ({}) : {}", getClass().getName(), this); - } - - R executeSelectQuery(Query query, QuerySolutionMap bindings, JenaResultSetHandler resultSetHandler, String context); - - default R executeSelectQuery(String query, JenaResultSetHandler resultSetHandler, String context) { - Query parsedQuery = QueryFactory.create(query, Syntax.syntaxARQ); - return executeSelectQuery(parsedQuery, new QuerySolutionMap(), resultSetHandler, context); - } - - default R executeSelectQuery(String query, JenaResultSetHandler resultSetHandler) { - return executeSelectQuery(query, resultSetHandler, null); - } - - boolean executeAskQuery(Query query, QuerySolutionMap bindings); - - Model executeConstructQuery(Query query, QuerySolutionMap bindings); - - default Model executeConstructQuery(String query) { - Query parsedQuery = QueryFactory.create(query, Syntax.syntaxARQ); - return executeConstructQuery(parsedQuery, new QuerySolutionMap()); - } -} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java b/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java deleted file mode 100644 index 6f3531e..0000000 --- a/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java +++ /dev/null @@ -1,78 +0,0 @@ -package zone.cogni.asquare.triplestore.jenamemory; - -import org.apache.jena.query.*; -import org.apache.jena.rdf.model.Model; -import org.apache.jena.shared.Lock; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import zone.cogni.asquare.triplestore.RdfStoreService; -import zone.cogni.sem.jena.template.JenaResultSetHandler; - -import java.util.function.Supplier; - -public class InternalRdfStoreService implements RdfStoreService { - - private static final Logger log = LoggerFactory.getLogger(InternalRdfStoreService.class); - - private final Model model; - - public InternalRdfStoreService(Model model) { - this.model = model; - } - - @Override - public R executeSelectQuery(Query query, QuerySolutionMap bindings, JenaResultSetHandler resultSetHandler, String context) { - return executeInLock(Lock.READ, () -> { - if (log.isTraceEnabled()) log.trace("Select {} - {} \n{}", - context == null ? "" : "--- " + context + " --- ", - bindings, - query); - - try (QueryExecution queryExecution = QueryExecutionFactory.create(query, model, bindings)) { - ResultSet resultSet = queryExecution.execSelect(); - return resultSetHandler.handle(resultSet); - } - catch (RuntimeException e) { - log.error("Query failed: {}", query); - throw e; - } - }); - } - - @Override - public boolean executeAskQuery(Query query, QuerySolutionMap bindings) { - return executeInLock(Lock.READ, () -> { - try (QueryExecution queryExecution = QueryExecutionFactory.create(query, model, bindings)) { - return queryExecution.execAsk(); - } - catch (RuntimeException e) { - log.error("Query failed: {}", query); - throw e; - } - }); - } - - @Override - public Model executeConstructQuery(Query query, QuerySolutionMap bindings) { - return executeInLock(Lock.READ, () -> { - try (QueryExecution queryExecution = QueryExecutionFactory.create(query, model, bindings)) { - if (log.isTraceEnabled()) log.trace("Running construct query: \n{}", query); - return queryExecution.execConstruct(); - } - catch (RuntimeException e) { - log.error("Query failed: {}", query); - throw e; - } - }); - } - - private T executeInLock(boolean lock, Supplier executeInLock) { - model.enterCriticalSection(lock); - try { - return executeInLock.get(); - } - finally { - model.leaveCriticalSection(); - } - } -} diff --git a/src/main/java/zone/cogni/core/spring/ResourceHelper.java b/src/main/java/zone/cogni/core/spring/ResourceHelper.java deleted file mode 100644 index 114b067..0000000 --- a/src/main/java/zone/cogni/core/spring/ResourceHelper.java +++ /dev/null @@ -1,35 +0,0 @@ -package zone.cogni.core.spring; - -import org.apache.commons.io.IOUtils; -import org.springframework.core.io.InputStreamSource; - -import java.io.IOException; -import java.io.InputStream; - -public class ResourceHelper { - - public static String toString(InputStreamSource resource) { - return toString(resource, "UTF-8"); - } - - public static String toString(InputStreamSource resource, String encoding) { - try (InputStream inputStream = resource.getInputStream()) { - return IOUtils.toString(inputStream, encoding); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - public static InputStream getInputStream(T resource) { - try { - return resource.getInputStream(); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - private ResourceHelper() { - } -} diff --git a/src/main/java/zone/cogni/core/util/FileHelper.java b/src/main/java/zone/cogni/core/util/FileHelper.java deleted file mode 100644 index cef687d..0000000 --- a/src/main/java/zone/cogni/core/util/FileHelper.java +++ /dev/null @@ -1,45 +0,0 @@ -package zone.cogni.core.util; - -import com.google.common.io.Files; -import org.apache.commons.io.FileUtils; - -import javax.annotation.Nonnull; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; - -public class FileHelper { - private FileHelper() { - } - - public static FileInputStream openInputStream(File file) { - try { - return new FileInputStream(file); - } - catch (FileNotFoundException e) { - throw new RuntimeException(e); - } - } - - public static FileOutputStream openOutputStream(@Nonnull File file) { - try { - Files.createParentDirs(file); - return FileUtils.openOutputStream(file); - } - catch (IOException e) { - throw new RuntimeException( "Failed to open outputstream to " + file, e); - } - } - - @Deprecated - public static void writeStringToFile(File file, String data) { - try { - FileUtils.writeStringToFile(file, data); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } -} diff --git a/src/main/java/zone/cogni/core/util/IOHelper.java b/src/main/java/zone/cogni/core/util/IOHelper.java deleted file mode 100644 index ad14e59..0000000 --- a/src/main/java/zone/cogni/core/util/IOHelper.java +++ /dev/null @@ -1,24 +0,0 @@ -package zone.cogni.core.util; - - -import java.io.Closeable; -import java.io.Flushable; -import java.io.IOException; - -public class IOHelper { - public static void flushAndClose(X closeFlusher) { - if (closeFlusher == null) return; - - try { - closeFlusher.flush(); - } - catch (IOException ignore) { - } - - try { - closeFlusher.close(); - } - catch (IOException ignore) { - } - } -} diff --git a/src/main/java/zone/cogni/sem/jena/JenaUtils.java b/src/main/java/zone/cogni/sem/jena/JenaUtils.java index 9dcc793..f7018c0 100644 --- a/src/main/java/zone/cogni/sem/jena/JenaUtils.java +++ b/src/main/java/zone/cogni/sem/jena/JenaUtils.java @@ -1,30 +1,18 @@ package zone.cogni.sem.jena; import com.google.common.base.Preconditions; -import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.jena.rdf.model.AnonId; -import org.apache.jena.rdf.model.Literal; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.RDFErrorHandler; -import org.apache.jena.rdf.model.RDFNode; import org.apache.jena.rdf.model.RDFReaderI; -import org.apache.jena.rdf.model.RDFVisitor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; -import zone.cogni.core.spring.ResourceHelper; -import zone.cogni.core.util.FileHelper; -import zone.cogni.core.util.IOHelper; -import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -47,29 +35,47 @@ private JenaUtils() { } public static Model read(Resource... resources) { - return read(Arrays.asList(resources)); - } - - public static Model read(Iterable resources) { - return read(resources, null); - } - - public static Model read(Iterable resources, Map readerProperties) { Model model = ModelFactory.createDefaultModel(); for (Resource resource : resources) { InputStream inputstream = null; try { - inputstream = ResourceHelper.getInputStream(resource); + InputStream result; + try { + result = resource.getInputStream(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + inputstream = result; InternalRdfErrorHandler errorHandler = new InternalRdfErrorHandler(resource.getDescription()); - RDFReaderI rdfReader = getReader(model, resource, errorHandler, readerProperties); + String extension = StringUtils.lowerCase(StringUtils.substringAfterLast(resource.getFilename(), ".")); + + // when return value is null, fall back to RDF/XML + String language = extensionToLanguageMap.getOrDefault(extension, null); + RDFReaderI rdfReader1; + try { + rdfReader1 = model.getReader(language); + } + catch (IllegalStateException ignored) { + rdfReader1 = model.getReader(); + } + rdfReader1.setErrorHandler(errorHandler); + RDFReaderI rdfReader = rdfReader1; rdfReader.read(model, inputstream, null); Preconditions.checkState(!errorHandler.isFailure(), errorHandler.getInfo()); } catch (RuntimeException e) { - closeQuietly(model); + Arrays.stream(new Model[]{model}).filter(Objects::nonNull).filter(model1 -> !model1.isClosed()).forEach(model1 -> { + try { + model1.close(); + } + catch (Exception e1) { + log.warn("Closing model failed.", e1); + } + }); throw e; } @@ -81,113 +87,6 @@ public static Model read(Iterable resources, Map reade return model; } - private static RDFReaderI getReader(Model model, Resource resource, RDFErrorHandler rdfErrorHandler, Map readerProperties) { - return getReader(model, rdfErrorHandler, readerProperties, getRdfSyntax(resource)); - } - - private static RDFReaderI getReader(Model model, RDFErrorHandler rdfErrorHandler, Map readerProperties, String language) { - RDFReaderI rdfReader = getReaderByRdfSyntax(model, language); - rdfReader.setErrorHandler(rdfErrorHandler); - if (readerProperties == null) return rdfReader; - - for (String propertyName : readerProperties.keySet()) { - rdfReader.setProperty(propertyName, readerProperties.get(propertyName)); - } - return rdfReader; - } - - private static RDFReaderI getReaderByRdfSyntax(Model model, String language) { - try { - return model.getReader(language); - } - catch (IllegalStateException ignored) { - return model.getReader(); - } - } - - private static String getRdfSyntax(org.springframework.core.io.Resource resource) { - String extension = StringUtils.lowerCase(StringUtils.substringAfterLast(resource.getFilename(), ".")); - - // when return value is null, fall back to RDF/XML - return extensionToLanguageMap.getOrDefault(extension, null); - } - - public static void write(Model model, File file) { - write(model, FileHelper.openOutputStream(file)); - } - - public static void write(Model model, OutputStream out) { - try { - model.write(out); - } - finally { - IOHelper.flushAndClose(out); - } - } - - public static String toString(Model model) { - return toString(model, "RDF/XML"); - } - - public static String toString(Model model, String language) { - try { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - model.write(out, language); - - return out.toString("UTF-8"); - } - catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - - - public static void closeQuietly(Model... models) { - Arrays.stream(models).filter(Objects::nonNull).filter(model -> !model.isClosed()).forEach(model -> { - try { - model.close(); - } - catch (Exception e) { - log.warn("Closing model failed.", e); - } - }); - } - - public static Model readInto(File file, Model model) { - return readInto(file, model, getLangByResourceName(file.getName())); - } - - public static String getLangByResourceName(String resourceName) { - String ext = FilenameUtils.getExtension(resourceName); - if (ext.equalsIgnoreCase("ttl")) return "TTL"; - //TODO: add other types - return null; - } - - public static Model readInto(File file, Model model, String lang) { - try (InputStream inputStream = FileHelper.openInputStream(file)) { - return readInto(inputStream, file.getAbsolutePath(), model, lang); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - public static Model readInto(InputStream inputStream, String streamName, Model model, String lang) { - try { - RDFReaderI reader = model.getReader(lang); - InternalRdfErrorHandler errorHandler = new InternalRdfErrorHandler(streamName); - reader.setErrorHandler(errorHandler); - reader.read(model, inputStream, null); - - Preconditions.checkState(errorHandler.isFailure(), errorHandler.getInfo()); - return model; - } - finally { - IOUtils.closeQuietly(inputStream); - } - } - private static class InternalRdfErrorHandler implements RDFErrorHandler { private final String info; From 2586b2d1cf27d98aae89cc5cebda0653bfc4c685 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 19 Jun 2024 16:31:40 +0200 Subject: [PATCH 05/58] refactor: cleanup, removing Spring from tests, JDK 11 compatibility --- .../urigenerator/UriGeneratorCalculator.java | 92 ++++++------- .../cube/urigenerator/UriGeneratorResult.java | 2 +- .../cube/urigenerator/UriReplacement.java | 29 ---- .../urigenerator/json/UriGeneratorRoot.java | 40 +++--- .../java/zone/cogni/sem/jena/JenaUtils.java | 130 ------------------ .../asquare/cube/spel/SpelConfiguration.java | 14 -- .../UriGeneratorCalculatorTest.java | 35 +++-- .../UriGeneratorCalculatorTestConfig.java | 26 ---- 8 files changed, 84 insertions(+), 284 deletions(-) delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java delete mode 100644 src/main/java/zone/cogni/sem/jena/JenaUtils.java delete mode 100644 src/test/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java delete mode 100644 src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java index b4ce972..1cb25c9 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -8,9 +8,9 @@ import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.RDFNode; import org.apache.jena.rdf.model.ResourceFactory; +import org.apache.jena.util.ResourceUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.core.io.Resource; import zone.cogni.asquare.cube.spel.TemplateService; import zone.cogni.asquare.cube.urigenerator.json.UriGenerator; import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; @@ -19,7 +19,9 @@ import zone.cogni.sem.jena.template.JenaQueryUtils; import jakarta.annotation.Nonnull; + import java.io.StringWriter; +import java.net.URL; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; @@ -34,9 +36,9 @@ public class UriGeneratorCalculator { private final Map preparedStatements = new HashMap<>(); public UriGeneratorCalculator( - String newUriPrefix, - TemplateService templateService, - Resource uriGeneratorRootResource + String newUriPrefix, + TemplateService templateService, + URL uriGeneratorRootResource ) { this.newUriPrefix = newUriPrefix; this.templateService = templateService; @@ -63,9 +65,9 @@ public Model convert(Model model, Map context) { @Nonnull private List getGeneratorResults(RdfStoreServiceAPI rdfStore) { return uriGeneratorRoot.getGenerators() - .stream() - .map(generator -> getUriGeneratorResult(rdfStore, generator)) - .collect(Collectors.toList()); + .stream() + .map(generator -> getUriGeneratorResult(rdfStore, generator)) + .collect(Collectors.toList()); } @Nonnull @@ -84,9 +86,9 @@ private int inputValidations(Model model, List results) { Set selectedUris = new HashSet<>(); Set duplicates = results.stream() - .flatMap(result -> result.getUris().stream()) - .filter(uri -> !selectedUris.add(uri)) - .collect(Collectors.toSet()); + .flatMap(result -> result.getUris().stream()) + .filter(uri -> !selectedUris.add(uri)) + .collect(Collectors.toSet()); if (!duplicates.isEmpty()) log.error("some uris matched multiple selectors: {}", duplicates); @@ -131,18 +133,16 @@ private int calculateReplacementUrisLoop(Model model, List results) { AtomicInteger count = new AtomicInteger(); - results.forEach(result -> { - result.getUris().forEach(uri -> { - if (result.alreadyReplaced(uri)) return; + results.forEach(result -> result.getUris().forEach(uri -> { + if (result.alreadyReplaced(uri)) return; - Optional possibleNewUri = calculateNewUri(rdfStore, context, result, uri); - if (possibleNewUri.isPresent()) { - count.addAndGet(1); - result.addReplacement(uri, possibleNewUri.get()); - UriReplacement.replace(model, uri, possibleNewUri.get()); - } - }); - }); + Optional possibleNewUri = calculateNewUri(rdfStore, context, result, uri); + if (possibleNewUri.isPresent()) { + count.addAndGet(1); + result.addReplacement(uri, possibleNewUri.get()); + ResourceUtils.renameResource(model.getResource(uri), possibleNewUri.get()); + } + })); return count.get(); } @@ -168,7 +168,7 @@ private Optional calculateNewUri(RdfStoreServiceAPI rdfStore, Optional> variableMap = getQueryMap(contextSupplier, rdfStore, variableQuery); // if one of template variables is still a new URI we should skip calculation for now - if (!variableMap.isPresent()) return Optional.empty(); + if (variableMap.isEmpty()) return Optional.empty(); Map map = variableMap.get(); if (log.isTraceEnabled()) log.trace("query result: {}", map); @@ -214,16 +214,14 @@ private Optional> getQueryMap(Supplier context, Map nodeMap = rows.get(0); boolean isBadMatch = nodeMap.values() - .stream() - .peek(node -> nonNullCheck(nodeMap, node)) - .anyMatch(node -> node.isURIResource() - && node.asResource().getURI().startsWith(newUriPrefix)); + .stream() + .peek(node -> nonNullCheck(nodeMap, node)) + .anyMatch(node -> node.isURIResource() + && node.asResource().getURI().startsWith(newUriPrefix)); if (isBadMatch) return Optional.empty(); Map result = new HashMap<>(); - nodeMap.forEach((k, v) -> { - result.put(k, (v.isResource() ? v.asResource().getURI() : v.asLiteral().getString())); - }); + nodeMap.forEach((k, v) -> result.put(k, (v.isResource() ? v.asResource().getURI() : v.asLiteral().getString()))); return Optional.of(result); } @@ -235,8 +233,7 @@ private void nonNullCheck(Map nodeMap, RDFNode node) { private List> queryForListOfMaps(RdfStoreServiceAPI rdfStore, String variableQuery) { try { return rdfStore.executeSelectQuery(variableQuery, JenaQueryUtils::convertToListOfMaps); - } - catch (RuntimeException e) { + } catch (RuntimeException e) { throw new RuntimeException("Query failed: \n" + variableQuery, e); } } @@ -245,15 +242,14 @@ private Set getNewSelectorUris(RdfStoreServiceAPI rdfStore, UriGenerator String query = uriGeneratorRoot.getPrefixQuery() + generator.getFullUriSelector(); List uris = getUris(rdfStore, query); return uris.stream() - .filter(uri -> uri.startsWith(newUriPrefix)) - .collect(Collectors.toSet()); + .filter(uri -> uri.startsWith(newUriPrefix)) + .collect(Collectors.toSet()); } private List getUris(RdfStoreServiceAPI rdfStore, String query) { try { return rdfStore.executeSelectQuery(query, UriGeneratorCalculator::convertToList); - } - catch (RuntimeException e) { + } catch (RuntimeException e) { throw new RuntimeException("problem with query: \n" + query, e); } } @@ -261,9 +257,9 @@ private List getUris(RdfStoreServiceAPI rdfStore, String query) { private static List convertToList(ResultSet resultSet) { List result = new ArrayList<>(); - resultSet.forEachRemaining(querySolution -> { - result.add(querySolution.get("uri").asResource().getURI()); - }); + resultSet.forEachRemaining(querySolution -> + result.add(querySolution.get("uri").asResource().getURI()) + ); return result; } @@ -282,16 +278,16 @@ private void validate(Model model) { private Set getProblemUris(Model model) { Set problemUris = new HashSet<>(); model.listStatements() - .forEachRemaining(statement -> { - if (statement.getSubject().getURI().startsWith(newUriPrefix)) { - problemUris.add(statement.getSubject().getURI()); - } - - if (statement.getObject().isURIResource() - && statement.getObject().asResource().getURI().startsWith(newUriPrefix)) { - problemUris.add(statement.getObject().asResource().getURI()); - } - }); + .forEachRemaining(statement -> { + if (statement.getSubject().getURI().startsWith(newUriPrefix)) { + problemUris.add(statement.getSubject().getURI()); + } + + if (statement.getObject().isURIResource() + && statement.getObject().asResource().getURI().startsWith(newUriPrefix)) { + problemUris.add(statement.getObject().asResource().getURI()); + } + }); return problemUris; } diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java index a91846e..357bedd 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java @@ -11,7 +11,7 @@ public class UriGeneratorResult { private UriGenerator generator; private Set uris; - private Map replacements = new HashMap<>(); + private final Map replacements = new HashMap<>(); public UriGeneratorResult() { } diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java deleted file mode 100644 index 5d45f1b..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java +++ /dev/null @@ -1,29 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -import org.apache.jena.rdf.model.*; - -import java.util.List; - -public class UriReplacement { - - public static void replace(Model model, String original, String replacement) { - Resource originalResource = ResourceFactory.createResource(original); - Resource replacementResource = ResourceFactory.createResource(replacement); - - List leftStatements = model.listStatements(originalResource, null, (RDFNode) null).toList(); - model.remove(leftStatements); - - leftStatements.forEach(statement -> { - model.add(replacementResource, statement.getPredicate(), statement.getObject()); - }); - - - List rightStatements = model.listStatements(null, null, originalResource).toList(); - model.remove(rightStatements); - - rightStatements.forEach(statement -> { - model.add(statement.getSubject(), statement.getPredicate(), replacementResource); - }); - } - -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java index 395ab9d..5a6d400 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java @@ -2,38 +2,30 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang3.StringUtils; -import org.springframework.core.io.InputStreamSource; -import org.springframework.core.io.Resource; import zone.cogni.asquare.cube.json5.Json5Light; import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class UriGeneratorRoot { - public static UriGeneratorRoot load(InputStreamSource resource) { + public static UriGeneratorRoot load(URL resource) { try { ObjectMapper mapper = Json5Light.getJson5Mapper(); - return mapper.readValue(resource.getInputStream(), UriGeneratorRoot.class); - } - catch (IOException e) { - String extra = getPath(resource) != null ? " Path " + getPath(resource) : ""; - throw new RuntimeException("Unable to load uri generator configuration." + extra, e); - } - } - - private static String getPath(InputStreamSource resource) { - try { - if (resource instanceof Resource r) { - return r.getFile().getPath(); + return mapper.readValue(resource.openStream(), UriGeneratorRoot.class); + } catch (IOException e) { + String extra; + try { + extra = " URL " + resource.toURI(); + } catch (URISyntaxException ex) { + throw new RuntimeException(ex); } + throw new RuntimeException("Unable to load uri generator configuration." + extra, e); } - catch (IOException e) { - return null; - } - return null; } private Map prefixes; @@ -60,11 +52,11 @@ public void setGenerators(List generators) { public String getPrefixQuery() { return prefixes.entrySet() - .stream() - .map(e -> "PREFIX " - + StringUtils.rightPad(e.getKey() + ":", 8) + " <" + e.getValue() + ">\n") - .collect(Collectors.joining()) - + "\n"; + .stream() + .map(e -> "PREFIX " + + StringUtils.rightPad(e.getKey() + ":", 8) + " <" + e.getValue() + ">\n") + .collect(Collectors.joining()) + + "\n"; } } diff --git a/src/main/java/zone/cogni/sem/jena/JenaUtils.java b/src/main/java/zone/cogni/sem/jena/JenaUtils.java deleted file mode 100644 index f7018c0..0000000 --- a/src/main/java/zone/cogni/sem/jena/JenaUtils.java +++ /dev/null @@ -1,130 +0,0 @@ -package zone.cogni.sem.jena; - -import com.google.common.base.Preconditions; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.jena.rdf.model.Model; -import org.apache.jena.rdf.model.ModelFactory; -import org.apache.jena.rdf.model.RDFErrorHandler; -import org.apache.jena.rdf.model.RDFReaderI; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.Resource; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -@Deprecated -public class JenaUtils { - private static final Logger log = LoggerFactory.getLogger(JenaUtils.class); - private static final Map extensionToLanguageMap = Collections.synchronizedMap(new HashMap<>()); - - static { - extensionToLanguageMap.put("nt", "N-TRIPLE"); - extensionToLanguageMap.put("n3", "N3"); - extensionToLanguageMap.put("ttl", "TURTLE"); - extensionToLanguageMap.put("jsonld", "JSONLD"); - } - - private JenaUtils() { - } - - public static Model read(Resource... resources) { - Model model = ModelFactory.createDefaultModel(); - - for (Resource resource : resources) { - InputStream inputstream = null; - try { - InputStream result; - try { - result = resource.getInputStream(); - } - catch (IOException e) { - throw new RuntimeException(e); - } - inputstream = result; - InternalRdfErrorHandler errorHandler = new InternalRdfErrorHandler(resource.getDescription()); - - String extension = StringUtils.lowerCase(StringUtils.substringAfterLast(resource.getFilename(), ".")); - - // when return value is null, fall back to RDF/XML - String language = extensionToLanguageMap.getOrDefault(extension, null); - RDFReaderI rdfReader1; - try { - rdfReader1 = model.getReader(language); - } - catch (IllegalStateException ignored) { - rdfReader1 = model.getReader(); - } - rdfReader1.setErrorHandler(errorHandler); - RDFReaderI rdfReader = rdfReader1; - rdfReader.read(model, inputstream, null); - - Preconditions.checkState(!errorHandler.isFailure(), errorHandler.getInfo()); - } - catch (RuntimeException e) { - Arrays.stream(new Model[]{model}).filter(Objects::nonNull).filter(model1 -> !model1.isClosed()).forEach(model1 -> { - try { - model1.close(); - } - catch (Exception e1) { - log.warn("Closing model failed.", e1); - } - }); - - throw e; - } - finally { - IOUtils.closeQuietly(inputstream); - } - } - - return model; - } - - private static class InternalRdfErrorHandler implements RDFErrorHandler { - - private final String info; - private boolean failure; - - private InternalRdfErrorHandler(String loadedFile) { - info = "Load rdf file (" + loadedFile + ") problem."; - } - - public boolean isFailure() { - return failure; - } - - public String getInfo() { - return info; - } - - @Override - public void warning(Exception e) { - String message = e.getMessage(); - if (null != message && message.contains("ISO-639 does not define language:")) { - log.warn("{}: {}", info, message); - return; - } - log.warn(info, e); - } - - @Override - public void error(Exception e) { - failure = true; - log.error(info, e); - } - - @Override - public void fatalError(Exception e) { - failure = true; - log.error(info, e); - } - } -} - diff --git a/src/test/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java b/src/test/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java deleted file mode 100644 index 38ad49c..0000000 --- a/src/test/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java +++ /dev/null @@ -1,14 +0,0 @@ -package zone.cogni.asquare.cube.spel; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class SpelConfiguration { - - @Bean(name = "spelService") - public SpelService getSpelService() { - return new SpelService(); - } - -} diff --git a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java index 2ef91f5..78e45dc 100644 --- a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java +++ b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java @@ -2,29 +2,40 @@ import com.google.common.collect.ImmutableMap; import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.ResourceFactory; +import org.apache.jena.riot.RDFDataMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.core.io.ClassPathResource; -import zone.cogni.sem.jena.JenaUtils; +import zone.cogni.asquare.cube.spel.SpelService; -import static org.assertj.core.api.Assertions.assertThat; +import java.net.URL; -@SpringBootTest(classes = UriGeneratorCalculatorTestConfig.class) public class UriGeneratorCalculatorTest { - @Autowired - UriGeneratorCalculator uriCalculator; + UriGeneratorCalculator sut; + + @BeforeEach + public void init() { + final URL uriGeneratorsResource = getClass().getResource("/urigenerator/uri-generators.json5"); + sut = new UriGeneratorCalculator("http://resource", + new SpelService(), + uriGeneratorsResource); + } @Test public void test_uris_converted() { + final URL modelUrl = getClass().getResource("/urigenerator/model.ttl"); + assert modelUrl != null; + //given - Model model = JenaUtils.read(new ClassPathResource("urigenerator/model.ttl")); + final Model model = ModelFactory.createDefaultModel(); + RDFDataMgr.read(model, modelUrl.toString()); //when - Model converted = uriCalculator.convert(model, ImmutableMap.of("baseUri", "http://asquare.cogni.zone")); + final Model converted = sut.convert(model, ImmutableMap.of("baseUri", "http://asquare.cogni.zone")); //then - assertThat(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/5"))); - assertThat(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/2021/0005"))); + Assertions.assertTrue(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/5"))); + Assertions.assertTrue(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/2021/0005"))); } } diff --git a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java deleted file mode 100644 index ea38dab..0000000 --- a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java +++ /dev/null @@ -1,26 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import zone.cogni.asquare.cube.spel.SpelService; - -@Configuration -@Import(SpelService.class) -public class UriGeneratorCalculatorTestConfig { - - @Autowired - private SpelService spelService; - - @Bean - public UriGeneratorCalculator uriCalculator() { - Resource uriGeneratorsResource = new ClassPathResource("urigenerator/uri-generators.json5"); - return new UriGeneratorCalculator("http://resource", - spelService, - uriGeneratorsResource); - } -} - From 8c3d046373223c5d72a7cb77302b903eb3960753 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 19 Jun 2024 18:15:32 +0200 Subject: [PATCH 06/58] fix: cleanup, code quality checks (dependencycheck, pmd, jacoco) --- .../urigenerator/UriGeneratorCalculator.java | 116 ++++++++---------- 1 file changed, 52 insertions(+), 64 deletions(-) diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java index 1cb25c9..1d96671 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -29,6 +29,7 @@ public class UriGeneratorCalculator { private static final Logger log = LoggerFactory.getLogger(UriGeneratorCalculator.class); + public static final int EXPECTED_ROW_COUNT = 1; private final String newUriPrefix; private final TemplateService templateService; @@ -51,15 +52,19 @@ private void initPreparedStatements() { } public Model convert(Model model, Map context) { - RdfStoreServiceAPI rdfStore = getRdfStore(model); - List results = getGeneratorResults(rdfStore); + try { + final RdfStoreServiceAPI rdfStore = getRdfStore(model); + final List results = getGeneratorResults(rdfStore); - int replaceCount = inputValidations(model, results); - processReplacements(model, rdfStore, replaceCount, context, results); + int replaceCount = inputValidations(model, results); + processReplacements(model, rdfStore, replaceCount, context, results); - validate(model); + validate(model); - return model; + return model; + } catch(RuntimeException e) { + throw new RuntimeException("An error occurred during URI generation", e); + } } @Nonnull @@ -81,11 +86,11 @@ private UriGeneratorResult getUriGeneratorResult(RdfStoreServiceAPI rdfStore, Ur /** * @return number of uris to be replaces */ - private int inputValidations(Model model, List results) { - Set incomingUris = getProblemUris(model); + private int inputValidations(final Model model, final List results) { + final Set incomingUris = getProblemUris(model); - Set selectedUris = new HashSet<>(); - Set duplicates = results.stream() + final Set selectedUris = new HashSet<>(); + final Set duplicates = results.stream() .flatMap(result -> result.getUris().stream()) .filter(uri -> !selectedUris.add(uri)) .collect(Collectors.toSet()); @@ -93,25 +98,24 @@ private int inputValidations(Model model, List results) { if (!duplicates.isEmpty()) log.error("some uris matched multiple selectors: {}", duplicates); - int size = incomingUris.size(); + final int size = incomingUris.size(); if (size != selectedUris.size()) log.error("incoming uris and selected uris do not match up." + - "\n\t incoming: {}" + - "\n\t selected: {}", incomingUris, selectedUris); + "\n\t incoming: {}" + + "\n\t selected: {}", incomingUris, selectedUris); if (!duplicates.isEmpty() || size != selectedUris.size()) throw new RuntimeException("some validations failed when converting new uris, check logs for more info"); - log.info("(uri generator) replacing {} uris", size); return size; } - private void processReplacements(Model model, - RdfStoreServiceAPI rdfStore, + private void processReplacements(final Model model, + final RdfStoreServiceAPI rdfStore, int replaceCount, - Map context, - List results) { + final Map context, + final List results) { int loopCount = 0; while (true) { int count = calculateReplacementUrisLoop(model, rdfStore, context, results); @@ -127,16 +131,16 @@ private void processReplacements(Model model, } } - private int calculateReplacementUrisLoop(Model model, - RdfStoreServiceAPI rdfStore, - Map context, - List results) { - AtomicInteger count = new AtomicInteger(); + private int calculateReplacementUrisLoop(final Model model, + final RdfStoreServiceAPI rdfStore, + final Map context, + final List results) { + final AtomicInteger count = new AtomicInteger(); results.forEach(result -> result.getUris().forEach(uri -> { if (result.alreadyReplaced(uri)) return; - Optional possibleNewUri = calculateNewUri(rdfStore, context, result, uri); + final Optional possibleNewUri = calculateNewUri(rdfStore, context, result, uri); if (possibleNewUri.isPresent()) { count.addAndGet(1); result.addReplacement(uri, possibleNewUri.get()); @@ -147,37 +151,37 @@ private int calculateReplacementUrisLoop(Model model, return count.get(); } - private Optional calculateNewUri(RdfStoreServiceAPI rdfStore, - Map context, - UriGeneratorResult result, - String oldUri) { + private Optional calculateNewUri(final RdfStoreServiceAPI rdfStore, + final Map context, + final UriGeneratorResult result, + final String oldUri) { if (log.isTraceEnabled()) log.trace("calculate new uri for {}", oldUri); traceModel(rdfStore); - Map variables = new HashMap<>(context); + final Map variables = new HashMap<>(context); variables.put("uri", oldUri); // variable template can also NOT exist: then this step is skipped! - String variableSelector = result.getGenerator().getFullVariableSelector(); + final String variableSelector = result.getGenerator().getFullVariableSelector(); if (StringUtils.isNotBlank(variableSelector)) { - String variableTemplateQuery = uriGeneratorRoot.getPrefixQuery() + variableSelector; - String variableQuery = templateService.processTemplate(variableTemplateQuery, variables); + final String variableTemplateQuery = uriGeneratorRoot.getPrefixQuery() + variableSelector; + final String variableQuery = templateService.processTemplate(variableTemplateQuery, variables); if (log.isTraceEnabled()) log.trace("query: {}", variableQuery); - Supplier contextSupplier = () -> result.getGenerator().getId(); - Optional> variableMap = getQueryMap(contextSupplier, rdfStore, variableQuery); + final Supplier contextSupplier = () -> result.getGenerator().getId(); + final Optional> variableMap = getQueryMap(contextSupplier, rdfStore, variableQuery); // if one of template variables is still a new URI we should skip calculation for now if (variableMap.isEmpty()) return Optional.empty(); - Map map = variableMap.get(); + final Map map = variableMap.get(); if (log.isTraceEnabled()) log.trace("query result: {}", map); variables.putAll(map); } if (log.isTraceEnabled()) log.debug("variables: {}", variables); - String uriTemplate = result.getGenerator().getUriTemplate(); - String newUri = templateService.processTemplate(uriTemplate, variables); + final String uriTemplate = result.getGenerator().getUriTemplate(); + final String newUri = templateService.processTemplate(uriTemplate, variables); if (existsInModel(rdfStore, newUri)) throw new RuntimeException("uri overlap found for " + newUri); @@ -188,14 +192,14 @@ private Optional calculateNewUri(RdfStoreServiceAPI rdfStore, private void traceModel(RdfStoreServiceAPI rdfStore) { if (!log.isTraceEnabled()) return; - Model trace = rdfStore.executeConstructQuery("construct {?s ?p ?o} where {?s ?p ?o}"); - StringWriter out = new StringWriter(); + final Model trace = rdfStore.executeConstructQuery("construct {?s ?p ?o} where {?s ?p ?o}"); + final StringWriter out = new StringWriter(); trace.write(out, "ttl"); log.trace("model: {}", out); } private boolean existsInModel(RdfStoreServiceAPI rdfStore, String newUri) { - QuerySolutionMap querySolution = new QuerySolutionMap(); + final QuerySolutionMap querySolution = new QuerySolutionMap(); querySolution.add("x", ResourceFactory.createResource(newUri)); return rdfStore.executeAskQuery(preparedStatements.get("exists-uri"), querySolution); @@ -208,11 +212,11 @@ private boolean existsInModel(RdfStoreServiceAPI rdfStore, String newUri) { private Optional> getQueryMap(Supplier context, RdfStoreServiceAPI rdfStore, String variableQuery) { - List> rows = queryForListOfMaps(rdfStore, variableQuery); - if (rows.size() != 1) - throw new RuntimeException("[" + context.get() + "] expected 1 row, found " + rows); + final List> result1 = rdfStore.executeSelectQuery(variableQuery, JenaQueryUtils::convertToListOfMaps); + if (result1.size() != EXPECTED_ROW_COUNT) + throw new RuntimeException("[" + context.get() + "] expected 1 row, found " + result1); - Map nodeMap = rows.get(0); + final Map nodeMap = result1.get(0); boolean isBadMatch = nodeMap.values() .stream() .peek(node -> nonNullCheck(nodeMap, node)) @@ -220,7 +224,7 @@ private Optional> getQueryMap(Supplier context, && node.asResource().getURI().startsWith(newUriPrefix)); if (isBadMatch) return Optional.empty(); - Map result = new HashMap<>(); + final Map result = new HashMap<>(); nodeMap.forEach((k, v) -> result.put(k, (v.isResource() ? v.asResource().getURI() : v.asLiteral().getString()))); return Optional.of(result); @@ -230,30 +234,14 @@ private void nonNullCheck(Map nodeMap, RDFNode node) { if (node == null) throw new RuntimeException("variableSelector result has some null values: " + nodeMap); } - private List> queryForListOfMaps(RdfStoreServiceAPI rdfStore, String variableQuery) { - try { - return rdfStore.executeSelectQuery(variableQuery, JenaQueryUtils::convertToListOfMaps); - } catch (RuntimeException e) { - throw new RuntimeException("Query failed: \n" + variableQuery, e); - } - } - private Set getNewSelectorUris(RdfStoreServiceAPI rdfStore, UriGenerator generator) { - String query = uriGeneratorRoot.getPrefixQuery() + generator.getFullUriSelector(); - List uris = getUris(rdfStore, query); - return uris.stream() + final String query = uriGeneratorRoot.getPrefixQuery() + generator.getFullUriSelector(); + return rdfStore + .executeSelectQuery(query, UriGeneratorCalculator::convertToList).stream() .filter(uri -> uri.startsWith(newUriPrefix)) .collect(Collectors.toSet()); } - private List getUris(RdfStoreServiceAPI rdfStore, String query) { - try { - return rdfStore.executeSelectQuery(query, UriGeneratorCalculator::convertToList); - } catch (RuntimeException e) { - throw new RuntimeException("problem with query: \n" + query, e); - } - } - private static List convertToList(ResultSet resultSet) { List result = new ArrayList<>(); From 873315050239d5c98d8b31f78b9347f9d08ae763 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Thu, 20 Jun 2024 08:51:19 +0200 Subject: [PATCH 07/58] feat: basic support for JSON-LD 1.1 inputs --- .../asquare/cube/urigenerator/Format.java | 6 ++ .../JsonLdObjectMapperFactory.java | 25 ++++++++ .../urigenerator/UriGeneratorCalculator.java | 5 +- .../asquare/cube/urigenerator/Utils.java | 19 ++++++ .../asquare/cube/urigenerator/Vocabulary.java | 17 ++++++ .../cube/urigenerator/json/Prefix.java | 23 ++++++++ .../cube/urigenerator/json/UriGenerator.java | 50 +++++----------- .../urigenerator/json/UriGeneratorRoot.java | 59 ++++++------------- .../UriGeneratorCalculatorTest.java | 24 +++++--- .../urigenerator/uri-generators.json | 19 ++++++ 10 files changed, 159 insertions(+), 88 deletions(-) create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java create mode 100644 src/test/resources/urigenerator/uri-generators.json diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java new file mode 100644 index 0000000..b7a109e --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java @@ -0,0 +1,6 @@ +package zone.cogni.asquare.cube.urigenerator; + +public enum Format { + JSON5, + JSONLD11 +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java new file mode 100644 index 0000000..56b106a --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java @@ -0,0 +1,25 @@ +package zone.cogni.asquare.cube.urigenerator; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import cz.cvut.kbss.jsonld.ConfigParam; +import cz.cvut.kbss.jsonld.jackson.JsonLdModule; +import cz.cvut.kbss.jsonld.jackson.serialization.SerializationConstants; + +import static cz.cvut.kbss.jsonld.ConfigParam.ASSUME_TARGET_TYPE; + +public class JsonLdObjectMapperFactory { + + public static ObjectMapper getJsonLdMapper() { + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + final JsonLdModule module = new JsonLdModule(); + module.configure(ASSUME_TARGET_TYPE, Boolean.TRUE.toString()); + module.configure(ConfigParam.SCAN_PACKAGE, "zone.cogni.asquare.cube.urigenerator.json"); + module.configure(SerializationConstants.FORM, SerializationConstants.FORM_COMPACT_WITH_CONTEXT); + objectMapper.registerModule(module); + return objectMapper; + } +} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java index 1d96671..9bf02fd 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -39,11 +39,12 @@ public class UriGeneratorCalculator { public UriGeneratorCalculator( String newUriPrefix, TemplateService templateService, - URL uriGeneratorRootResource + URL uriGeneratorRootResource, + Format format ) { this.newUriPrefix = newUriPrefix; this.templateService = templateService; - this.uriGeneratorRoot = UriGeneratorRoot.load(uriGeneratorRootResource); + this.uriGeneratorRoot = Utils.load(uriGeneratorRootResource, format); initPreparedStatements(); } diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java new file mode 100644 index 0000000..2db6b35 --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java @@ -0,0 +1,19 @@ +package zone.cogni.asquare.cube.urigenerator; + +import com.fasterxml.jackson.databind.ObjectMapper; +import zone.cogni.asquare.cube.json5.Json5Light; +import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; + +import java.io.IOException; +import java.net.URL; + +public class Utils { + public static UriGeneratorRoot load(URL resource, Format format) { + try { + ObjectMapper mapper = format.equals(Format.JSON5) ? Json5Light.getJson5Mapper() : JsonLdObjectMapperFactory.getJsonLdMapper(); + return mapper.readValue(resource.openStream(), UriGeneratorRoot.class); + } catch (IOException e) { + throw new RuntimeException("Unable to load uri generator configuration." + resource, e); + } + } +} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java new file mode 100644 index 0000000..3e97649 --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java @@ -0,0 +1,17 @@ +package zone.cogni.asquare.cube.urigenerator; + +public class Vocabulary { + private static final String NS = "https://data.cogni.zone/voc/irigenerator/"; + public static final String C_IRI_GENERATOR = NS + "iri-generator"; + public static final String P_IRI_SELECTOR = NS + "iri-selector"; + public static final String P_VARIABLE_SELECTOR = NS + "variable-selector"; + public static final String P_IRI_TEMPLATE = NS + "iri-template"; + + public static final String C_GENERATOR_SPECIFICATION = NS + "generator-specification"; + public static final String P_PREFIX = NS + "prefix"; + public static final String P_GENERATOR = NS + "generator"; + + public static final String C_PREFIX = NS + "prefix-class"; + public static final String P_PREFIX_NAME = NS + "prefix-name"; + public static final String P_NAMESPACE = NS + "namespace"; +} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java new file mode 100644 index 0000000..46c4108 --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java @@ -0,0 +1,23 @@ +package zone.cogni.asquare.cube.urigenerator.json; + +import cz.cvut.kbss.jopa.model.annotations.Id; +import cz.cvut.kbss.jopa.model.annotations.OWLClass; +import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty; +import lombok.Data; +import zone.cogni.asquare.cube.urigenerator.Vocabulary; + +import java.net.URI; + +@Data +@OWLClass(iri = Vocabulary.C_PREFIX) +public class Prefix { + + @Id + private URI id; + + @OWLDataProperty(iri = Vocabulary.P_PREFIX_NAME) + private String key; + + @OWLDataProperty(iri = Vocabulary.P_NAMESPACE) + private String value; +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java index a1fbe4b..5d87c1d 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java @@ -1,46 +1,26 @@ package zone.cogni.asquare.cube.urigenerator.json; +import cz.cvut.kbss.jopa.model.annotations.Id; +import cz.cvut.kbss.jopa.model.annotations.OWLClass; +import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty; +import lombok.Data; +import zone.cogni.asquare.cube.urigenerator.Vocabulary; + +@Data +@OWLClass(iri = Vocabulary.C_IRI_GENERATOR) public class UriGenerator { + @Id private String id; - private String uriSelector; - private String variableSelector; - private String uriTemplate; - - public UriGenerator() { - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getUriSelector() { - return uriSelector; - } - public void setUriSelector(String uriSelector) { - this.uriSelector = uriSelector; - } - - public String getVariableSelector() { - return variableSelector; - } - - public void setVariableSelector(String variableSelector) { - this.variableSelector = variableSelector; - } + @OWLDataProperty(iri = Vocabulary.P_IRI_SELECTOR) + private String uriSelector; - public String getUriTemplate() { - return uriTemplate; - } + @OWLDataProperty(iri = Vocabulary.P_VARIABLE_SELECTOR) + private String variableSelector; - public void setUriTemplate(String uriTemplate) { - this.uriTemplate = uriTemplate; - } + @OWLDataProperty(iri = Vocabulary.P_IRI_TEMPLATE) + private String uriTemplate; public String getFullUriSelector() { if (uriSelector == null) return ""; diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java index 5a6d400..900b9da 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java @@ -1,62 +1,37 @@ package zone.cogni.asquare.cube.urigenerator.json; -import com.fasterxml.jackson.databind.ObjectMapper; +import cz.cvut.kbss.jopa.model.annotations.Id; +import cz.cvut.kbss.jopa.model.annotations.OWLClass; +import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty; +import lombok.Data; import org.apache.commons.lang3.StringUtils; -import zone.cogni.asquare.cube.json5.Json5Light; +import zone.cogni.asquare.cube.urigenerator.Vocabulary; -import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; +import java.net.URI; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; +@Data +@OWLClass(iri = Vocabulary.C_GENERATOR_SPECIFICATION) public class UriGeneratorRoot { - public static UriGeneratorRoot load(URL resource) { - try { - ObjectMapper mapper = Json5Light.getJson5Mapper(); - return mapper.readValue(resource.openStream(), UriGeneratorRoot.class); - } catch (IOException e) { - String extra; - try { - extra = " URL " + resource.toURI(); - } catch (URISyntaxException ex) { - throw new RuntimeException(ex); - } - throw new RuntimeException("Unable to load uri generator configuration." + extra, e); - } - } - - private Map prefixes; - private List generators; + @Id + private URI id; - public UriGeneratorRoot() { - } + @OWLObjectProperty(iri = Vocabulary.P_PREFIX) + private List prefixes; +// private Map prefixes; - public Map getPrefixes() { - return prefixes; - } - - public void setPrefixes(Map prefixes) { - this.prefixes = prefixes; - } - - public List getGenerators() { - return generators; - } - - public void setGenerators(List generators) { - this.generators = generators; - } + @OWLObjectProperty(iri = Vocabulary.P_GENERATOR) + private List generators; public String getPrefixQuery() { - return prefixes.entrySet() + return prefixes +// .entrySet() .stream() .map(e -> "PREFIX " + StringUtils.rightPad(e.getKey() + ":", 8) + " <" + e.getValue() + ">\n") .collect(Collectors.joining()) + "\n"; } - } diff --git a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java index 78e45dc..3f6e72e 100644 --- a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java +++ b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java @@ -6,7 +6,6 @@ import org.apache.jena.rdf.model.ResourceFactory; import org.apache.jena.riot.RDFDataMgr; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import zone.cogni.asquare.cube.spel.SpelService; @@ -14,18 +13,25 @@ public class UriGeneratorCalculatorTest { - UriGeneratorCalculator sut; - @BeforeEach - public void init() { - final URL uriGeneratorsResource = getClass().getResource("/urigenerator/uri-generators.json5"); - sut = new UriGeneratorCalculator("http://resource", - new SpelService(), - uriGeneratorsResource); + @Test + public void testURIConvertedForJsonLD11() { + testURIConvertedForSyntax("/urigenerator/uri-generators.json", Format.JSONLD11); } @Test - public void test_uris_converted() { + public void testURIConvertedForJson5() { + testURIConvertedForSyntax("/urigenerator/uri-generators.json5", Format.JSON5); + } + + private void testURIConvertedForSyntax(String generatorsResource, Format format) { + final URL uriGeneratorsResource = getClass().getResource(generatorsResource); + + final UriGeneratorCalculator sut = new UriGeneratorCalculator("http://resource", + new SpelService(), + uriGeneratorsResource, + format); + final URL modelUrl = getClass().getResource("/urigenerator/model.ttl"); assert modelUrl != null; diff --git a/src/test/resources/urigenerator/uri-generators.json b/src/test/resources/urigenerator/uri-generators.json new file mode 100644 index 0000000..3e778e1 --- /dev/null +++ b/src/test/resources/urigenerator/uri-generators.json @@ -0,0 +1,19 @@ +{ + "@context": "file:/home/psiotwo/soft/cognizone/irigenerator/src/main/resources/context.json", + "prefixes": { + "prefix-name": "demo", + "namespace": "http://demo.com/model#" + }, + "generators": [ + { + "uriSelector": "select ?uri { ?uri a demo:One }", + "variableSelector": "select ?id where { <#{[uri]}> demo:id ?id }", + "uriTemplate": "#{[baseUri]}/#{[id]}" + }, + { + "uriSelector": "select ?uri { ?uri a demo:Two }", + "variableSelector": "select ?year ?sequence where { <#{[uri]}> demo:year ?year ; demo:sequence ?sequence}", + "uriTemplate": "#{[baseUri]}/#{[year]}/#{[sequence]}" + } + ] +} \ No newline at end of file From 7232e36b9fb6ef117c1a195a8d59562e7b8da846 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Sat, 22 Jun 2024 09:16:00 +0200 Subject: [PATCH 08/58] feat: custom deserializer for prefixes in JSON5 --- .../cube/urigenerator/PrefixDeserializer.java | 38 +++++++++++++++++++ .../cube/urigenerator/json/Prefix.java | 2 + .../urigenerator/json/UriGeneratorRoot.java | 4 +- 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/PrefixDeserializer.java diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/PrefixDeserializer.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/PrefixDeserializer.java new file mode 100644 index 0000000..0acab3b --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/PrefixDeserializer.java @@ -0,0 +1,38 @@ +package zone.cogni.asquare.cube.urigenerator; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import zone.cogni.asquare.cube.urigenerator.json.Prefix; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Deserializes the map of prefixes into Java POJOs. + * + * TODO: note that this is here only to ensure compliance of the new data model with the original JSON5 serialization. + */ +public class PrefixDeserializer extends JsonDeserializer> { + + @Override + public List deserialize(JsonParser p, DeserializationContext ctxt) + throws IOException { + final List keyValueList = new ArrayList<>(); + final ObjectMapper mapper = (ObjectMapper) p.getCodec(); + final JsonNode rootNode = mapper.readTree(p); + + final Iterator fieldNames = rootNode.fieldNames(); + while (fieldNames.hasNext()) { + final String key = fieldNames.next(); + final String value = rootNode.get(key).asText(); + keyValueList.add(new Prefix().setKey(key).setValue(value)); + } + + return keyValueList; + } +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java index 46c4108..5215cea 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java @@ -4,11 +4,13 @@ import cz.cvut.kbss.jopa.model.annotations.OWLClass; import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty; import lombok.Data; +import lombok.experimental.Accessors; import zone.cogni.asquare.cube.urigenerator.Vocabulary; import java.net.URI; @Data +@Accessors(chain = true) @OWLClass(iri = Vocabulary.C_PREFIX) public class Prefix { diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java index 900b9da..f8ba3ff 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java @@ -1,10 +1,12 @@ package zone.cogni.asquare.cube.urigenerator.json; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import cz.cvut.kbss.jopa.model.annotations.Id; import cz.cvut.kbss.jopa.model.annotations.OWLClass; import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty; import lombok.Data; import org.apache.commons.lang3.StringUtils; +import zone.cogni.asquare.cube.urigenerator.PrefixDeserializer; import zone.cogni.asquare.cube.urigenerator.Vocabulary; import java.net.URI; @@ -19,8 +21,8 @@ public class UriGeneratorRoot { private URI id; @OWLObjectProperty(iri = Vocabulary.P_PREFIX) + @JsonDeserialize(using = PrefixDeserializer.class) private List prefixes; -// private Map prefixes; @OWLObjectProperty(iri = Vocabulary.P_GENERATOR) private List generators; From 636facbd0019eb329d73a8b4d1d1f4eddb2e9f51 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Sat, 22 Jun 2024 09:19:19 +0200 Subject: [PATCH 09/58] fix: JSON-lD example --- src/test/resources/urigenerator/uri-generators.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/resources/urigenerator/uri-generators.json b/src/test/resources/urigenerator/uri-generators.json index 3e778e1..79f6c35 100644 --- a/src/test/resources/urigenerator/uri-generators.json +++ b/src/test/resources/urigenerator/uri-generators.json @@ -1,9 +1,9 @@ { "@context": "file:/home/psiotwo/soft/cognizone/irigenerator/src/main/resources/context.json", - "prefixes": { + "prefixes": [{ "prefix-name": "demo", "namespace": "http://demo.com/model#" - }, + }], "generators": [ { "uriSelector": "select ?uri { ?uri a demo:One }", From c5f16e36771574fc927712c4c989995ac650799d Mon Sep 17 00:00:00 2001 From: psiotwo Date: Sat, 22 Jun 2024 09:19:42 +0200 Subject: [PATCH 10/58] fix: simplifyng data model (POJOs) --- .../urigenerator/UriGeneratorCalculator.java | 8 +++--- .../asquare/cube/urigenerator/Utils.java | 28 +++++++++++++++++++ .../cube/urigenerator/json/UriGenerator.java | 12 ++------ .../urigenerator/json/UriGeneratorRoot.java | 14 ++-------- 4 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java index 9bf02fd..9cf07ab 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -63,7 +63,7 @@ public Model convert(Model model, Map context) { validate(model); return model; - } catch(RuntimeException e) { + } catch (RuntimeException e) { throw new RuntimeException("An error occurred during URI generation", e); } } @@ -163,9 +163,9 @@ private Optional calculateNewUri(final RdfStoreServiceAPI rdfStore, variables.put("uri", oldUri); // variable template can also NOT exist: then this step is skipped! - final String variableSelector = result.getGenerator().getFullVariableSelector(); + final String variableSelector = result.getGenerator().getVariableSelector(); if (StringUtils.isNotBlank(variableSelector)) { - final String variableTemplateQuery = uriGeneratorRoot.getPrefixQuery() + variableSelector; + final String variableTemplateQuery = Utils.getPrefixQuery(uriGeneratorRoot.getPrefixes()) + variableSelector; final String variableQuery = templateService.processTemplate(variableTemplateQuery, variables); if (log.isTraceEnabled()) log.trace("query: {}", variableQuery); @@ -236,7 +236,7 @@ private void nonNullCheck(Map nodeMap, RDFNode node) { } private Set getNewSelectorUris(RdfStoreServiceAPI rdfStore, UriGenerator generator) { - final String query = uriGeneratorRoot.getPrefixQuery() + generator.getFullUriSelector(); + final String query = Utils.getPrefixQuery(uriGeneratorRoot.getPrefixes()) + generator.getUriSelector(); return rdfStore .executeSelectQuery(query, UriGeneratorCalculator::convertToList).stream() .filter(uri -> uri.startsWith(newUriPrefix)) diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java index 2db6b35..04e5529 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java @@ -1,13 +1,25 @@ package zone.cogni.asquare.cube.urigenerator; import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.StringUtils; import zone.cogni.asquare.cube.json5.Json5Light; +import zone.cogni.asquare.cube.urigenerator.json.Prefix; import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; import java.io.IOException; import java.net.URL; +import java.util.Collection; +import java.util.stream.Collectors; public class Utils { + + /** + * Loads the Java object from the given resource in the given format. + * + * @param resource URL to load the object from + * @param format format of data that dwell at the URL + * @return the Java object + */ public static UriGeneratorRoot load(URL resource, Format format) { try { ObjectMapper mapper = format.equals(Format.JSON5) ? Json5Light.getJson5Mapper() : JsonLdObjectMapperFactory.getJsonLdMapper(); @@ -16,4 +28,20 @@ public static UriGeneratorRoot load(URL resource, Format format) { throw new RuntimeException("Unable to load uri generator configuration." + resource, e); } } + + + /** + * Constructs the prefix clauses from the objects. + * + * @param prefixes prefixes to generate + * @return the SPARQL representation + */ + public static String getPrefixQuery(final Collection prefixes) { + return prefixes + .stream() + .map(e -> "PREFIX " + + StringUtils.rightPad(e.getKey() + ":", 8) + " <" + e.getValue() + ">\n") + .collect(Collectors.joining()) + + "\n"; + } } \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java index 5d87c1d..db1befa 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java @@ -4,9 +4,11 @@ import cz.cvut.kbss.jopa.model.annotations.OWLClass; import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty; import lombok.Data; +import lombok.experimental.Accessors; import zone.cogni.asquare.cube.urigenerator.Vocabulary; @Data +@Accessors(chain = true) @OWLClass(iri = Vocabulary.C_IRI_GENERATOR) public class UriGenerator { @@ -21,14 +23,4 @@ public class UriGenerator { @OWLDataProperty(iri = Vocabulary.P_IRI_TEMPLATE) private String uriTemplate; - - public String getFullUriSelector() { - if (uriSelector == null) return ""; - return uriSelector; - } - - public String getFullVariableSelector() { - if (variableSelector == null) return ""; - return variableSelector; - } } diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java index f8ba3ff..afbc9b2 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java @@ -5,15 +5,15 @@ import cz.cvut.kbss.jopa.model.annotations.OWLClass; import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty; import lombok.Data; -import org.apache.commons.lang3.StringUtils; +import lombok.experimental.Accessors; import zone.cogni.asquare.cube.urigenerator.PrefixDeserializer; import zone.cogni.asquare.cube.urigenerator.Vocabulary; import java.net.URI; import java.util.List; -import java.util.stream.Collectors; @Data +@Accessors(chain = true) @OWLClass(iri = Vocabulary.C_GENERATOR_SPECIFICATION) public class UriGeneratorRoot { @@ -26,14 +26,4 @@ public class UriGeneratorRoot { @OWLObjectProperty(iri = Vocabulary.P_GENERATOR) private List generators; - - public String getPrefixQuery() { - return prefixes -// .entrySet() - .stream() - .map(e -> "PREFIX " - + StringUtils.rightPad(e.getKey() + ":", 8) + " <" + e.getValue() + ">\n") - .collect(Collectors.joining()) - + "\n"; - } } From b36483ab25e6c2fa1351b0ce1e080193f9fec07a Mon Sep 17 00:00:00 2001 From: psiotwo Date: Sat, 22 Jun 2024 09:55:49 +0200 Subject: [PATCH 11/58] refactor: move to the package zone.cogni.semantics.irigenerator, renaming URIs to IRIs --- .../asquare/cube/urigenerator/Format.java | 6 - .../JsonLdObjectMapperFactory.java | 25 -- .../cube/urigenerator/PrefixDeserializer.java | 38 --- .../urigenerator/UriGeneratorCalculator.java | 283 ------------------ .../cube/urigenerator/UriGeneratorResult.java | 42 --- .../asquare/cube/urigenerator/Utils.java | 47 --- .../asquare/cube/urigenerator/Vocabulary.java | 17 -- .../cube/urigenerator/json/Prefix.java | 25 -- .../cube/urigenerator/json/UriGenerator.java | 26 -- .../urigenerator/json/UriGeneratorRoot.java | 29 -- .../UriGeneratorCalculatorTest.java | 47 --- .../{urigenerator => irigenerator}/model.ttl | 0 .../uri-generators.json | 0 .../uri-generators.json5 | 0 14 files changed, 585 deletions(-) delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/PrefixDeserializer.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java delete mode 100644 src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java rename src/test/resources/{urigenerator => irigenerator}/model.ttl (100%) rename src/test/resources/{urigenerator => irigenerator}/uri-generators.json (100%) rename src/test/resources/{urigenerator => irigenerator}/uri-generators.json5 (100%) diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java deleted file mode 100644 index b7a109e..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java +++ /dev/null @@ -1,6 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -public enum Format { - JSON5, - JSONLD11 -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java deleted file mode 100644 index 56b106a..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java +++ /dev/null @@ -1,25 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import cz.cvut.kbss.jsonld.ConfigParam; -import cz.cvut.kbss.jsonld.jackson.JsonLdModule; -import cz.cvut.kbss.jsonld.jackson.serialization.SerializationConstants; - -import static cz.cvut.kbss.jsonld.ConfigParam.ASSUME_TARGET_TYPE; - -public class JsonLdObjectMapperFactory { - - public static ObjectMapper getJsonLdMapper() { - final ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - final JsonLdModule module = new JsonLdModule(); - module.configure(ASSUME_TARGET_TYPE, Boolean.TRUE.toString()); - module.configure(ConfigParam.SCAN_PACKAGE, "zone.cogni.asquare.cube.urigenerator.json"); - module.configure(SerializationConstants.FORM, SerializationConstants.FORM_COMPACT_WITH_CONTEXT); - objectMapper.registerModule(module); - return objectMapper; - } -} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/PrefixDeserializer.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/PrefixDeserializer.java deleted file mode 100644 index 0acab3b..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/PrefixDeserializer.java +++ /dev/null @@ -1,38 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import zone.cogni.asquare.cube.urigenerator.json.Prefix; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -/** - * Deserializes the map of prefixes into Java POJOs. - * - * TODO: note that this is here only to ensure compliance of the new data model with the original JSON5 serialization. - */ -public class PrefixDeserializer extends JsonDeserializer> { - - @Override - public List deserialize(JsonParser p, DeserializationContext ctxt) - throws IOException { - final List keyValueList = new ArrayList<>(); - final ObjectMapper mapper = (ObjectMapper) p.getCodec(); - final JsonNode rootNode = mapper.readTree(p); - - final Iterator fieldNames = rootNode.fieldNames(); - while (fieldNames.hasNext()) { - final String key = fieldNames.next(); - final String value = rootNode.get(key).asText(); - keyValueList.add(new Prefix().setKey(key).setValue(value)); - } - - return keyValueList; - } -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java deleted file mode 100644 index 9cf07ab..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ /dev/null @@ -1,283 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -import org.apache.commons.lang3.StringUtils; -import org.apache.jena.query.Query; -import org.apache.jena.query.QueryFactory; -import org.apache.jena.query.QuerySolutionMap; -import org.apache.jena.query.ResultSet; -import org.apache.jena.rdf.model.Model; -import org.apache.jena.rdf.model.RDFNode; -import org.apache.jena.rdf.model.ResourceFactory; -import org.apache.jena.util.ResourceUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import zone.cogni.asquare.cube.spel.TemplateService; -import zone.cogni.asquare.cube.urigenerator.json.UriGenerator; -import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; -import zone.cogni.asquare.triplestore.RdfStoreServiceAPI; -import zone.cogni.asquare.triplestore.InternalRdfStoreService; -import zone.cogni.sem.jena.template.JenaQueryUtils; - -import jakarta.annotation.Nonnull; - -import java.io.StringWriter; -import java.net.URL; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -public class UriGeneratorCalculator { - private static final Logger log = LoggerFactory.getLogger(UriGeneratorCalculator.class); - public static final int EXPECTED_ROW_COUNT = 1; - - private final String newUriPrefix; - private final TemplateService templateService; - private final UriGeneratorRoot uriGeneratorRoot; - private final Map preparedStatements = new HashMap<>(); - - public UriGeneratorCalculator( - String newUriPrefix, - TemplateService templateService, - URL uriGeneratorRootResource, - Format format - ) { - this.newUriPrefix = newUriPrefix; - this.templateService = templateService; - this.uriGeneratorRoot = Utils.load(uriGeneratorRootResource, format); - initPreparedStatements(); - } - - private void initPreparedStatements() { - preparedStatements.put("exists-uri", QueryFactory.create("ask { { ?x ?p ?o } union { ?s ?p ?x } } ")); - } - - public Model convert(Model model, Map context) { - try { - final RdfStoreServiceAPI rdfStore = getRdfStore(model); - final List results = getGeneratorResults(rdfStore); - - int replaceCount = inputValidations(model, results); - processReplacements(model, rdfStore, replaceCount, context, results); - - validate(model); - - return model; - } catch (RuntimeException e) { - throw new RuntimeException("An error occurred during URI generation", e); - } - } - - @Nonnull - private List getGeneratorResults(RdfStoreServiceAPI rdfStore) { - return uriGeneratorRoot.getGenerators() - .stream() - .map(generator -> getUriGeneratorResult(rdfStore, generator)) - .collect(Collectors.toList()); - } - - @Nonnull - private UriGeneratorResult getUriGeneratorResult(RdfStoreServiceAPI rdfStore, UriGenerator generator) { - UriGeneratorResult uriGeneratorResult = new UriGeneratorResult(); - uriGeneratorResult.setGenerator(generator); - uriGeneratorResult.setUris(getNewSelectorUris(rdfStore, generator)); - return uriGeneratorResult; - } - - /** - * @return number of uris to be replaces - */ - private int inputValidations(final Model model, final List results) { - final Set incomingUris = getProblemUris(model); - - final Set selectedUris = new HashSet<>(); - final Set duplicates = results.stream() - .flatMap(result -> result.getUris().stream()) - .filter(uri -> !selectedUris.add(uri)) - .collect(Collectors.toSet()); - - if (!duplicates.isEmpty()) - log.error("some uris matched multiple selectors: {}", duplicates); - - final int size = incomingUris.size(); - if (size != selectedUris.size()) - log.error("incoming uris and selected uris do not match up." + - "\n\t incoming: {}" + - "\n\t selected: {}", incomingUris, selectedUris); - - if (!duplicates.isEmpty() || size != selectedUris.size()) - throw new RuntimeException("some validations failed when converting new uris, check logs for more info"); - - log.info("(uri generator) replacing {} uris", size); - return size; - } - - private void processReplacements(final Model model, - final RdfStoreServiceAPI rdfStore, - int replaceCount, - final Map context, - final List results) { - int loopCount = 0; - while (true) { - int count = calculateReplacementUrisLoop(model, rdfStore, context, results); - replaceCount -= count; - - log.info("(uri generator) loop {} processed {} uris", ++loopCount, count); - - // stop loop when all uris are processed - if (replaceCount == 0) break; - - // stop loop when no replacement where processed - if (count == 0) break; - } - } - - private int calculateReplacementUrisLoop(final Model model, - final RdfStoreServiceAPI rdfStore, - final Map context, - final List results) { - final AtomicInteger count = new AtomicInteger(); - - results.forEach(result -> result.getUris().forEach(uri -> { - if (result.alreadyReplaced(uri)) return; - - final Optional possibleNewUri = calculateNewUri(rdfStore, context, result, uri); - if (possibleNewUri.isPresent()) { - count.addAndGet(1); - result.addReplacement(uri, possibleNewUri.get()); - ResourceUtils.renameResource(model.getResource(uri), possibleNewUri.get()); - } - })); - - return count.get(); - } - - private Optional calculateNewUri(final RdfStoreServiceAPI rdfStore, - final Map context, - final UriGeneratorResult result, - final String oldUri) { - if (log.isTraceEnabled()) log.trace("calculate new uri for {}", oldUri); - traceModel(rdfStore); - - final Map variables = new HashMap<>(context); - variables.put("uri", oldUri); - - // variable template can also NOT exist: then this step is skipped! - final String variableSelector = result.getGenerator().getVariableSelector(); - if (StringUtils.isNotBlank(variableSelector)) { - final String variableTemplateQuery = Utils.getPrefixQuery(uriGeneratorRoot.getPrefixes()) + variableSelector; - final String variableQuery = templateService.processTemplate(variableTemplateQuery, variables); - if (log.isTraceEnabled()) log.trace("query: {}", variableQuery); - - final Supplier contextSupplier = () -> result.getGenerator().getId(); - final Optional> variableMap = getQueryMap(contextSupplier, rdfStore, variableQuery); - - // if one of template variables is still a new URI we should skip calculation for now - if (variableMap.isEmpty()) return Optional.empty(); - - final Map map = variableMap.get(); - if (log.isTraceEnabled()) log.trace("query result: {}", map); - variables.putAll(map); - } - if (log.isTraceEnabled()) log.debug("variables: {}", variables); - - final String uriTemplate = result.getGenerator().getUriTemplate(); - final String newUri = templateService.processTemplate(uriTemplate, variables); - - if (existsInModel(rdfStore, newUri)) - throw new RuntimeException("uri overlap found for " + newUri); - - return Optional.of(newUri); - } - - private void traceModel(RdfStoreServiceAPI rdfStore) { - if (!log.isTraceEnabled()) return; - - final Model trace = rdfStore.executeConstructQuery("construct {?s ?p ?o} where {?s ?p ?o}"); - final StringWriter out = new StringWriter(); - trace.write(out, "ttl"); - log.trace("model: {}", out); - } - - private boolean existsInModel(RdfStoreServiceAPI rdfStore, String newUri) { - final QuerySolutionMap querySolution = new QuerySolutionMap(); - querySolution.add("x", ResourceFactory.createResource(newUri)); - - return rdfStore.executeAskQuery(preparedStatements.get("exists-uri"), querySolution); - } - - /** - * @return empty optional if one of resources start with a newUriPrefix ! - * else a map of variables to be used in uri template! - */ - private Optional> getQueryMap(Supplier context, - RdfStoreServiceAPI rdfStore, - String variableQuery) { - final List> result1 = rdfStore.executeSelectQuery(variableQuery, JenaQueryUtils::convertToListOfMaps); - if (result1.size() != EXPECTED_ROW_COUNT) - throw new RuntimeException("[" + context.get() + "] expected 1 row, found " + result1); - - final Map nodeMap = result1.get(0); - boolean isBadMatch = nodeMap.values() - .stream() - .peek(node -> nonNullCheck(nodeMap, node)) - .anyMatch(node -> node.isURIResource() - && node.asResource().getURI().startsWith(newUriPrefix)); - if (isBadMatch) return Optional.empty(); - - final Map result = new HashMap<>(); - nodeMap.forEach((k, v) -> result.put(k, (v.isResource() ? v.asResource().getURI() : v.asLiteral().getString()))); - - return Optional.of(result); - } - - private void nonNullCheck(Map nodeMap, RDFNode node) { - if (node == null) throw new RuntimeException("variableSelector result has some null values: " + nodeMap); - } - - private Set getNewSelectorUris(RdfStoreServiceAPI rdfStore, UriGenerator generator) { - final String query = Utils.getPrefixQuery(uriGeneratorRoot.getPrefixes()) + generator.getUriSelector(); - return rdfStore - .executeSelectQuery(query, UriGeneratorCalculator::convertToList).stream() - .filter(uri -> uri.startsWith(newUriPrefix)) - .collect(Collectors.toSet()); - } - - private static List convertToList(ResultSet resultSet) { - List result = new ArrayList<>(); - - resultSet.forEachRemaining(querySolution -> - result.add(querySolution.get("uri").asResource().getURI()) - ); - - return result; - } - - private RdfStoreServiceAPI getRdfStore(Model model) { - return new InternalRdfStoreService(model); - } - - private void validate(Model model) { - Set problemUris = getProblemUris(model); - - if (!problemUris.isEmpty()) throw new RuntimeException("some uris could not be replaced: " + problemUris); - } - - @Nonnull - private Set getProblemUris(Model model) { - Set problemUris = new HashSet<>(); - model.listStatements() - .forEachRemaining(statement -> { - if (statement.getSubject().getURI().startsWith(newUriPrefix)) { - problemUris.add(statement.getSubject().getURI()); - } - - if (statement.getObject().isURIResource() - && statement.getObject().asResource().getURI().startsWith(newUriPrefix)) { - problemUris.add(statement.getObject().asResource().getURI()); - } - }); - return problemUris; - } - -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java deleted file mode 100644 index 357bedd..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java +++ /dev/null @@ -1,42 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - - -import zone.cogni.asquare.cube.urigenerator.json.UriGenerator; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -public class UriGeneratorResult { - - private UriGenerator generator; - private Set uris; - private final Map replacements = new HashMap<>(); - - public UriGeneratorResult() { - } - - public UriGenerator getGenerator() { - return generator; - } - - public void setGenerator(UriGenerator generator) { - this.generator = generator; - } - - public Set getUris() { - return uris; - } - - public void setUris(Set uris) { - this.uris = uris; - } - - public boolean alreadyReplaced(String oldUri) { - return replacements.containsKey(oldUri); - } - - public void addReplacement(String oldUri, String newUri) { - replacements.put(oldUri, newUri); - } -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java deleted file mode 100644 index 04e5529..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java +++ /dev/null @@ -1,47 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.commons.lang3.StringUtils; -import zone.cogni.asquare.cube.json5.Json5Light; -import zone.cogni.asquare.cube.urigenerator.json.Prefix; -import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; - -import java.io.IOException; -import java.net.URL; -import java.util.Collection; -import java.util.stream.Collectors; - -public class Utils { - - /** - * Loads the Java object from the given resource in the given format. - * - * @param resource URL to load the object from - * @param format format of data that dwell at the URL - * @return the Java object - */ - public static UriGeneratorRoot load(URL resource, Format format) { - try { - ObjectMapper mapper = format.equals(Format.JSON5) ? Json5Light.getJson5Mapper() : JsonLdObjectMapperFactory.getJsonLdMapper(); - return mapper.readValue(resource.openStream(), UriGeneratorRoot.class); - } catch (IOException e) { - throw new RuntimeException("Unable to load uri generator configuration." + resource, e); - } - } - - - /** - * Constructs the prefix clauses from the objects. - * - * @param prefixes prefixes to generate - * @return the SPARQL representation - */ - public static String getPrefixQuery(final Collection prefixes) { - return prefixes - .stream() - .map(e -> "PREFIX " - + StringUtils.rightPad(e.getKey() + ":", 8) + " <" + e.getValue() + ">\n") - .collect(Collectors.joining()) - + "\n"; - } -} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java deleted file mode 100644 index 3e97649..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java +++ /dev/null @@ -1,17 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -public class Vocabulary { - private static final String NS = "https://data.cogni.zone/voc/irigenerator/"; - public static final String C_IRI_GENERATOR = NS + "iri-generator"; - public static final String P_IRI_SELECTOR = NS + "iri-selector"; - public static final String P_VARIABLE_SELECTOR = NS + "variable-selector"; - public static final String P_IRI_TEMPLATE = NS + "iri-template"; - - public static final String C_GENERATOR_SPECIFICATION = NS + "generator-specification"; - public static final String P_PREFIX = NS + "prefix"; - public static final String P_GENERATOR = NS + "generator"; - - public static final String C_PREFIX = NS + "prefix-class"; - public static final String P_PREFIX_NAME = NS + "prefix-name"; - public static final String P_NAMESPACE = NS + "namespace"; -} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java deleted file mode 100644 index 5215cea..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java +++ /dev/null @@ -1,25 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator.json; - -import cz.cvut.kbss.jopa.model.annotations.Id; -import cz.cvut.kbss.jopa.model.annotations.OWLClass; -import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty; -import lombok.Data; -import lombok.experimental.Accessors; -import zone.cogni.asquare.cube.urigenerator.Vocabulary; - -import java.net.URI; - -@Data -@Accessors(chain = true) -@OWLClass(iri = Vocabulary.C_PREFIX) -public class Prefix { - - @Id - private URI id; - - @OWLDataProperty(iri = Vocabulary.P_PREFIX_NAME) - private String key; - - @OWLDataProperty(iri = Vocabulary.P_NAMESPACE) - private String value; -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java deleted file mode 100644 index db1befa..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java +++ /dev/null @@ -1,26 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator.json; - -import cz.cvut.kbss.jopa.model.annotations.Id; -import cz.cvut.kbss.jopa.model.annotations.OWLClass; -import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty; -import lombok.Data; -import lombok.experimental.Accessors; -import zone.cogni.asquare.cube.urigenerator.Vocabulary; - -@Data -@Accessors(chain = true) -@OWLClass(iri = Vocabulary.C_IRI_GENERATOR) -public class UriGenerator { - - @Id - private String id; - - @OWLDataProperty(iri = Vocabulary.P_IRI_SELECTOR) - private String uriSelector; - - @OWLDataProperty(iri = Vocabulary.P_VARIABLE_SELECTOR) - private String variableSelector; - - @OWLDataProperty(iri = Vocabulary.P_IRI_TEMPLATE) - private String uriTemplate; -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java deleted file mode 100644 index afbc9b2..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java +++ /dev/null @@ -1,29 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator.json; - -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import cz.cvut.kbss.jopa.model.annotations.Id; -import cz.cvut.kbss.jopa.model.annotations.OWLClass; -import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty; -import lombok.Data; -import lombok.experimental.Accessors; -import zone.cogni.asquare.cube.urigenerator.PrefixDeserializer; -import zone.cogni.asquare.cube.urigenerator.Vocabulary; - -import java.net.URI; -import java.util.List; - -@Data -@Accessors(chain = true) -@OWLClass(iri = Vocabulary.C_GENERATOR_SPECIFICATION) -public class UriGeneratorRoot { - - @Id - private URI id; - - @OWLObjectProperty(iri = Vocabulary.P_PREFIX) - @JsonDeserialize(using = PrefixDeserializer.class) - private List prefixes; - - @OWLObjectProperty(iri = Vocabulary.P_GENERATOR) - private List generators; -} diff --git a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java deleted file mode 100644 index 3f6e72e..0000000 --- a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -import com.google.common.collect.ImmutableMap; -import org.apache.jena.rdf.model.Model; -import org.apache.jena.rdf.model.ModelFactory; -import org.apache.jena.rdf.model.ResourceFactory; -import org.apache.jena.riot.RDFDataMgr; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import zone.cogni.asquare.cube.spel.SpelService; - -import java.net.URL; - -public class UriGeneratorCalculatorTest { - - - @Test - public void testURIConvertedForJsonLD11() { - testURIConvertedForSyntax("/urigenerator/uri-generators.json", Format.JSONLD11); - } - - @Test - public void testURIConvertedForJson5() { - testURIConvertedForSyntax("/urigenerator/uri-generators.json5", Format.JSON5); - } - - private void testURIConvertedForSyntax(String generatorsResource, Format format) { - final URL uriGeneratorsResource = getClass().getResource(generatorsResource); - - final UriGeneratorCalculator sut = new UriGeneratorCalculator("http://resource", - new SpelService(), - uriGeneratorsResource, - format); - - final URL modelUrl = getClass().getResource("/urigenerator/model.ttl"); - assert modelUrl != null; - - //given - final Model model = ModelFactory.createDefaultModel(); - RDFDataMgr.read(model, modelUrl.toString()); - //when - final Model converted = sut.convert(model, ImmutableMap.of("baseUri", "http://asquare.cogni.zone")); - //then - Assertions.assertTrue(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/5"))); - Assertions.assertTrue(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/2021/0005"))); - } -} diff --git a/src/test/resources/urigenerator/model.ttl b/src/test/resources/irigenerator/model.ttl similarity index 100% rename from src/test/resources/urigenerator/model.ttl rename to src/test/resources/irigenerator/model.ttl diff --git a/src/test/resources/urigenerator/uri-generators.json b/src/test/resources/irigenerator/uri-generators.json similarity index 100% rename from src/test/resources/urigenerator/uri-generators.json rename to src/test/resources/irigenerator/uri-generators.json diff --git a/src/test/resources/urigenerator/uri-generators.json5 b/src/test/resources/irigenerator/uri-generators.json5 similarity index 100% rename from src/test/resources/urigenerator/uri-generators.json5 rename to src/test/resources/irigenerator/uri-generators.json5 From 2fd60cd4689f69feece2f90de51a964911411576 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Sun, 18 Aug 2024 19:54:14 +0200 Subject: [PATCH 12/58] refactor: moving default example to 'demo' folder --- src/test/resources/irigenerator/{ => demo}/model.ttl | 0 src/test/resources/irigenerator/{ => demo}/uri-generators.json | 0 src/test/resources/irigenerator/{ => demo}/uri-generators.json5 | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/test/resources/irigenerator/{ => demo}/model.ttl (100%) rename src/test/resources/irigenerator/{ => demo}/uri-generators.json (100%) rename src/test/resources/irigenerator/{ => demo}/uri-generators.json5 (100%) diff --git a/src/test/resources/irigenerator/model.ttl b/src/test/resources/irigenerator/demo/model.ttl similarity index 100% rename from src/test/resources/irigenerator/model.ttl rename to src/test/resources/irigenerator/demo/model.ttl diff --git a/src/test/resources/irigenerator/uri-generators.json b/src/test/resources/irigenerator/demo/uri-generators.json similarity index 100% rename from src/test/resources/irigenerator/uri-generators.json rename to src/test/resources/irigenerator/demo/uri-generators.json diff --git a/src/test/resources/irigenerator/uri-generators.json5 b/src/test/resources/irigenerator/demo/uri-generators.json5 similarity index 100% rename from src/test/resources/irigenerator/uri-generators.json5 rename to src/test/resources/irigenerator/demo/uri-generators.json5 From a60ae508a99f0a817eff589247cb91a6972e2b9d Mon Sep 17 00:00:00 2001 From: psiotwo Date: Mon, 19 Aug 2024 08:12:25 +0200 Subject: [PATCH 13/58] feat: test parameterization and improved logging --- src/test/resources/irigenerator/demo/expected-model.ttl | 8 ++++++++ .../irigenerator/demo/{model.ttl => original-model.ttl} | 0 2 files changed, 8 insertions(+) create mode 100644 src/test/resources/irigenerator/demo/expected-model.ttl rename src/test/resources/irigenerator/demo/{model.ttl => original-model.ttl} (100%) diff --git a/src/test/resources/irigenerator/demo/expected-model.ttl b/src/test/resources/irigenerator/demo/expected-model.ttl new file mode 100644 index 0000000..10e9a70 --- /dev/null +++ b/src/test/resources/irigenerator/demo/expected-model.ttl @@ -0,0 +1,8 @@ +@prefix demo: . + + a demo:One ; + demo:id "5" . + + a demo:Two ; + demo:year "2021" ; + demo:sequence "0005" . \ No newline at end of file diff --git a/src/test/resources/irigenerator/demo/model.ttl b/src/test/resources/irigenerator/demo/original-model.ttl similarity index 100% rename from src/test/resources/irigenerator/demo/model.ttl rename to src/test/resources/irigenerator/demo/original-model.ttl From 1a65b92563447bbfb5d33a4ca37364dcddd647aa Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 21 Aug 2024 09:45:18 +0200 Subject: [PATCH 14/58] refactor: test IRIs --- .../irigenerator/demo/expected-model.ttl | 12 +++--- .../irigenerator/demo/original-model.ttl | 12 +++--- .../irigenerator/demo/uri-generators.json | 40 +++++++++++++++---- .../irigenerator/demo/uri-generators.json5 | 12 +++--- 4 files changed, 51 insertions(+), 25 deletions(-) diff --git a/src/test/resources/irigenerator/demo/expected-model.ttl b/src/test/resources/irigenerator/demo/expected-model.ttl index 10e9a70..baddb9b 100644 --- a/src/test/resources/irigenerator/demo/expected-model.ttl +++ b/src/test/resources/irigenerator/demo/expected-model.ttl @@ -1,8 +1,8 @@ -@prefix demo: . +@prefix eczm: . - a demo:One ; - demo:id "5" . + a eczm:One ; + eczm:id "5" . - a demo:Two ; - demo:year "2021" ; - demo:sequence "0005" . \ No newline at end of file + a eczm:Two ; + eczm:year "2021" ; + eczm:sequence "0005" . \ No newline at end of file diff --git a/src/test/resources/irigenerator/demo/original-model.ttl b/src/test/resources/irigenerator/demo/original-model.ttl index efd8442..bf9bfad 100644 --- a/src/test/resources/irigenerator/demo/original-model.ttl +++ b/src/test/resources/irigenerator/demo/original-model.ttl @@ -1,8 +1,8 @@ -@prefix demo: . +@prefix eczm: . - a demo:One ; - demo:id "5" . + a eczm:One ; + eczm:id "5" . - a demo:Two ; - demo:year "2021" ; - demo:sequence "0005" . \ No newline at end of file + a eczm:Two ; + eczm:year "2021" ; + eczm:sequence "0005" . \ No newline at end of file diff --git a/src/test/resources/irigenerator/demo/uri-generators.json b/src/test/resources/irigenerator/demo/uri-generators.json index 79f6c35..ef6f6d3 100644 --- a/src/test/resources/irigenerator/demo/uri-generators.json +++ b/src/test/resources/irigenerator/demo/uri-generators.json @@ -1,18 +1,44 @@ { - "@context": "file:/home/psiotwo/soft/cognizone/irigenerator/src/main/resources/context.json", + "@context": { + "@version": 1.1, + "irigenerator": "https://data.cogni.zone/voc/irigenerator/", + "uri": "@id", + "types": "@type", + "prefixes": { + "@id": "irigenerator:prefix", + "@type": "irigenerator:prefix-class", + "@context": { + "uri": "@id", + "types": "@type", + "prefix-name": "irigenerator:prefix-name", + "namespace": "irigenerator:namespace" + } + }, + "generators": { + "@id": "irigenerator:generator", + "@type": "irigenerator:iri-generator", + "@context": { + "uri": "@id", + "types": "@type", + "uriSelector": "irigenerator:iri-selector", + "variableSelector": "irigenerator:variable-selector", + "uriTemplate": "irigenerator:iri-template" + } + } + }, "prefixes": [{ - "prefix-name": "demo", - "namespace": "http://demo.com/model#" + "prefix-name": "eczm", + "namespace": "https://example.cogni.zone/model#" }], "generators": [ { - "uriSelector": "select ?uri { ?uri a demo:One }", - "variableSelector": "select ?id where { <#{[uri]}> demo:id ?id }", + "uriSelector": "select ?uri { ?uri a eczm:One }", + "variableSelector": "select ?id where { <#{[uri]}> eczm:id ?id }", "uriTemplate": "#{[baseUri]}/#{[id]}" }, { - "uriSelector": "select ?uri { ?uri a demo:Two }", - "variableSelector": "select ?year ?sequence where { <#{[uri]}> demo:year ?year ; demo:sequence ?sequence}", + "uriSelector": "select ?uri { ?uri a eczm:Two }", + "variableSelector": "select ?year ?sequence where { <#{[uri]}> eczm:year ?year ; eczm:sequence ?sequence}", "uriTemplate": "#{[baseUri]}/#{[year]}/#{[sequence]}" } ] diff --git a/src/test/resources/irigenerator/demo/uri-generators.json5 b/src/test/resources/irigenerator/demo/uri-generators.json5 index ba71dad..89e4737 100644 --- a/src/test/resources/irigenerator/demo/uri-generators.json5 +++ b/src/test/resources/irigenerator/demo/uri-generators.json5 @@ -1,20 +1,20 @@ { prefixes: { - demo: "http://demo.com/model#" + "eczm": "https://example.cogni.zone/model#" }, generators: [ { id: "One", - uriSelector: "select ?uri { ?uri a demo:One }", - variableSelector: "select ?id where { <#{[uri]}> demo:id ?id }", + uriSelector: "select ?uri { ?uri a eczm:One }", + variableSelector: "select ?id where { <#{[uri]}> eczm:id ?id }", uriTemplate: "#{[baseUri]}/#{[id]}" }, { id: "Two", - uriSelector: "select ?uri { ?uri a demo:Two }", + uriSelector: "select ?uri { ?uri a eczm:Two }", variableSelector: "select ?year ?sequence where { \ - <#{[uri]}> demo:year ?year ; \ - demo:sequence ?sequence \ + <#{[uri]}> eczm:year ?year ; \ + eczm:sequence ?sequence \ }", uriTemplate: "#{[baseUri]}/#{[year]}/#{[sequence]}" } From 9f832025db0e9bfec998691b97e2ecd46747a029 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 21 Aug 2024 09:47:52 +0200 Subject: [PATCH 15/58] refactor: test case naming --- .../irigenerator/demo/expected-model.ttl | 8 ---- .../irigenerator/demo/original-model.ttl | 8 ---- .../irigenerator/demo/uri-generators.json | 45 ------------------- .../irigenerator/demo/uri-generators.json5 | 22 --------- 4 files changed, 83 deletions(-) delete mode 100644 src/test/resources/irigenerator/demo/expected-model.ttl delete mode 100644 src/test/resources/irigenerator/demo/original-model.ttl delete mode 100644 src/test/resources/irigenerator/demo/uri-generators.json delete mode 100644 src/test/resources/irigenerator/demo/uri-generators.json5 diff --git a/src/test/resources/irigenerator/demo/expected-model.ttl b/src/test/resources/irigenerator/demo/expected-model.ttl deleted file mode 100644 index baddb9b..0000000 --- a/src/test/resources/irigenerator/demo/expected-model.ttl +++ /dev/null @@ -1,8 +0,0 @@ -@prefix eczm: . - - a eczm:One ; - eczm:id "5" . - - a eczm:Two ; - eczm:year "2021" ; - eczm:sequence "0005" . \ No newline at end of file diff --git a/src/test/resources/irigenerator/demo/original-model.ttl b/src/test/resources/irigenerator/demo/original-model.ttl deleted file mode 100644 index bf9bfad..0000000 --- a/src/test/resources/irigenerator/demo/original-model.ttl +++ /dev/null @@ -1,8 +0,0 @@ -@prefix eczm: . - - a eczm:One ; - eczm:id "5" . - - a eczm:Two ; - eczm:year "2021" ; - eczm:sequence "0005" . \ No newline at end of file diff --git a/src/test/resources/irigenerator/demo/uri-generators.json b/src/test/resources/irigenerator/demo/uri-generators.json deleted file mode 100644 index ef6f6d3..0000000 --- a/src/test/resources/irigenerator/demo/uri-generators.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "@context": { - "@version": 1.1, - "irigenerator": "https://data.cogni.zone/voc/irigenerator/", - "uri": "@id", - "types": "@type", - "prefixes": { - "@id": "irigenerator:prefix", - "@type": "irigenerator:prefix-class", - "@context": { - "uri": "@id", - "types": "@type", - "prefix-name": "irigenerator:prefix-name", - "namespace": "irigenerator:namespace" - } - }, - "generators": { - "@id": "irigenerator:generator", - "@type": "irigenerator:iri-generator", - "@context": { - "uri": "@id", - "types": "@type", - "uriSelector": "irigenerator:iri-selector", - "variableSelector": "irigenerator:variable-selector", - "uriTemplate": "irigenerator:iri-template" - } - } - }, - "prefixes": [{ - "prefix-name": "eczm", - "namespace": "https://example.cogni.zone/model#" - }], - "generators": [ - { - "uriSelector": "select ?uri { ?uri a eczm:One }", - "variableSelector": "select ?id where { <#{[uri]}> eczm:id ?id }", - "uriTemplate": "#{[baseUri]}/#{[id]}" - }, - { - "uriSelector": "select ?uri { ?uri a eczm:Two }", - "variableSelector": "select ?year ?sequence where { <#{[uri]}> eczm:year ?year ; eczm:sequence ?sequence}", - "uriTemplate": "#{[baseUri]}/#{[year]}/#{[sequence]}" - } - ] -} \ No newline at end of file diff --git a/src/test/resources/irigenerator/demo/uri-generators.json5 b/src/test/resources/irigenerator/demo/uri-generators.json5 deleted file mode 100644 index 89e4737..0000000 --- a/src/test/resources/irigenerator/demo/uri-generators.json5 +++ /dev/null @@ -1,22 +0,0 @@ -{ - prefixes: { - "eczm": "https://example.cogni.zone/model#" - }, - generators: [ - { - id: "One", - uriSelector: "select ?uri { ?uri a eczm:One }", - variableSelector: "select ?id where { <#{[uri]}> eczm:id ?id }", - uriTemplate: "#{[baseUri]}/#{[id]}" - }, - { - id: "Two", - uriSelector: "select ?uri { ?uri a eczm:Two }", - variableSelector: "select ?year ?sequence where { \ - <#{[uri]}> eczm:year ?year ; \ - eczm:sequence ?sequence \ - }", - uriTemplate: "#{[baseUri]}/#{[year]}/#{[sequence]}" - } - ] -} \ No newline at end of file From 216ad3842b59d8cf64342e9d09ec0dfaedea2fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20K=C5=99emen?= Date: Wed, 21 Aug 2024 11:54:59 +0200 Subject: [PATCH 16/58] chore: create gradle.yml - Github automation --- .github/workflows/gradle.yml | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 .github/workflows/gradle.yml diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml new file mode 100644 index 0000000..ede3faa --- /dev/null +++ b/.github/workflows/gradle.yml @@ -0,0 +1,59 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. +# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle + +name: Java CI with Gradle + +on: + push: + branches: [ "develop" ] + pull_request: + branches: [ "develop" ] + +jobs: + build: + + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 11 + uses: actions/setup-java@v4 + with: + java-version: '11' + distribution: 'temurin' + + # Configure Gradle for optimal use in GitHub Actions, including caching of downloaded dependencies. + # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md + - name: Setup Gradle + uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 + + - name: Check + run: ./gradlew check + + - name: Build + run: ./gradlew build + + dependency-submission: + + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK 11 + uses: actions/setup-java@v4 + with: + java-version: '11' + distribution: 'temurin' + + # Generates and submits a dependency graph, enabling Dependabot Alerts for all project dependencies. + # See: https://github.com/gradle/actions/blob/main/dependency-submission/README.md + - name: Generate and submit dependency graph + uses: gradle/actions/dependency-submission@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 From fc959684ba84386451e1f1ad80ebb55a2fd86c74 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 21 Aug 2024 12:09:21 +0200 Subject: [PATCH 17/58] chore: remove dependency-submission (temporarily) --- .github/workflows/gradle.yml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index ede3faa..0aad49f 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -39,21 +39,21 @@ jobs: - name: Build run: ./gradlew build - dependency-submission: - - runs-on: ubuntu-latest - permissions: - contents: write - - steps: - - uses: actions/checkout@v4 - - name: Set up JDK 11 - uses: actions/setup-java@v4 - with: - java-version: '11' - distribution: 'temurin' - - # Generates and submits a dependency graph, enabling Dependabot Alerts for all project dependencies. - # See: https://github.com/gradle/actions/blob/main/dependency-submission/README.md - - name: Generate and submit dependency graph - uses: gradle/actions/dependency-submission@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 +# dependency-submission: +# +# runs-on: ubuntu-latest +# permissions: +# contents: write +# +# steps: +# - uses: actions/checkout@v4 +# - name: Set up JDK 11 +# uses: actions/setup-java@v4 +# with: +# java-version: '11' +# distribution: 'temurin' +# +# # Generates and submits a dependency graph, enabling Dependabot Alerts for all project dependencies. +# # See: https://github.com/gradle/actions/blob/main/dependency-submission/README.md +# - name: Generate and submit dependency graph +# uses: gradle/actions/dependency-submission@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 From eea478a81955ebf5d217b9561d8203941ea45467 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Mon, 26 Aug 2024 16:49:17 +0200 Subject: [PATCH 18/58] fix: CI cleanup --- .github/workflows/gradle.yml | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 0aad49f..8eb8675 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -37,23 +37,4 @@ jobs: run: ./gradlew check - name: Build - run: ./gradlew build - -# dependency-submission: -# -# runs-on: ubuntu-latest -# permissions: -# contents: write -# -# steps: -# - uses: actions/checkout@v4 -# - name: Set up JDK 11 -# uses: actions/setup-java@v4 -# with: -# java-version: '11' -# distribution: 'temurin' -# -# # Generates and submits a dependency graph, enabling Dependabot Alerts for all project dependencies. -# # See: https://github.com/gradle/actions/blob/main/dependency-submission/README.md -# - name: Generate and submit dependency graph -# uses: gradle/actions/dependency-submission@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 + run: ./gradlew build \ No newline at end of file From f824fb2933fa67ea0df0c03c30701e8d43024db3 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Mon, 26 Aug 2024 17:38:31 +0200 Subject: [PATCH 19/58] feat: splitting the main and develop flow --- .github/workflows/gradle.yml | 40 ------------------------------------ 1 file changed, 40 deletions(-) delete mode 100644 .github/workflows/gradle.yml diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml deleted file mode 100644 index 8eb8675..0000000 --- a/.github/workflows/gradle.yml +++ /dev/null @@ -1,40 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle - -name: Java CI with Gradle - -on: - push: - branches: [ "develop" ] - pull_request: - branches: [ "develop" ] - -jobs: - build: - - runs-on: ubuntu-latest - permissions: - contents: read - - steps: - - uses: actions/checkout@v4 - - name: Set up JDK 11 - uses: actions/setup-java@v4 - with: - java-version: '11' - distribution: 'temurin' - - # Configure Gradle for optimal use in GitHub Actions, including caching of downloaded dependencies. - # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md - - name: Setup Gradle - uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0 - - - name: Check - run: ./gradlew check - - - name: Build - run: ./gradlew build \ No newline at end of file From 4508f2de62d5c04431b042e4da46ac38f1704d7f Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 12:40:53 +0300 Subject: [PATCH 20/58] adapt maven central publishing --- build.gradle.kts | 83 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 48f7d6c..57da863 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,6 +12,8 @@ plugins { jacoco id("io.freefair.lombok") version "8.10" id("org.owasp.dependencycheck") version "10.0.3" + id("maven-publish") + id("signing") } group = "zone.cogni.semanticz" @@ -25,6 +27,8 @@ java { toolchain { languageVersion.set(JavaLanguageVersion.of(11)) } + withJavadocJar() + withSourcesJar() } pmd { @@ -69,4 +73,81 @@ tasks.test { tasks.jacocoTestReport { dependsOn(tasks.test) -} \ No newline at end of file +} + +// Copy LICENSE file to the build JAR +tasks.jar { + from("${projectDir}") { + include("LICENSE") + into("/") + } + from("${projectDir}") { + include("LICENSE") + into("META-INF") + } +} + +// Publishing configuration for Maven Central +publishing { + publications { + create("mavenJava") { + from(components["java"]) + + pom { + name.set("Semanticz") + description.set("This project servers for generating IRIs using a predefined template based on existing RDF data.") + url.set("https://github.com/cognizone/semanticz") + + scm { + connection.set("scm:git:git@github.com:cognizone/semanticz.git") + developerConnection.set("scm:git:git@github.com:cognizone/semanticz.git") + url.set("https://github.com/cognizone/semanticz") + } + + licenses { + license { + name.set("The Apache License, Version 2.0") + url.set("http://www.apache.org/licenses/LICENSE-2.0.txt") + } + } + + developers { + developer { + id.set("cognizone") + name.set("Cognizone") + email.set("dev@cognizone.com") + } + } + } + } + } + + repositories { + maven { + name = "Sonatype" + url = uri(if (version.endsWith("SNAPSHOT")) { + "${System.properties['ossrh.url']}/content/repositories/snapshots/" + } else { + "${System.properties['ossrh.url']}/service/local/staging/deploy/maven2/" + }) + credentials { + username = System.properties['ossrh.username'] + password = System.properties['ossrh.password'] + } + } + } +} + +signing { + useInMemoryPgpKeys( + project.findProperty("signing.keyId")?.toString(), + project.findProperty("signing.password")?.toString(), + project.findProperty("signing.secretKeyRingFile")?.toString() + ) + sign(publishing.publications["mavenJava"]) +} + +// Ensure signing task is invoked when publishing +tasks.withType { + dependsOn(tasks.withType()) +} From dde139eab81c88d891087c7b3d5b6b088af24e08 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 12:44:40 +0300 Subject: [PATCH 21/58] Update build.gradle.kts --- build.gradle.kts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 57da863..a9b4142 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -94,8 +94,8 @@ publishing { from(components["java"]) pom { - name.set("Semanticz") - description.set("This project servers for generating IRIs using a predefined template based on existing RDF data.") + name.set("SemanticZ") + description.set("Library for Semantic Development") url.set("https://github.com/cognizone/semanticz") scm { @@ -126,13 +126,13 @@ publishing { maven { name = "Sonatype" url = uri(if (version.endsWith("SNAPSHOT")) { - "${System.properties['ossrh.url']}/content/repositories/snapshots/" + "${System.getProperty("ossrh.url")}/content/repositories/snapshots/" } else { - "${System.properties['ossrh.url']}/service/local/staging/deploy/maven2/" + "${System.getProperty("ossrh.url")}/service/local/staging/deploy/maven2/" }) credentials { - username = System.properties['ossrh.username'] - password = System.properties['ossrh.password'] + username = System.getProperty("ossrh.username") + password = System.getProperty("ossrh.password") } } } From 7b9c749d33e851788c843f9b066348154c3315af Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 12:47:40 +0300 Subject: [PATCH 22/58] Update build.gradle.kts --- build.gradle.kts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index a9b4142..459c4e5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -125,10 +125,10 @@ publishing { repositories { maven { name = "Sonatype" - url = uri(if (version.endsWith("SNAPSHOT")) { - "${System.getProperty("ossrh.url")}/content/repositories/snapshots/" + url = uri(if (version.toString().endsWith("SNAPSHOT")) { + "${System.getProperty("ossrh.url")}/content/repositories/snapshots/" } else { - "${System.getProperty("ossrh.url")}/service/local/staging/deploy/maven2/" + "${System.getProperty("ossrh.url")}/service/local/staging/deploy/maven2/" }) credentials { username = System.getProperty("ossrh.username") From 9f563bdef628e6ea369b5f335ddaf33f3bec9ce1 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 13:51:32 +0300 Subject: [PATCH 23/58] Update build.gradle.kts --- build.gradle.kts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.gradle.kts b/build.gradle.kts index 459c4e5..6c65921 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -137,6 +137,11 @@ publishing { } } } +tasks.withType { + options.addStringOption("Xdoclint:none", "-quiet") + failOnError = false +} + signing { useInMemoryPgpKeys( From 5e04a7d223aa258da88090708221aae35a87fa9a Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 13:53:21 +0300 Subject: [PATCH 24/58] Update build.gradle.kts --- build.gradle.kts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 6c65921..ab2e8c7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -138,11 +138,12 @@ publishing { } } tasks.withType { - options.addStringOption("Xdoclint:none", "-quiet") - failOnError = false + options.addBooleanOption("Xdoclint:none", true) + isFailOnError = false // Use the `isFailOnError` setter for Gradle 8.5 } + signing { useInMemoryPgpKeys( project.findProperty("signing.keyId")?.toString(), From 86dff1521c33da277fb95f92d6f48e4b6cfeb08d Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 13:55:05 +0300 Subject: [PATCH 25/58] Update build.gradle.kts --- build.gradle.kts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index ab2e8c7..ed246be 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -138,12 +138,16 @@ publishing { } } tasks.withType { - options.addBooleanOption("Xdoclint:none", true) - isFailOnError = false // Use the `isFailOnError` setter for Gradle 8.5 + options { + // Suppress all Javadoc lint warnings + addStringOption("Xdoclint:none", "-quiet") + } + isFailOnError = false // Ensure the build doesn't fail on Javadoc warnings or errors } + signing { useInMemoryPgpKeys( project.findProperty("signing.keyId")?.toString(), From 0a2411fcfebb4a5387a195e117e789f762c75612 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 13:56:52 +0300 Subject: [PATCH 26/58] Update build.gradle.kts --- build.gradle.kts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index ed246be..d5302f5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -139,8 +139,8 @@ publishing { } tasks.withType { options { - // Suppress all Javadoc lint warnings - addStringOption("Xdoclint:none", "-quiet") + // Disables all doclint warnings, including HTML errors and missing tags + (this as StandardJavadocDocletOptions).addBooleanOption("Xdoclint:none", true) } isFailOnError = false // Ensure the build doesn't fail on Javadoc warnings or errors } @@ -148,6 +148,7 @@ tasks.withType { + signing { useInMemoryPgpKeys( project.findProperty("signing.keyId")?.toString(), From fce5bb47d6191e841d34394fb0ec5eee3cd4b570 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 13:59:33 +0300 Subject: [PATCH 27/58] Rename LICENSE.txt to LICENSE --- LICENSE.txt => LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename LICENSE.txt => LICENSE (99%) diff --git a/LICENSE.txt b/LICENSE similarity index 99% rename from LICENSE.txt rename to LICENSE index df7f8b1..912c973 100644 --- a/LICENSE.txt +++ b/LICENSE @@ -198,4 +198,4 @@ 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. \ No newline at end of file +limitations under the License. From 9fb9ea53cb4da6cd58d45223fb953b7bec44c916 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 15:05:13 +0300 Subject: [PATCH 28/58] Update build.gradle.kts --- build.gradle.kts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index d5302f5..67f31a4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -99,9 +99,9 @@ publishing { url.set("https://github.com/cognizone/semanticz") scm { - connection.set("scm:git:git@github.com:cognizone/semanticz.git") - developerConnection.set("scm:git:git@github.com:cognizone/semanticz.git") - url.set("https://github.com/cognizone/semanticz") + connection.set("scm:git@github.com:cognizone/semanticz-irigenerator.git") + developerConnection.set("scm:git:git@github.com:cognizone/semanticz-irigenerator.git") + url.set("https://github.com/cognizone/semanticz-irigenerator") } licenses { From bd6a1e6dfab68d7794d8283a0d95d361ff2824ce Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:11:33 +0300 Subject: [PATCH 29/58] Update build.gradle.kts --- build.gradle.kts | 64 ++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 67f31a4..49fd894 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,11 +1,3 @@ -val jenaVersion = "4.10.0" -val springVersion = "5.3.+" -val jakartaAnnotationApiVersion = "3.0.0" -val guavaVersion = "33.3.0-jre" -val jupiterVersion = "5.11.0" -val jb4jsonldJacksonVersion = "0.14.3" -val logbackVersion = "1.5.7" - plugins { `java-library` pmd @@ -14,10 +6,11 @@ plugins { id("org.owasp.dependencycheck") version "10.0.3" id("maven-publish") id("signing") + id("pl.allegro.tech.build.axion-release") version "1.13.3" // Add this plugin } group = "zone.cogni.semanticz" -version = "1.0.0" +version = scmVersion.version // Use version managed by the Axion Release Plugin repositories { mavenCentral() @@ -31,6 +24,25 @@ java { withSourcesJar() } +scmVersion { + tag { + prefix = "v" + versionSeparator = "" + branchPrefix = mapOf( + "release/.*" to "release-v", + "hotfix/.*" to "hotfix-v" + ) + initialVersion = { rules, position -> + "1.0.0-SNAPSHOT" // Customize this to your initial version + } + } + nextVersion { + suffix = "SNAPSHOT" + separator = "-" + } +} + + pmd { isIgnoreFailures = true isConsoleOutput = true @@ -46,8 +58,6 @@ tasks.withType { dependencies { implementation("org.apache.jena:jena-arq:$jenaVersion") implementation("com.google.guava:guava:$guavaVersion") - implementation("org.springframework:spring-core:$springVersion") - implementation("org.springframework:spring-context:$springVersion") implementation("org.springframework:spring-expression:$springVersion") implementation("jakarta.annotation:jakarta.annotation-api:$jakartaAnnotationApiVersion") implementation("cz.cvut.kbss.jsonld:jb4jsonld-jackson:$jb4jsonldJacksonVersion") @@ -94,13 +104,13 @@ publishing { from(components["java"]) pom { - name.set("SemanticZ") - description.set("Library for Semantic Development") + name.set("Semanticz") + description.set("This project servers for generating IRIs using a predefined template based on existing RDF data.") url.set("https://github.com/cognizone/semanticz") - + scm { connection.set("scm:git@github.com:cognizone/semanticz-irigenerator.git") - developerConnection.set("scm:git:git@github.com:cognizone/semanticz-irigenerator.git") + developerConnection.set("scm:git@github.com:cognizone/semanticz-irigenerator.git") url.set("https://github.com/cognizone/semanticz-irigenerator") } @@ -123,20 +133,20 @@ publishing { } repositories { - maven { - name = "Sonatype" - url = uri(if (version.toString().endsWith("SNAPSHOT")) { - "${System.getProperty("ossrh.url")}/content/repositories/snapshots/" - } else { - "${System.getProperty("ossrh.url")}/service/local/staging/deploy/maven2/" - }) - credentials { - username = System.getProperty("ossrh.username") - password = System.getProperty("ossrh.password") + if (project.hasProperty("publishToMavenCentral")) { + maven { + credentials { + username = System.getProperty("ossrh.username") + password = System.getProperty("ossrh.password") + } + def stagingRepoUrl = "${System.getProperty('ossrh.url')}/service/local/staging/deploy/maven2" + def snapshotsRepoUrl = "${System.getProperty('ossrh.url')}/content/repositories/snapshots" + url = if (version.endsWith("SNAPSHOT")) snapshotsRepoUrl else stagingRepoUrl } } } } + tasks.withType { options { // Disables all doclint warnings, including HTML errors and missing tags @@ -155,7 +165,9 @@ signing { project.findProperty("signing.password")?.toString(), project.findProperty("signing.secretKeyRingFile")?.toString() ) - sign(publishing.publications["mavenJava"]) + if (project.hasProperty("publishToMavenCentral")) { + sign(publishing.publications["mavenJava"]) + } } // Ensure signing task is invoked when publishing From fcd9db772ff348b96aa46eb9abb091c636a3b251 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:16:33 +0300 Subject: [PATCH 30/58] Update build.gradle.kts --- build.gradle.kts | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 49fd894..7025a46 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,11 @@ +val jenaVersion = "4.10.0" +val guavaVersion = "33.3.0-jre" +val springVersion = "5.3.+" +val jakartaAnnotationApiVersion = "3.0.0" +val jb4jsonldJacksonVersion = "0.14.3" +val logbackVersion = "1.5.7" +val jupiterVersion = "5.11.0" + plugins { `java-library` pmd @@ -6,11 +14,11 @@ plugins { id("org.owasp.dependencycheck") version "10.0.3" id("maven-publish") id("signing") - id("pl.allegro.tech.build.axion-release") version "1.13.3" // Add this plugin + id("pl.allegro.tech.build.axion-release") version "1.13.3" } group = "zone.cogni.semanticz" -version = scmVersion.version // Use version managed by the Axion Release Plugin +version = scmVersion.version repositories { mavenCentral() @@ -25,24 +33,21 @@ java { } scmVersion { - tag { + tag.apply { prefix = "v" versionSeparator = "" branchPrefix = mapOf( "release/.*" to "release-v", "hotfix/.*" to "hotfix-v" ) - initialVersion = { rules, position -> - "1.0.0-SNAPSHOT" // Customize this to your initial version - } } - nextVersion { + initialVersion = { _, _ -> "1.0.0-SNAPSHOT" } + nextVersion.apply { suffix = "SNAPSHOT" separator = "-" } } - pmd { isIgnoreFailures = true isConsoleOutput = true @@ -85,7 +90,6 @@ tasks.jacocoTestReport { dependsOn(tasks.test) } -// Copy LICENSE file to the build JAR tasks.jar { from("${projectDir}") { include("LICENSE") @@ -97,7 +101,6 @@ tasks.jar { } } -// Publishing configuration for Maven Central publishing { publications { create("mavenJava") { @@ -105,7 +108,7 @@ publishing { pom { name.set("Semanticz") - description.set("This project servers for generating IRIs using a predefined template based on existing RDF data.") + description.set("This project serves for generating IRIs using a predefined template based on existing RDF data.") url.set("https://github.com/cognizone/semanticz") scm { @@ -139,9 +142,9 @@ publishing { username = System.getProperty("ossrh.username") password = System.getProperty("ossrh.password") } - def stagingRepoUrl = "${System.getProperty('ossrh.url')}/service/local/staging/deploy/maven2" - def snapshotsRepoUrl = "${System.getProperty('ossrh.url')}/content/repositories/snapshots" - url = if (version.endsWith("SNAPSHOT")) snapshotsRepoUrl else stagingRepoUrl + val stagingRepoUrl = "${System.getProperty("ossrh.url")}/service/local/staging/deploy/maven2" + val snapshotsRepoUrl = "${System.getProperty("ossrh.url")}/content/repositories/snapshots" + url = uri(if (version.toString().endsWith("SNAPSHOT")) snapshotsRepoUrl else stagingRepoUrl) } } } @@ -149,16 +152,11 @@ publishing { tasks.withType { options { - // Disables all doclint warnings, including HTML errors and missing tags (this as StandardJavadocDocletOptions).addBooleanOption("Xdoclint:none", true) } - isFailOnError = false // Ensure the build doesn't fail on Javadoc warnings or errors + isFailOnError = false } - - - - signing { useInMemoryPgpKeys( project.findProperty("signing.keyId")?.toString(), @@ -170,7 +168,6 @@ signing { } } -// Ensure signing task is invoked when publishing tasks.withType { dependsOn(tasks.withType()) } From 00e07fe5974c9ebb10f93a3134ef059547c67333 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:18:59 +0300 Subject: [PATCH 31/58] Update build.gradle.kts --- build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 7025a46..696180c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -41,7 +41,6 @@ scmVersion { "hotfix/.*" to "hotfix-v" ) } - initialVersion = { _, _ -> "1.0.0-SNAPSHOT" } nextVersion.apply { suffix = "SNAPSHOT" separator = "-" From 8f22f470d8aa3167e52d8dd985a0b1fa311c8423 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:22:24 +0300 Subject: [PATCH 32/58] Update build.gradle.kts --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 696180c..8bcb8da 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,7 +18,7 @@ plugins { } group = "zone.cogni.semanticz" -version = scmVersion.version +version = version = "1.0.0-SNAPSHOT" repositories { mavenCentral() From b1c33782e4fac52eb6c1b2f339b09559808af5be Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:26:49 +0300 Subject: [PATCH 33/58] Update build.gradle.kts --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8bcb8da..983ecae 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,7 +18,7 @@ plugins { } group = "zone.cogni.semanticz" -version = version = "1.0.0-SNAPSHOT" +version = "1.0.0-SNAPSHOT" repositories { mavenCentral() From 26f09c7b10e0cc79edc1f2f027e9ec6349733af1 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:41:41 +0300 Subject: [PATCH 34/58] Update build.gradle.kts --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 983ecae..062fa79 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,7 +18,7 @@ plugins { } group = "zone.cogni.semanticz" -version = "1.0.0-SNAPSHOT" +version = "1.0.0" repositories { mavenCentral() From 0354544f90ce303d2a719f69c6cde7fc932338cf Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:50:37 +0300 Subject: [PATCH 35/58] Update build.gradle.kts --- build.gradle.kts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 062fa79..8d6ca04 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,7 +18,7 @@ plugins { } group = "zone.cogni.semanticz" -version = "1.0.0" +version = "1.0.0-SNAPSHOT" repositories { mavenCentral() @@ -90,10 +90,6 @@ tasks.jacocoTestReport { } tasks.jar { - from("${projectDir}") { - include("LICENSE") - into("/") - } from("${projectDir}") { include("LICENSE") into("META-INF") @@ -106,9 +102,9 @@ publishing { from(components["java"]) pom { - name.set("Semanticz") + name.set("semanticz-irigenerator") description.set("This project serves for generating IRIs using a predefined template based on existing RDF data.") - url.set("https://github.com/cognizone/semanticz") + url.set("https://github.com/cognizone/semanticz-irigenerator") scm { connection.set("scm:git@github.com:cognizone/semanticz-irigenerator.git") From 97713da85780454a63359a2b05363f9f2d44f310 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:53:17 +0300 Subject: [PATCH 36/58] Update build.gradle.kts --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8d6ca04..3a81a36 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,7 +18,7 @@ plugins { } group = "zone.cogni.semanticz" -version = "1.0.0-SNAPSHOT" +version = scmVersion.version repositories { mavenCentral() From 9475c91a3dd4f4d52aa34a07ca54395fb04d2454 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:01:54 +0300 Subject: [PATCH 37/58] Update build.gradle.kts --- build.gradle.kts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 3a81a36..a2ad9ab 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,7 +18,7 @@ plugins { } group = "zone.cogni.semanticz" -version = scmVersion.version + repositories { mavenCentral() @@ -33,6 +33,9 @@ java { } scmVersion { + // Set the current version baseline to 1.0.0 + version = "1.0.0" + tag.apply { prefix = "v" versionSeparator = "" @@ -45,8 +48,10 @@ scmVersion { suffix = "SNAPSHOT" separator = "-" } + versionIncrementer("incrementPatch") } + pmd { isIgnoreFailures = true isConsoleOutput = true From e450a2861491fb78803135c4d422dc25ebfc3a06 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:04:18 +0300 Subject: [PATCH 38/58] Update build.gradle.kts --- build.gradle.kts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index a2ad9ab..d0fca5f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,9 +33,6 @@ java { } scmVersion { - // Set the current version baseline to 1.0.0 - version = "1.0.0" - tag.apply { prefix = "v" versionSeparator = "" @@ -48,10 +45,11 @@ scmVersion { suffix = "SNAPSHOT" separator = "-" } - versionIncrementer("incrementPatch") + versionIncrementer("incrementPatch") // Increment patch version } + pmd { isIgnoreFailures = true isConsoleOutput = true From 47baa0a0eb41c516eaf3c14d839def7d735b0002 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:15:17 +0300 Subject: [PATCH 39/58] Update build.gradle.kts --- build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index d0fca5f..7349e4f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -32,6 +32,7 @@ java { withSourcesJar() } +version = scmVersion.version scmVersion { tag.apply { prefix = "v" @@ -45,7 +46,7 @@ scmVersion { suffix = "SNAPSHOT" separator = "-" } - versionIncrementer("incrementPatch") // Increment patch version + versionIncrementer("incrementPatch") // Increment the patch version } From 69378f5235e4a5763a1267956dd7ec27ccece876 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 28 Aug 2024 10:40:43 +0200 Subject: [PATCH 40/58] Initial commit From b6183b75bca114d7359a1a2ad84199533fe853a3 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 28 Aug 2024 10:45:52 +0200 Subject: [PATCH 41/58] v1.0.0 --- LICENSE.txt | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..df7f8b1 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2024 Cognizone (BV) + +Licensed 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. \ No newline at end of file From be55a8dc0112e6dec3ae35abefddd634d6cc2275 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Mon, 17 Jun 2024 06:11:34 +0200 Subject: [PATCH 42/58] refactor: extracted from asquare rev. f4556f04cad137b90a6534e56b052f6bfac88689 --- .../asquare/cube/spel/NamedTemplate.java | 74 +++++ .../asquare/cube/spel/SpelConfiguration.java | 14 + .../urigenerator/UriGeneratorCalculator.java | 306 ++++++++++++++++++ .../cube/urigenerator/UriGeneratorResult.java | 50 +++ .../cube/urigenerator/UriReplacement.java | 29 ++ .../cube/urigenerator/json/UriGenerator.java | 54 ++++ .../urigenerator/json/UriGeneratorRoot.java | 74 +++++ .../UriGeneratorCalculatorTest.java | 30 ++ .../UriGeneratorCalculatorTestConfig.java | 26 ++ src/test/resources/urigenerator/model.ttl | 8 + .../urigenerator/uri-generators.json5 | 22 ++ 11 files changed, 687 insertions(+) create mode 100644 src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java create mode 100644 src/main/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java create mode 100644 src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java create mode 100644 src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java create mode 100644 src/test/resources/urigenerator/model.ttl create mode 100644 src/test/resources/urigenerator/uri-generators.json5 diff --git a/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java b/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java new file mode 100644 index 0000000..b4e4ce2 --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java @@ -0,0 +1,74 @@ +package zone.cogni.asquare.cube.spel; + +import org.springframework.core.io.Resource; +import zone.cogni.core.spring.ResourceHelper; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class NamedTemplate { + + /** + * might not be stable: uses filename for name !! + */ + public static List fromResources(Resource... resources) { + return Arrays.stream(resources) + .map(NamedTemplate::fromResource) + .collect(Collectors.toList()); + } + + public static NamedTemplate fromResource(Resource resource) { + return fromResource(resource, resource.getFilename()); + } + + public static NamedTemplate fromResource(Resource resource, String name) { + return fromString(ResourceHelper.toString(resource), name); + } + + public static NamedTemplate fromString(String template, String name) { + return new NamedTemplate(template, name); + } + + private final String template; + private final String name; + + private Object root; + private String result; + + protected NamedTemplate(String template, String name) { + this.template = template; + this.name = name; + } + + /** + * @return copy of template part, not result part + */ + public NamedTemplate copy() { + return new NamedTemplate(template, name); + } + + public String getTemplate() { + return template; + } + + public String getName() { + return name; + } + + public Object getRoot() { + return root; + } + + public void setRoot(Object root) { + this.root = root; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } +} diff --git a/src/main/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java b/src/main/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java new file mode 100644 index 0000000..38ad49c --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java @@ -0,0 +1,14 @@ +package zone.cogni.asquare.cube.spel; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SpelConfiguration { + + @Bean(name = "spelService") + public SpelService getSpelService() { + return new SpelService(); + } + +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java new file mode 100644 index 0000000..4d3f512 --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -0,0 +1,306 @@ +package zone.cogni.asquare.cube.urigenerator; + +import org.apache.commons.lang3.StringUtils; +import org.apache.jena.query.Query; +import org.apache.jena.query.QueryFactory; +import org.apache.jena.query.QuerySolutionMap; +import org.apache.jena.query.ResultSet; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.rdf.model.ResourceFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.Resource; +import zone.cogni.asquare.cube.spel.TemplateService; +import zone.cogni.asquare.cube.urigenerator.json.UriGenerator; +import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; +import zone.cogni.asquare.triplestore.RdfStoreService; +import zone.cogni.asquare.triplestore.jenamemory.InternalRdfStoreService; +import zone.cogni.sem.jena.template.JenaResultSetHandlers; + +import javax.annotation.Nonnull; +import java.io.StringWriter; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public class UriGeneratorCalculator { + private static final Logger log = LoggerFactory.getLogger(UriGeneratorCalculator.class); + + private final String newUriPrefix; + private final TemplateService templateService; + private final UriGeneratorRoot uriGeneratorRoot; + private final Map preparedStatements = new HashMap<>(); + + public UriGeneratorCalculator( + String newUriPrefix, + TemplateService templateService, + Resource uriGeneratorRootResource + ) { + this.newUriPrefix = newUriPrefix; + this.templateService = templateService; + this.uriGeneratorRoot = UriGeneratorRoot.load(uriGeneratorRootResource); + initPreparedStatements(); + } + + private void initPreparedStatements() { + preparedStatements.put("exists-uri", QueryFactory.create("ask { { ?x ?p ?o } union { ?s ?p ?x } } ")); + } + + public String createTemporaryUri() { + return newUriPrefix + "/" + UUID.randomUUID(); + } + + public boolean isNewUri(@Nonnull String uri) { + return uri.startsWith(newUriPrefix); + } + + public Model convert(Model model, Map context) { + RdfStoreService rdfStore = getRdfStore(model); + List results = getGeneratorResults(rdfStore); + + int replaceCount = inputValidations(model, results); + processReplacements(model, rdfStore, replaceCount, context, results); + + validate(model); + + return model; + } + + @Nonnull + private List getGeneratorResults(RdfStoreService rdfStore) { + return uriGeneratorRoot.getGenerators() + .stream() + .map(generator -> getUriGeneratorResult(rdfStore, generator)) + .collect(Collectors.toList()); + } + + @Nonnull + private UriGeneratorResult getUriGeneratorResult(RdfStoreService rdfStore, UriGenerator generator) { + UriGeneratorResult uriGeneratorResult = new UriGeneratorResult(); + uriGeneratorResult.setGenerator(generator); + uriGeneratorResult.setUris(getNewSelectorUris(rdfStore, generator)); + return uriGeneratorResult; + } + + /** + * @return number of uris to be replaces + */ + private int inputValidations(Model model, List results) { + Set incomingUris = getProblemUris(model); + + Set selectedUris = new HashSet<>(); + Set duplicates = results.stream() + .flatMap(result -> result.getUris().stream()) + .filter(uri -> !selectedUris.add(uri)) + .collect(Collectors.toSet()); + + if (!duplicates.isEmpty()) + log.error("some uris matched multiple selectors: {}", duplicates); + + int size = incomingUris.size(); + if (size != selectedUris.size()) + log.error("incoming uris and selected uris do not match up." + + "\n\t incoming: {}" + + "\n\t selected: {}", incomingUris, selectedUris); + + if (!duplicates.isEmpty() || size != selectedUris.size()) + throw new RuntimeException("some validations failed when converting new uris, check logs for more info"); + + + log.info("(uri generator) replacing {} uris", size); + return size; + } + + private void processReplacements(Model model, + RdfStoreService rdfStore, + int replaceCount, + Map context, + List results) { + int loopCount = 0; + while (true) { + int count = calculateReplacementUrisLoop(model, rdfStore, context, results); + replaceCount -= count; + + log.info("(uri generator) loop {} processed {} uris", ++loopCount, count); + + // stop loop when all uris are processed + if (replaceCount == 0) break; + + // stop loop when no replacement where processed + if (count == 0) break; + } + } + + private int calculateReplacementUrisLoop(Model model, + RdfStoreService rdfStore, + Map context, + List results) { + AtomicInteger count = new AtomicInteger(); + + results.forEach(result -> { + result.getUris().forEach(uri -> { + if (result.alreadyReplaced(uri)) return; + + Optional possibleNewUri = calculateNewUri(rdfStore, context, result, uri); + if (possibleNewUri.isPresent()) { + count.addAndGet(1); + result.addReplacement(uri, possibleNewUri.get()); + UriReplacement.replace(model, uri, possibleNewUri.get()); + } + }); + }); + + return count.get(); + } + + private Optional calculateNewUri(RdfStoreService rdfStore, + Map context, + UriGeneratorResult result, + String oldUri) { + if (log.isTraceEnabled()) log.trace("calculate new uri for {}", oldUri); + traceModel(rdfStore); + + Map variables = new HashMap<>(context); + variables.put("uri", oldUri); + + // variable template can also NOT exist: then this step is skipped! + String variableSelector = result.getGenerator().getFullVariableSelector(); + if (StringUtils.isNotBlank(variableSelector)) { + String variableTemplateQuery = uriGeneratorRoot.getPrefixQuery() + variableSelector; + String variableQuery = templateService.processTemplate(variableTemplateQuery, variables); + if (log.isTraceEnabled()) log.trace("query: {}", variableQuery); + + Supplier contextSupplier = () -> result.getGenerator().getId(); + Optional> variableMap = getQueryMap(contextSupplier, rdfStore, variableQuery); + + // if one of template variables is still a new URI we should skip calculation for now + if (!variableMap.isPresent()) return Optional.empty(); + + Map map = variableMap.get(); + if (log.isTraceEnabled()) log.trace("query result: {}", map); + variables.putAll(map); + } + if (log.isTraceEnabled()) log.debug("variables: {}", variables); + + String uriTemplate = result.getGenerator().getUriTemplate(); + String newUri = templateService.processTemplate(uriTemplate, variables); + + if (existsInModel(rdfStore, newUri)) + throw new RuntimeException("uri overlap found for " + newUri); + + return Optional.of(newUri); + } + + private void traceModel(RdfStoreService rdfStore) { + if (!log.isTraceEnabled()) return; + + Model trace = rdfStore.executeConstructQuery("construct {?s ?p ?o} where {?s ?p ?o}"); + StringWriter out = new StringWriter(); + trace.write(out, "ttl"); + log.trace("model: {}", out); + } + + private boolean existsInModel(RdfStoreService rdfStore, String newUri) { + QuerySolutionMap querySolution = new QuerySolutionMap(); + querySolution.add("x", ResourceFactory.createResource(newUri)); + + return rdfStore.executeAskQuery(preparedStatements.get("exists-uri"), querySolution); + } + + /** + * @return empty optional if one of resources start with a newUriPrefix ! + * else a map of variables to be used in uri template! + */ + private Optional> getQueryMap(Supplier context, + RdfStoreService rdfStore, + String variableQuery) { + List> rows = queryForListOfMaps(rdfStore, variableQuery); + if (rows.size() != 1) + throw new RuntimeException("[" + context.get() + "] expected 1 row, found " + rows); + + Map nodeMap = rows.get(0); + boolean isBadMatch = nodeMap.values() + .stream() + .peek(node -> nonNullCheck(nodeMap, node)) + .anyMatch(node -> node.isURIResource() + && node.asResource().getURI().startsWith(newUriPrefix)); + if (isBadMatch) return Optional.empty(); + + Map result = new HashMap<>(); + nodeMap.forEach((k, v) -> { + result.put(k, (v.isResource() ? v.asResource().getURI() : v.asLiteral().getString())); + }); + + return Optional.of(result); + } + + private void nonNullCheck(Map nodeMap, RDFNode node) { + if (node == null) throw new RuntimeException("variableSelector result has some null values: " + nodeMap); + } + + private List> queryForListOfMaps(RdfStoreService rdfStore, String variableQuery) { + try { + return rdfStore.executeSelectQuery(variableQuery, JenaResultSetHandlers.listOfMapsResolver); + } + catch (RuntimeException e) { + throw new RuntimeException("Query failed: \n" + variableQuery, e); + } + } + + private Set getNewSelectorUris(RdfStoreService rdfStore, UriGenerator generator) { + String query = uriGeneratorRoot.getPrefixQuery() + generator.getFullUriSelector(); + List uris = getUris(rdfStore, query); + return uris.stream() + .filter(uri -> uri.startsWith(newUriPrefix)) + .collect(Collectors.toSet()); + } + + private List getUris(RdfStoreService rdfStore, String query) { + try { + return rdfStore.executeSelectQuery(query, UriGeneratorCalculator::convertToList); + } + catch (RuntimeException e) { + throw new RuntimeException("problem with query: \n" + query, e); + } + } + + private static List convertToList(ResultSet resultSet) { + List result = new ArrayList<>(); + + resultSet.forEachRemaining(querySolution -> { + result.add(querySolution.get("uri").asResource().getURI()); + }); + + return result; + } + + private RdfStoreService getRdfStore(Model model) { + return new InternalRdfStoreService(model); + } + + private void validate(Model model) { + Set problemUris = getProblemUris(model); + + if (!problemUris.isEmpty()) throw new RuntimeException("some uris could not be replaced: " + problemUris); + } + + @Nonnull + private Set getProblemUris(Model model) { + Set problemUris = new HashSet<>(); + model.listStatements() + .forEachRemaining(statement -> { + if (statement.getSubject().getURI().startsWith(newUriPrefix)) { + problemUris.add(statement.getSubject().getURI()); + } + + if (statement.getObject().isURIResource() + && statement.getObject().asResource().getURI().startsWith(newUriPrefix)) { + problemUris.add(statement.getObject().asResource().getURI()); + } + }); + return problemUris; + } + +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java new file mode 100644 index 0000000..789fa05 --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java @@ -0,0 +1,50 @@ +package zone.cogni.asquare.cube.urigenerator; + + +import zone.cogni.asquare.cube.urigenerator.json.UriGenerator; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class UriGeneratorResult { + + private UriGenerator generator; + private Set uris; + private Map replacements = new HashMap<>(); + + public UriGeneratorResult() { + } + + public UriGenerator getGenerator() { + return generator; + } + + public void setGenerator(UriGenerator generator) { + this.generator = generator; + } + + public Set getUris() { + return uris; + } + + public void setUris(Set uris) { + this.uris = uris; + } + + public Map getReplacements() { + return replacements; + } + + public void setReplacements(Map replacements) { + this.replacements = replacements; + } + + public boolean alreadyReplaced(String oldUri) { + return replacements.containsKey(oldUri); + } + + public void addReplacement(String oldUri, String newUri) { + replacements.put(oldUri, newUri); + } +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java new file mode 100644 index 0000000..5d45f1b --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java @@ -0,0 +1,29 @@ +package zone.cogni.asquare.cube.urigenerator; + +import org.apache.jena.rdf.model.*; + +import java.util.List; + +public class UriReplacement { + + public static void replace(Model model, String original, String replacement) { + Resource originalResource = ResourceFactory.createResource(original); + Resource replacementResource = ResourceFactory.createResource(replacement); + + List leftStatements = model.listStatements(originalResource, null, (RDFNode) null).toList(); + model.remove(leftStatements); + + leftStatements.forEach(statement -> { + model.add(replacementResource, statement.getPredicate(), statement.getObject()); + }); + + + List rightStatements = model.listStatements(null, null, originalResource).toList(); + model.remove(rightStatements); + + rightStatements.forEach(statement -> { + model.add(statement.getSubject(), statement.getPredicate(), replacementResource); + }); + } + +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java new file mode 100644 index 0000000..a1fbe4b --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java @@ -0,0 +1,54 @@ +package zone.cogni.asquare.cube.urigenerator.json; + +public class UriGenerator { + + private String id; + private String uriSelector; + private String variableSelector; + private String uriTemplate; + + public UriGenerator() { + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getUriSelector() { + return uriSelector; + } + + public void setUriSelector(String uriSelector) { + this.uriSelector = uriSelector; + } + + public String getVariableSelector() { + return variableSelector; + } + + public void setVariableSelector(String variableSelector) { + this.variableSelector = variableSelector; + } + + public String getUriTemplate() { + return uriTemplate; + } + + public void setUriTemplate(String uriTemplate) { + this.uriTemplate = uriTemplate; + } + + public String getFullUriSelector() { + if (uriSelector == null) return ""; + return uriSelector; + } + + public String getFullVariableSelector() { + if (variableSelector == null) return ""; + return variableSelector; + } +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java new file mode 100644 index 0000000..f45c84d --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java @@ -0,0 +1,74 @@ +package zone.cogni.asquare.cube.urigenerator.json; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.io.InputStreamSource; +import org.springframework.core.io.Resource; +import zone.cogni.asquare.cube.json5.Json5Light; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class UriGeneratorRoot { + + public static UriGeneratorRoot load(InputStreamSource resource) { + try { + ObjectMapper mapper = Json5Light.getJson5Mapper(); + UriGeneratorRoot result = mapper.readValue(resource.getInputStream(), UriGeneratorRoot.class); + +// result.validate(); + return result; + } + catch (IOException e) { + String extra = getPath(resource) != null ? " Path " + getPath(resource) : ""; + throw new RuntimeException("Unable to load uri generator configuration." + extra, e); + } + } + + private static String getPath(InputStreamSource resource) { + try { + if (resource instanceof Resource) { + Resource r = (Resource) resource; + return r.getFile().getPath(); + } + } + catch (IOException e) { + return null; + } + return null; + } + + private Map prefixes; + private List generators; + + public UriGeneratorRoot() { + } + + public Map getPrefixes() { + return prefixes; + } + + public void setPrefixes(Map prefixes) { + this.prefixes = prefixes; + } + + public List getGenerators() { + return generators; + } + + public void setGenerators(List generators) { + this.generators = generators; + } + + public String getPrefixQuery() { + return prefixes.entrySet() + .stream() + .map(e -> "PREFIX " + + StringUtils.rightPad(e.getKey() + ":", 8) + " <" + e.getValue() + ">\n") + .collect(Collectors.joining()) + + "\n"; + } + +} diff --git a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java new file mode 100644 index 0000000..2ef91f5 --- /dev/null +++ b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java @@ -0,0 +1,30 @@ +package zone.cogni.asquare.cube.urigenerator; + +import com.google.common.collect.ImmutableMap; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ResourceFactory; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.io.ClassPathResource; +import zone.cogni.sem.jena.JenaUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest(classes = UriGeneratorCalculatorTestConfig.class) +public class UriGeneratorCalculatorTest { + + @Autowired + UriGeneratorCalculator uriCalculator; + + @Test + public void test_uris_converted() { + //given + Model model = JenaUtils.read(new ClassPathResource("urigenerator/model.ttl")); + //when + Model converted = uriCalculator.convert(model, ImmutableMap.of("baseUri", "http://asquare.cogni.zone")); + //then + assertThat(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/5"))); + assertThat(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/2021/0005"))); + } +} diff --git a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java new file mode 100644 index 0000000..ea38dab --- /dev/null +++ b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java @@ -0,0 +1,26 @@ +package zone.cogni.asquare.cube.urigenerator; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import zone.cogni.asquare.cube.spel.SpelService; + +@Configuration +@Import(SpelService.class) +public class UriGeneratorCalculatorTestConfig { + + @Autowired + private SpelService spelService; + + @Bean + public UriGeneratorCalculator uriCalculator() { + Resource uriGeneratorsResource = new ClassPathResource("urigenerator/uri-generators.json5"); + return new UriGeneratorCalculator("http://resource", + spelService, + uriGeneratorsResource); + } +} + diff --git a/src/test/resources/urigenerator/model.ttl b/src/test/resources/urigenerator/model.ttl new file mode 100644 index 0000000..efd8442 --- /dev/null +++ b/src/test/resources/urigenerator/model.ttl @@ -0,0 +1,8 @@ +@prefix demo: . + + a demo:One ; + demo:id "5" . + + a demo:Two ; + demo:year "2021" ; + demo:sequence "0005" . \ No newline at end of file diff --git a/src/test/resources/urigenerator/uri-generators.json5 b/src/test/resources/urigenerator/uri-generators.json5 new file mode 100644 index 0000000..ba71dad --- /dev/null +++ b/src/test/resources/urigenerator/uri-generators.json5 @@ -0,0 +1,22 @@ +{ + prefixes: { + demo: "http://demo.com/model#" + }, + generators: [ + { + id: "One", + uriSelector: "select ?uri { ?uri a demo:One }", + variableSelector: "select ?id where { <#{[uri]}> demo:id ?id }", + uriTemplate: "#{[baseUri]}/#{[id]}" + }, + { + id: "Two", + uriSelector: "select ?uri { ?uri a demo:Two }", + variableSelector: "select ?year ?sequence where { \ + <#{[uri]}> demo:year ?year ; \ + demo:sequence ?sequence \ + }", + uriTemplate: "#{[baseUri]}/#{[year]}/#{[sequence]}" + } + ] +} \ No newline at end of file From e0accac3fc0f625e357a0efacb140e1e14589ef6 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 19 Jun 2024 10:30:00 +0200 Subject: [PATCH 43/58] refactor: made independent on asquare --- .../asquare/cube/spel/NamedTemplate.java | 51 ---- .../urigenerator/UriGeneratorCalculator.java | 2 +- .../asquare/triplestore/RdfStoreService.java | 43 +++ .../jenamemory/InternalRdfStoreService.java | 124 +++++++++ .../cogni/core/spring/ResourceHelper.java | 46 ++++ .../java/zone/cogni/core/util/FileHelper.java | 45 ++++ .../java/zone/cogni/core/util/IOHelper.java | 24 ++ .../zone/cogni/sem/jena/AutoCloseModels.java | 26 ++ .../java/zone/cogni/sem/jena/JenaUtils.java | 251 ++++++++++++++++++ .../jena/template/JenaResultSetHandlers.java | 16 ++ 10 files changed, 576 insertions(+), 52 deletions(-) create mode 100644 src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java create mode 100644 src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java create mode 100644 src/main/java/zone/cogni/core/spring/ResourceHelper.java create mode 100644 src/main/java/zone/cogni/core/util/FileHelper.java create mode 100644 src/main/java/zone/cogni/core/util/IOHelper.java create mode 100644 src/main/java/zone/cogni/sem/jena/AutoCloseModels.java create mode 100644 src/main/java/zone/cogni/sem/jena/JenaUtils.java create mode 100644 src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java diff --git a/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java b/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java index b4e4ce2..a341aad 100644 --- a/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java +++ b/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java @@ -1,41 +1,10 @@ package zone.cogni.asquare.cube.spel; -import org.springframework.core.io.Resource; -import zone.cogni.core.spring.ResourceHelper; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - public class NamedTemplate { - /** - * might not be stable: uses filename for name !! - */ - public static List fromResources(Resource... resources) { - return Arrays.stream(resources) - .map(NamedTemplate::fromResource) - .collect(Collectors.toList()); - } - - public static NamedTemplate fromResource(Resource resource) { - return fromResource(resource, resource.getFilename()); - } - - public static NamedTemplate fromResource(Resource resource, String name) { - return fromString(ResourceHelper.toString(resource), name); - } - - public static NamedTemplate fromString(String template, String name) { - return new NamedTemplate(template, name); - } - private final String template; private final String name; - private Object root; - private String result; - protected NamedTemplate(String template, String name) { this.template = template; this.name = name; @@ -51,24 +20,4 @@ public NamedTemplate copy() { public String getTemplate() { return template; } - - public String getName() { - return name; - } - - public Object getRoot() { - return root; - } - - public void setRoot(Object root) { - this.root = root; - } - - public String getResult() { - return result; - } - - public void setResult(String result) { - this.result = result; - } } diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java index 4d3f512..497f01f 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -18,7 +18,7 @@ import zone.cogni.asquare.triplestore.jenamemory.InternalRdfStoreService; import zone.cogni.sem.jena.template.JenaResultSetHandlers; -import javax.annotation.Nonnull; +import jakarta.annotation.Nonnull; import java.io.StringWriter; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; diff --git a/src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java b/src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java new file mode 100644 index 0000000..b3416db --- /dev/null +++ b/src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java @@ -0,0 +1,43 @@ +package zone.cogni.asquare.triplestore; + + +import org.apache.jena.query.Query; +import org.apache.jena.query.QueryFactory; +import org.apache.jena.query.QuerySolutionMap; +import org.apache.jena.query.Syntax; +import org.apache.jena.rdf.model.Model; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import zone.cogni.sem.jena.template.JenaResultSetHandler; + +import java.io.Closeable; + +public interface RdfStoreService extends Closeable { + + Logger log = LoggerFactory.getLogger(RdfStoreService.class); + + @Override + default void close() { + log.info("Closing RdfStoreService ({}) : {}", getClass().getName(), this); + } + + R executeSelectQuery(Query query, QuerySolutionMap bindings, JenaResultSetHandler resultSetHandler, String context); + + default R executeSelectQuery(String query, JenaResultSetHandler resultSetHandler, String context) { + Query parsedQuery = QueryFactory.create(query, Syntax.syntaxARQ); + return executeSelectQuery(parsedQuery, new QuerySolutionMap(), resultSetHandler, context); + } + + default R executeSelectQuery(String query, JenaResultSetHandler resultSetHandler) { + return executeSelectQuery(query, resultSetHandler, null); + } + + boolean executeAskQuery(Query query, QuerySolutionMap bindings); + + Model executeConstructQuery(Query query, QuerySolutionMap bindings); + + default Model executeConstructQuery(String query) { + Query parsedQuery = QueryFactory.create(query, Syntax.syntaxARQ); + return executeConstructQuery(parsedQuery, new QuerySolutionMap()); + } +} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java b/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java new file mode 100644 index 0000000..3954a0b --- /dev/null +++ b/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java @@ -0,0 +1,124 @@ +package zone.cogni.asquare.triplestore.jenamemory; + +import org.apache.commons.lang3.StringUtils; +import org.apache.jena.query.*; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.shared.Lock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.support.ResourcePatternResolver; +import zone.cogni.asquare.triplestore.RdfStoreService; +import zone.cogni.core.spring.ResourceHelper; +import zone.cogni.sem.jena.JenaUtils; +import zone.cogni.sem.jena.template.JenaResultSetHandler; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.function.Supplier; + +public class InternalRdfStoreService implements RdfStoreService { + + private static final Logger log = LoggerFactory.getLogger(InternalRdfStoreService.class); + + private final Model model; + + private ResourcePatternResolver resourcePatternResolver; + private String preLoadLocations; + private String savePath; + + private File storeFile; + private File tempStoreFile; + + public InternalRdfStoreService(Model model) { + this.model = model; + } + + @PostConstruct + private void init() { + if (StringUtils.isNotBlank(savePath)) { + storeFile = new File(savePath, "store.rdf"); + tempStoreFile = new File(savePath, "temp-store.rdf"); + storeFile.getParentFile().mkdirs(); + + if (storeFile.isFile()) JenaUtils.readInto(storeFile, model); + } + + if (resourcePatternResolver == null || StringUtils.isBlank(preLoadLocations)) return; + + Arrays.stream(StringUtils.split(preLoadLocations, ',')).forEach(location -> { + log.info("Loading RDF file {}.", location); + Arrays.stream(ResourceHelper.getResources(resourcePatternResolver, location)).forEach(resource -> { + try (InputStream inputStream = resource.getInputStream()) { + model.read(inputStream, null, JenaUtils.getLangByResourceName(location)); + } + catch (IOException e) { + throw new RuntimeException(e); + } + }); + }); + } + + @Override + public R executeSelectQuery(Query query, QuerySolutionMap bindings, JenaResultSetHandler resultSetHandler, String context) { + return executeInLock(Lock.READ, () -> { + if (log.isTraceEnabled()) log.trace("Select {} - {} \n{}", + context == null ? "" : "--- " + context + " --- ", + bindings, + query); + + try (QueryExecution queryExecution = QueryExecutionFactory.create(query, model, bindings)) { + ResultSet resultSet = queryExecution.execSelect(); + return resultSetHandler.handle(resultSet); + } + catch (RuntimeException e) { + log.error("Query failed: {}", query); + throw e; + } + }); + } + + @Override + public boolean executeAskQuery(Query query, QuerySolutionMap bindings) { + return executeInLock(Lock.READ, () -> { + try (QueryExecution queryExecution = QueryExecutionFactory.create(query, model, bindings)) { + return queryExecution.execAsk(); + } + catch (RuntimeException e) { + log.error("Query failed: {}", query); + throw e; + } + }); + } + + @Override + public Model executeConstructQuery(Query query, QuerySolutionMap bindings) { + return executeInLock(Lock.READ, () -> { + try (QueryExecution queryExecution = QueryExecutionFactory.create(query, model, bindings)) { + if (log.isTraceEnabled()) log.trace("Running construct query: \n{}", query); + return queryExecution.execConstruct(); + } + catch (RuntimeException e) { + log.error("Query failed: {}", query); + throw e; + } + }); + } + + private T executeInLock(boolean lock, Supplier executeInLock) { + model.enterCriticalSection(lock); + try { + return executeInLock.get(); + } + finally { + model.leaveCriticalSection(); + } + } + + public Model getModel() { + return model; + } + +} diff --git a/src/main/java/zone/cogni/core/spring/ResourceHelper.java b/src/main/java/zone/cogni/core/spring/ResourceHelper.java new file mode 100644 index 0000000..d194871 --- /dev/null +++ b/src/main/java/zone/cogni/core/spring/ResourceHelper.java @@ -0,0 +1,46 @@ +package zone.cogni.core.spring; + +import org.apache.commons.io.IOUtils; +import org.springframework.core.io.InputStreamSource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.ResourcePatternResolver; + +import java.io.IOException; +import java.io.InputStream; + +public class ResourceHelper { + + public static Resource[] getResources(ResourcePatternResolver applicationContext, String locationPattern) { + try { + return applicationContext.getResources(locationPattern); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static String toString(InputStreamSource resource) { + return toString(resource, "UTF-8"); + } + + public static String toString(InputStreamSource resource, String encoding) { + try (InputStream inputStream = resource.getInputStream()) { + return IOUtils.toString(inputStream, encoding); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static InputStream getInputStream(T resource) { + try { + return resource.getInputStream(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + private ResourceHelper() { + } +} diff --git a/src/main/java/zone/cogni/core/util/FileHelper.java b/src/main/java/zone/cogni/core/util/FileHelper.java new file mode 100644 index 0000000..cef687d --- /dev/null +++ b/src/main/java/zone/cogni/core/util/FileHelper.java @@ -0,0 +1,45 @@ +package zone.cogni.core.util; + +import com.google.common.io.Files; +import org.apache.commons.io.FileUtils; + +import javax.annotation.Nonnull; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +public class FileHelper { + private FileHelper() { + } + + public static FileInputStream openInputStream(File file) { + try { + return new FileInputStream(file); + } + catch (FileNotFoundException e) { + throw new RuntimeException(e); + } + } + + public static FileOutputStream openOutputStream(@Nonnull File file) { + try { + Files.createParentDirs(file); + return FileUtils.openOutputStream(file); + } + catch (IOException e) { + throw new RuntimeException( "Failed to open outputstream to " + file, e); + } + } + + @Deprecated + public static void writeStringToFile(File file, String data) { + try { + FileUtils.writeStringToFile(file, data); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/zone/cogni/core/util/IOHelper.java b/src/main/java/zone/cogni/core/util/IOHelper.java new file mode 100644 index 0000000..ad14e59 --- /dev/null +++ b/src/main/java/zone/cogni/core/util/IOHelper.java @@ -0,0 +1,24 @@ +package zone.cogni.core.util; + + +import java.io.Closeable; +import java.io.Flushable; +import java.io.IOException; + +public class IOHelper { + public static void flushAndClose(X closeFlusher) { + if (closeFlusher == null) return; + + try { + closeFlusher.flush(); + } + catch (IOException ignore) { + } + + try { + closeFlusher.close(); + } + catch (IOException ignore) { + } + } +} diff --git a/src/main/java/zone/cogni/sem/jena/AutoCloseModels.java b/src/main/java/zone/cogni/sem/jena/AutoCloseModels.java new file mode 100644 index 0000000..f9c982d --- /dev/null +++ b/src/main/java/zone/cogni/sem/jena/AutoCloseModels.java @@ -0,0 +1,26 @@ +package zone.cogni.sem.jena; + +import org.apache.jena.rdf.model.Model; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; + +public class AutoCloseModels implements AutoCloseable { + + private final Collection models = new ArrayList<>(); + + public AutoCloseModels(Model... models) { + this.models.addAll(Arrays.asList(models)); + } + + public Model add(Model model) { + models.add(model); + return model; + } + + @Override + public void close() { + JenaUtils.closeQuietly(models); + } +} diff --git a/src/main/java/zone/cogni/sem/jena/JenaUtils.java b/src/main/java/zone/cogni/sem/jena/JenaUtils.java new file mode 100644 index 0000000..415be2f --- /dev/null +++ b/src/main/java/zone/cogni/sem/jena/JenaUtils.java @@ -0,0 +1,251 @@ +package zone.cogni.sem.jena; + +import com.google.common.base.Preconditions; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.jena.rdf.model.AnonId; +import org.apache.jena.rdf.model.Literal; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.RDFErrorHandler; +import org.apache.jena.rdf.model.RDFNode; +import org.apache.jena.rdf.model.RDFReaderI; +import org.apache.jena.rdf.model.RDFVisitor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.Resource; +import zone.cogni.core.spring.ResourceHelper; +import zone.cogni.core.util.FileHelper; +import zone.cogni.core.util.IOHelper; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +@Deprecated +public class JenaUtils { + private static final Logger log = LoggerFactory.getLogger(JenaUtils.class); + private static final Map extensionToLanguageMap = Collections.synchronizedMap(new HashMap<>()); + + static { + extensionToLanguageMap.put("nt", "N-TRIPLE"); + extensionToLanguageMap.put("n3", "N3"); + extensionToLanguageMap.put("ttl", "TURTLE"); + extensionToLanguageMap.put("jsonld", "JSONLD"); + } + + private JenaUtils() { + } + + public static Model read(Resource... resources) { + return read(Arrays.asList(resources)); + } + + public static Model read(Iterable resources) { + return read(resources, null); + } + + public static Model read(Iterable resources, Map readerProperties) { + Model model = ModelFactory.createDefaultModel(); + + for (Resource resource : resources) { + InputStream inputstream = null; + try { + inputstream = ResourceHelper.getInputStream(resource); + InternalRdfErrorHandler errorHandler = new InternalRdfErrorHandler(resource.getDescription()); + + RDFReaderI rdfReader = getReader(model, resource, errorHandler, readerProperties); + rdfReader.read(model, inputstream, null); + + Preconditions.checkState(!errorHandler.isFailure(), errorHandler.getInfo()); + } + catch (RuntimeException e) { + closeQuietly(model); + + throw e; + } + finally { + IOUtils.closeQuietly(inputstream); + } + } + + return model; + } + + private static RDFReaderI getReader(Model model, Resource resource, RDFErrorHandler rdfErrorHandler, Map readerProperties) { + return getReader(model, rdfErrorHandler, readerProperties, getRdfSyntax(resource)); + } + + private static RDFReaderI getReader(Model model, RDFErrorHandler rdfErrorHandler, Map readerProperties, String language) { + RDFReaderI rdfReader = getReaderByRdfSyntax(model, language); + rdfReader.setErrorHandler(rdfErrorHandler); + if (readerProperties == null) return rdfReader; + + for (String propertyName : readerProperties.keySet()) { + rdfReader.setProperty(propertyName, readerProperties.get(propertyName)); + } + return rdfReader; + } + + private static RDFReaderI getReaderByRdfSyntax(Model model, String language) { + try { + return model.getReader(language); + } + catch (IllegalStateException ignored) { + return model.getReader(); + } + } + + private static String getRdfSyntax(org.springframework.core.io.Resource resource) { + String extension = StringUtils.lowerCase(StringUtils.substringAfterLast(resource.getFilename(), ".")); + + // when return value is null, fall back to RDF/XML + return extensionToLanguageMap.getOrDefault(extension, null); + } + + public static void write(Model model, File file) { + write(model, FileHelper.openOutputStream(file)); + } + + public static void write(Model model, OutputStream out) { + try { + model.write(out); + } + finally { + IOHelper.flushAndClose(out); + } + } + + public static String toString(Model model) { + return toString(model, "RDF/XML"); + } + + public static String toString(Model model, String language) { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + model.write(out, language); + + return out.toString("UTF-8"); + } + catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + + public static void closeQuietly(Model... models) { + Arrays.stream(models).filter(Objects::nonNull).filter(model -> !model.isClosed()).forEach(model -> { + try { + model.close(); + } + catch (Exception e) { + log.warn("Closing model failed.", e); + } + }); + } + + public static void closeQuietly(Iterable models) { + for (Model model : models) { + if (model == null) { + continue; + } + + if (model.isClosed()) { + log.warn("Closing an already closed model."); + continue; + } + + try { + model.close(); + } + catch (Exception e) { + log.warn("Closing model failed.", e); + } + } + } + + public static Model readInto(File file, Model model) { + return readInto(file, model, getLangByResourceName(file.getName())); + } + + public static String getLangByResourceName(String resourceName) { + String ext = FilenameUtils.getExtension(resourceName); + if (ext.equalsIgnoreCase("ttl")) return "TTL"; + //TODO: add other types + return null; + } + + public static Model readInto(File file, Model model, String lang) { + try (InputStream inputStream = FileHelper.openInputStream(file)) { + return readInto(inputStream, file.getAbsolutePath(), model, lang); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + public static Model readInto(InputStream inputStream, String streamName, Model model, String lang) { + try { + RDFReaderI reader = model.getReader(lang); + InternalRdfErrorHandler errorHandler = new InternalRdfErrorHandler(streamName); + reader.setErrorHandler(errorHandler); + reader.read(model, inputStream, null); + + Preconditions.checkState(errorHandler.isFailure(), errorHandler.getInfo()); + return model; + } + finally { + IOUtils.closeQuietly(inputStream); + } + } + + private static class InternalRdfErrorHandler implements RDFErrorHandler { + + private final String info; + private boolean failure; + + private InternalRdfErrorHandler(String loadedFile) { + info = "Load rdf file (" + loadedFile + ") problem."; + } + + public boolean isFailure() { + return failure; + } + + public String getInfo() { + return info; + } + + @Override + public void warning(Exception e) { + String message = e.getMessage(); + if (null != message && message.contains("ISO-639 does not define language:")) { + log.warn("{}: {}", info, message); + return; + } + log.warn(info, e); + } + + @Override + public void error(Exception e) { + failure = true; + log.error(info, e); + } + + @Override + public void fatalError(Exception e) { + failure = true; + log.error(info, e); + } + } +} + diff --git a/src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java b/src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java new file mode 100644 index 0000000..16a4809 --- /dev/null +++ b/src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java @@ -0,0 +1,16 @@ +package zone.cogni.sem.jena.template; + + +import org.apache.jena.rdf.model.RDFNode; + +import java.util.List; +import java.util.Map; + +public final class JenaResultSetHandlers { + + public static final JenaResultSetHandler>> listOfMapsResolver = JenaQueryUtils::convertToListOfMaps; + + private JenaResultSetHandlers() { + throw new AssertionError("Should not be initialized!"); + } +} From 4d96c810e1182685910097e54a4ee0dd8ca55478 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 19 Jun 2024 11:58:13 +0200 Subject: [PATCH 44/58] refactor: simplification + removing buildtime dependency on Spring --- .../asquare/cube/spel/NamedTemplate.java | 23 ---------- .../urigenerator/UriGeneratorCalculator.java | 12 +---- .../cube/urigenerator/UriGeneratorResult.java | 8 ---- .../jenamemory/InternalRdfStoreService.java | 46 ------------------- .../cogni/core/spring/ResourceHelper.java | 11 ----- .../zone/cogni/sem/jena/AutoCloseModels.java | 26 ----------- .../java/zone/cogni/sem/jena/JenaUtils.java | 20 -------- .../jena/template/JenaResultSetHandlers.java | 16 ------- .../asquare/cube/spel/SpelConfiguration.java | 0 9 files changed, 2 insertions(+), 160 deletions(-) delete mode 100644 src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java delete mode 100644 src/main/java/zone/cogni/sem/jena/AutoCloseModels.java delete mode 100644 src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java rename src/{main => test}/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java (100%) diff --git a/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java b/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java deleted file mode 100644 index a341aad..0000000 --- a/src/main/java/zone/cogni/asquare/cube/spel/NamedTemplate.java +++ /dev/null @@ -1,23 +0,0 @@ -package zone.cogni.asquare.cube.spel; - -public class NamedTemplate { - - private final String template; - private final String name; - - protected NamedTemplate(String template, String name) { - this.template = template; - this.name = name; - } - - /** - * @return copy of template part, not result part - */ - public NamedTemplate copy() { - return new NamedTemplate(template, name); - } - - public String getTemplate() { - return template; - } -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java index 497f01f..772b38d 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -16,7 +16,7 @@ import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; import zone.cogni.asquare.triplestore.RdfStoreService; import zone.cogni.asquare.triplestore.jenamemory.InternalRdfStoreService; -import zone.cogni.sem.jena.template.JenaResultSetHandlers; +import zone.cogni.sem.jena.template.JenaQueryUtils; import jakarta.annotation.Nonnull; import java.io.StringWriter; @@ -48,14 +48,6 @@ private void initPreparedStatements() { preparedStatements.put("exists-uri", QueryFactory.create("ask { { ?x ?p ?o } union { ?s ?p ?x } } ")); } - public String createTemporaryUri() { - return newUriPrefix + "/" + UUID.randomUUID(); - } - - public boolean isNewUri(@Nonnull String uri) { - return uri.startsWith(newUriPrefix); - } - public Model convert(Model model, Map context) { RdfStoreService rdfStore = getRdfStore(model); List results = getGeneratorResults(rdfStore); @@ -242,7 +234,7 @@ private void nonNullCheck(Map nodeMap, RDFNode node) { private List> queryForListOfMaps(RdfStoreService rdfStore, String variableQuery) { try { - return rdfStore.executeSelectQuery(variableQuery, JenaResultSetHandlers.listOfMapsResolver); + return rdfStore.executeSelectQuery(variableQuery, JenaQueryUtils::convertToListOfMaps); } catch (RuntimeException e) { throw new RuntimeException("Query failed: \n" + variableQuery, e); diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java index 789fa05..a91846e 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java @@ -32,14 +32,6 @@ public void setUris(Set uris) { this.uris = uris; } - public Map getReplacements() { - return replacements; - } - - public void setReplacements(Map replacements) { - this.replacements = replacements; - } - public boolean alreadyReplaced(String oldUri) { return replacements.containsKey(oldUri); } diff --git a/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java b/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java index 3954a0b..6f3531e 100644 --- a/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java +++ b/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java @@ -1,22 +1,13 @@ package zone.cogni.asquare.triplestore.jenamemory; -import org.apache.commons.lang3.StringUtils; import org.apache.jena.query.*; import org.apache.jena.rdf.model.Model; import org.apache.jena.shared.Lock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.core.io.support.ResourcePatternResolver; import zone.cogni.asquare.triplestore.RdfStoreService; -import zone.cogni.core.spring.ResourceHelper; -import zone.cogni.sem.jena.JenaUtils; import zone.cogni.sem.jena.template.JenaResultSetHandler; -import javax.annotation.PostConstruct; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; import java.util.function.Supplier; public class InternalRdfStoreService implements RdfStoreService { @@ -25,42 +16,10 @@ public class InternalRdfStoreService implements RdfStoreService { private final Model model; - private ResourcePatternResolver resourcePatternResolver; - private String preLoadLocations; - private String savePath; - - private File storeFile; - private File tempStoreFile; - public InternalRdfStoreService(Model model) { this.model = model; } - @PostConstruct - private void init() { - if (StringUtils.isNotBlank(savePath)) { - storeFile = new File(savePath, "store.rdf"); - tempStoreFile = new File(savePath, "temp-store.rdf"); - storeFile.getParentFile().mkdirs(); - - if (storeFile.isFile()) JenaUtils.readInto(storeFile, model); - } - - if (resourcePatternResolver == null || StringUtils.isBlank(preLoadLocations)) return; - - Arrays.stream(StringUtils.split(preLoadLocations, ',')).forEach(location -> { - log.info("Loading RDF file {}.", location); - Arrays.stream(ResourceHelper.getResources(resourcePatternResolver, location)).forEach(resource -> { - try (InputStream inputStream = resource.getInputStream()) { - model.read(inputStream, null, JenaUtils.getLangByResourceName(location)); - } - catch (IOException e) { - throw new RuntimeException(e); - } - }); - }); - } - @Override public R executeSelectQuery(Query query, QuerySolutionMap bindings, JenaResultSetHandler resultSetHandler, String context) { return executeInLock(Lock.READ, () -> { @@ -116,9 +75,4 @@ private T executeInLock(boolean lock, Supplier executeInLock) { model.leaveCriticalSection(); } } - - public Model getModel() { - return model; - } - } diff --git a/src/main/java/zone/cogni/core/spring/ResourceHelper.java b/src/main/java/zone/cogni/core/spring/ResourceHelper.java index d194871..114b067 100644 --- a/src/main/java/zone/cogni/core/spring/ResourceHelper.java +++ b/src/main/java/zone/cogni/core/spring/ResourceHelper.java @@ -2,23 +2,12 @@ import org.apache.commons.io.IOUtils; import org.springframework.core.io.InputStreamSource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.ResourcePatternResolver; import java.io.IOException; import java.io.InputStream; public class ResourceHelper { - public static Resource[] getResources(ResourcePatternResolver applicationContext, String locationPattern) { - try { - return applicationContext.getResources(locationPattern); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - public static String toString(InputStreamSource resource) { return toString(resource, "UTF-8"); } diff --git a/src/main/java/zone/cogni/sem/jena/AutoCloseModels.java b/src/main/java/zone/cogni/sem/jena/AutoCloseModels.java deleted file mode 100644 index f9c982d..0000000 --- a/src/main/java/zone/cogni/sem/jena/AutoCloseModels.java +++ /dev/null @@ -1,26 +0,0 @@ -package zone.cogni.sem.jena; - -import org.apache.jena.rdf.model.Model; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; - -public class AutoCloseModels implements AutoCloseable { - - private final Collection models = new ArrayList<>(); - - public AutoCloseModels(Model... models) { - this.models.addAll(Arrays.asList(models)); - } - - public Model add(Model model) { - models.add(model); - return model; - } - - @Override - public void close() { - JenaUtils.closeQuietly(models); - } -} diff --git a/src/main/java/zone/cogni/sem/jena/JenaUtils.java b/src/main/java/zone/cogni/sem/jena/JenaUtils.java index 415be2f..9dcc793 100644 --- a/src/main/java/zone/cogni/sem/jena/JenaUtils.java +++ b/src/main/java/zone/cogni/sem/jena/JenaUtils.java @@ -153,26 +153,6 @@ public static void closeQuietly(Model... models) { }); } - public static void closeQuietly(Iterable models) { - for (Model model : models) { - if (model == null) { - continue; - } - - if (model.isClosed()) { - log.warn("Closing an already closed model."); - continue; - } - - try { - model.close(); - } - catch (Exception e) { - log.warn("Closing model failed.", e); - } - } - } - public static Model readInto(File file, Model model) { return readInto(file, model, getLangByResourceName(file.getName())); } diff --git a/src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java b/src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java deleted file mode 100644 index 16a4809..0000000 --- a/src/main/java/zone/cogni/sem/jena/template/JenaResultSetHandlers.java +++ /dev/null @@ -1,16 +0,0 @@ -package zone.cogni.sem.jena.template; - - -import org.apache.jena.rdf.model.RDFNode; - -import java.util.List; -import java.util.Map; - -public final class JenaResultSetHandlers { - - public static final JenaResultSetHandler>> listOfMapsResolver = JenaQueryUtils::convertToListOfMaps; - - private JenaResultSetHandlers() { - throw new AssertionError("Should not be initialized!"); - } -} diff --git a/src/main/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java b/src/test/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java similarity index 100% rename from src/main/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java rename to src/test/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java From c69f01fc239b811cf12338121b7cab9e6f2b6f99 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 19 Jun 2024 14:59:04 +0200 Subject: [PATCH 45/58] refactor: simplification of the code --- .../urigenerator/UriGeneratorCalculator.java | 30 ++-- .../urigenerator/json/UriGeneratorRoot.java | 8 +- .../asquare/triplestore/RdfStoreService.java | 43 ----- .../jenamemory/InternalRdfStoreService.java | 78 --------- .../cogni/core/spring/ResourceHelper.java | 35 ---- .../java/zone/cogni/core/util/FileHelper.java | 45 ----- .../java/zone/cogni/core/util/IOHelper.java | 24 --- .../java/zone/cogni/sem/jena/JenaUtils.java | 159 ++++-------------- 8 files changed, 46 insertions(+), 376 deletions(-) delete mode 100644 src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java delete mode 100644 src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java delete mode 100644 src/main/java/zone/cogni/core/spring/ResourceHelper.java delete mode 100644 src/main/java/zone/cogni/core/util/FileHelper.java delete mode 100644 src/main/java/zone/cogni/core/util/IOHelper.java diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java index 772b38d..b4ce972 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -14,8 +14,8 @@ import zone.cogni.asquare.cube.spel.TemplateService; import zone.cogni.asquare.cube.urigenerator.json.UriGenerator; import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; -import zone.cogni.asquare.triplestore.RdfStoreService; -import zone.cogni.asquare.triplestore.jenamemory.InternalRdfStoreService; +import zone.cogni.asquare.triplestore.RdfStoreServiceAPI; +import zone.cogni.asquare.triplestore.InternalRdfStoreService; import zone.cogni.sem.jena.template.JenaQueryUtils; import jakarta.annotation.Nonnull; @@ -49,7 +49,7 @@ private void initPreparedStatements() { } public Model convert(Model model, Map context) { - RdfStoreService rdfStore = getRdfStore(model); + RdfStoreServiceAPI rdfStore = getRdfStore(model); List results = getGeneratorResults(rdfStore); int replaceCount = inputValidations(model, results); @@ -61,7 +61,7 @@ public Model convert(Model model, Map context) { } @Nonnull - private List getGeneratorResults(RdfStoreService rdfStore) { + private List getGeneratorResults(RdfStoreServiceAPI rdfStore) { return uriGeneratorRoot.getGenerators() .stream() .map(generator -> getUriGeneratorResult(rdfStore, generator)) @@ -69,7 +69,7 @@ private List getGeneratorResults(RdfStoreService rdfStore) { } @Nonnull - private UriGeneratorResult getUriGeneratorResult(RdfStoreService rdfStore, UriGenerator generator) { + private UriGeneratorResult getUriGeneratorResult(RdfStoreServiceAPI rdfStore, UriGenerator generator) { UriGeneratorResult uriGeneratorResult = new UriGeneratorResult(); uriGeneratorResult.setGenerator(generator); uriGeneratorResult.setUris(getNewSelectorUris(rdfStore, generator)); @@ -106,7 +106,7 @@ private int inputValidations(Model model, List results) { } private void processReplacements(Model model, - RdfStoreService rdfStore, + RdfStoreServiceAPI rdfStore, int replaceCount, Map context, List results) { @@ -126,7 +126,7 @@ private void processReplacements(Model model, } private int calculateReplacementUrisLoop(Model model, - RdfStoreService rdfStore, + RdfStoreServiceAPI rdfStore, Map context, List results) { AtomicInteger count = new AtomicInteger(); @@ -147,7 +147,7 @@ private int calculateReplacementUrisLoop(Model model, return count.get(); } - private Optional calculateNewUri(RdfStoreService rdfStore, + private Optional calculateNewUri(RdfStoreServiceAPI rdfStore, Map context, UriGeneratorResult result, String oldUri) { @@ -185,7 +185,7 @@ private Optional calculateNewUri(RdfStoreService rdfStore, return Optional.of(newUri); } - private void traceModel(RdfStoreService rdfStore) { + private void traceModel(RdfStoreServiceAPI rdfStore) { if (!log.isTraceEnabled()) return; Model trace = rdfStore.executeConstructQuery("construct {?s ?p ?o} where {?s ?p ?o}"); @@ -194,7 +194,7 @@ private void traceModel(RdfStoreService rdfStore) { log.trace("model: {}", out); } - private boolean existsInModel(RdfStoreService rdfStore, String newUri) { + private boolean existsInModel(RdfStoreServiceAPI rdfStore, String newUri) { QuerySolutionMap querySolution = new QuerySolutionMap(); querySolution.add("x", ResourceFactory.createResource(newUri)); @@ -206,7 +206,7 @@ private boolean existsInModel(RdfStoreService rdfStore, String newUri) { * else a map of variables to be used in uri template! */ private Optional> getQueryMap(Supplier context, - RdfStoreService rdfStore, + RdfStoreServiceAPI rdfStore, String variableQuery) { List> rows = queryForListOfMaps(rdfStore, variableQuery); if (rows.size() != 1) @@ -232,7 +232,7 @@ private void nonNullCheck(Map nodeMap, RDFNode node) { if (node == null) throw new RuntimeException("variableSelector result has some null values: " + nodeMap); } - private List> queryForListOfMaps(RdfStoreService rdfStore, String variableQuery) { + private List> queryForListOfMaps(RdfStoreServiceAPI rdfStore, String variableQuery) { try { return rdfStore.executeSelectQuery(variableQuery, JenaQueryUtils::convertToListOfMaps); } @@ -241,7 +241,7 @@ private List> queryForListOfMaps(RdfStoreService rdfStore, } } - private Set getNewSelectorUris(RdfStoreService rdfStore, UriGenerator generator) { + private Set getNewSelectorUris(RdfStoreServiceAPI rdfStore, UriGenerator generator) { String query = uriGeneratorRoot.getPrefixQuery() + generator.getFullUriSelector(); List uris = getUris(rdfStore, query); return uris.stream() @@ -249,7 +249,7 @@ private Set getNewSelectorUris(RdfStoreService rdfStore, UriGenerator ge .collect(Collectors.toSet()); } - private List getUris(RdfStoreService rdfStore, String query) { + private List getUris(RdfStoreServiceAPI rdfStore, String query) { try { return rdfStore.executeSelectQuery(query, UriGeneratorCalculator::convertToList); } @@ -268,7 +268,7 @@ private static List convertToList(ResultSet resultSet) { return result; } - private RdfStoreService getRdfStore(Model model) { + private RdfStoreServiceAPI getRdfStore(Model model) { return new InternalRdfStoreService(model); } diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java index f45c84d..395ab9d 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java @@ -16,10 +16,7 @@ public class UriGeneratorRoot { public static UriGeneratorRoot load(InputStreamSource resource) { try { ObjectMapper mapper = Json5Light.getJson5Mapper(); - UriGeneratorRoot result = mapper.readValue(resource.getInputStream(), UriGeneratorRoot.class); - -// result.validate(); - return result; + return mapper.readValue(resource.getInputStream(), UriGeneratorRoot.class); } catch (IOException e) { String extra = getPath(resource) != null ? " Path " + getPath(resource) : ""; @@ -29,8 +26,7 @@ public static UriGeneratorRoot load(InputStreamSource resource) { private static String getPath(InputStreamSource resource) { try { - if (resource instanceof Resource) { - Resource r = (Resource) resource; + if (resource instanceof Resource r) { return r.getFile().getPath(); } } diff --git a/src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java b/src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java deleted file mode 100644 index b3416db..0000000 --- a/src/main/java/zone/cogni/asquare/triplestore/RdfStoreService.java +++ /dev/null @@ -1,43 +0,0 @@ -package zone.cogni.asquare.triplestore; - - -import org.apache.jena.query.Query; -import org.apache.jena.query.QueryFactory; -import org.apache.jena.query.QuerySolutionMap; -import org.apache.jena.query.Syntax; -import org.apache.jena.rdf.model.Model; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import zone.cogni.sem.jena.template.JenaResultSetHandler; - -import java.io.Closeable; - -public interface RdfStoreService extends Closeable { - - Logger log = LoggerFactory.getLogger(RdfStoreService.class); - - @Override - default void close() { - log.info("Closing RdfStoreService ({}) : {}", getClass().getName(), this); - } - - R executeSelectQuery(Query query, QuerySolutionMap bindings, JenaResultSetHandler resultSetHandler, String context); - - default R executeSelectQuery(String query, JenaResultSetHandler resultSetHandler, String context) { - Query parsedQuery = QueryFactory.create(query, Syntax.syntaxARQ); - return executeSelectQuery(parsedQuery, new QuerySolutionMap(), resultSetHandler, context); - } - - default R executeSelectQuery(String query, JenaResultSetHandler resultSetHandler) { - return executeSelectQuery(query, resultSetHandler, null); - } - - boolean executeAskQuery(Query query, QuerySolutionMap bindings); - - Model executeConstructQuery(Query query, QuerySolutionMap bindings); - - default Model executeConstructQuery(String query) { - Query parsedQuery = QueryFactory.create(query, Syntax.syntaxARQ); - return executeConstructQuery(parsedQuery, new QuerySolutionMap()); - } -} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java b/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java deleted file mode 100644 index 6f3531e..0000000 --- a/src/main/java/zone/cogni/asquare/triplestore/jenamemory/InternalRdfStoreService.java +++ /dev/null @@ -1,78 +0,0 @@ -package zone.cogni.asquare.triplestore.jenamemory; - -import org.apache.jena.query.*; -import org.apache.jena.rdf.model.Model; -import org.apache.jena.shared.Lock; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import zone.cogni.asquare.triplestore.RdfStoreService; -import zone.cogni.sem.jena.template.JenaResultSetHandler; - -import java.util.function.Supplier; - -public class InternalRdfStoreService implements RdfStoreService { - - private static final Logger log = LoggerFactory.getLogger(InternalRdfStoreService.class); - - private final Model model; - - public InternalRdfStoreService(Model model) { - this.model = model; - } - - @Override - public R executeSelectQuery(Query query, QuerySolutionMap bindings, JenaResultSetHandler resultSetHandler, String context) { - return executeInLock(Lock.READ, () -> { - if (log.isTraceEnabled()) log.trace("Select {} - {} \n{}", - context == null ? "" : "--- " + context + " --- ", - bindings, - query); - - try (QueryExecution queryExecution = QueryExecutionFactory.create(query, model, bindings)) { - ResultSet resultSet = queryExecution.execSelect(); - return resultSetHandler.handle(resultSet); - } - catch (RuntimeException e) { - log.error("Query failed: {}", query); - throw e; - } - }); - } - - @Override - public boolean executeAskQuery(Query query, QuerySolutionMap bindings) { - return executeInLock(Lock.READ, () -> { - try (QueryExecution queryExecution = QueryExecutionFactory.create(query, model, bindings)) { - return queryExecution.execAsk(); - } - catch (RuntimeException e) { - log.error("Query failed: {}", query); - throw e; - } - }); - } - - @Override - public Model executeConstructQuery(Query query, QuerySolutionMap bindings) { - return executeInLock(Lock.READ, () -> { - try (QueryExecution queryExecution = QueryExecutionFactory.create(query, model, bindings)) { - if (log.isTraceEnabled()) log.trace("Running construct query: \n{}", query); - return queryExecution.execConstruct(); - } - catch (RuntimeException e) { - log.error("Query failed: {}", query); - throw e; - } - }); - } - - private T executeInLock(boolean lock, Supplier executeInLock) { - model.enterCriticalSection(lock); - try { - return executeInLock.get(); - } - finally { - model.leaveCriticalSection(); - } - } -} diff --git a/src/main/java/zone/cogni/core/spring/ResourceHelper.java b/src/main/java/zone/cogni/core/spring/ResourceHelper.java deleted file mode 100644 index 114b067..0000000 --- a/src/main/java/zone/cogni/core/spring/ResourceHelper.java +++ /dev/null @@ -1,35 +0,0 @@ -package zone.cogni.core.spring; - -import org.apache.commons.io.IOUtils; -import org.springframework.core.io.InputStreamSource; - -import java.io.IOException; -import java.io.InputStream; - -public class ResourceHelper { - - public static String toString(InputStreamSource resource) { - return toString(resource, "UTF-8"); - } - - public static String toString(InputStreamSource resource, String encoding) { - try (InputStream inputStream = resource.getInputStream()) { - return IOUtils.toString(inputStream, encoding); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - public static InputStream getInputStream(T resource) { - try { - return resource.getInputStream(); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - private ResourceHelper() { - } -} diff --git a/src/main/java/zone/cogni/core/util/FileHelper.java b/src/main/java/zone/cogni/core/util/FileHelper.java deleted file mode 100644 index cef687d..0000000 --- a/src/main/java/zone/cogni/core/util/FileHelper.java +++ /dev/null @@ -1,45 +0,0 @@ -package zone.cogni.core.util; - -import com.google.common.io.Files; -import org.apache.commons.io.FileUtils; - -import javax.annotation.Nonnull; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; - -public class FileHelper { - private FileHelper() { - } - - public static FileInputStream openInputStream(File file) { - try { - return new FileInputStream(file); - } - catch (FileNotFoundException e) { - throw new RuntimeException(e); - } - } - - public static FileOutputStream openOutputStream(@Nonnull File file) { - try { - Files.createParentDirs(file); - return FileUtils.openOutputStream(file); - } - catch (IOException e) { - throw new RuntimeException( "Failed to open outputstream to " + file, e); - } - } - - @Deprecated - public static void writeStringToFile(File file, String data) { - try { - FileUtils.writeStringToFile(file, data); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } -} diff --git a/src/main/java/zone/cogni/core/util/IOHelper.java b/src/main/java/zone/cogni/core/util/IOHelper.java deleted file mode 100644 index ad14e59..0000000 --- a/src/main/java/zone/cogni/core/util/IOHelper.java +++ /dev/null @@ -1,24 +0,0 @@ -package zone.cogni.core.util; - - -import java.io.Closeable; -import java.io.Flushable; -import java.io.IOException; - -public class IOHelper { - public static void flushAndClose(X closeFlusher) { - if (closeFlusher == null) return; - - try { - closeFlusher.flush(); - } - catch (IOException ignore) { - } - - try { - closeFlusher.close(); - } - catch (IOException ignore) { - } - } -} diff --git a/src/main/java/zone/cogni/sem/jena/JenaUtils.java b/src/main/java/zone/cogni/sem/jena/JenaUtils.java index 9dcc793..f7018c0 100644 --- a/src/main/java/zone/cogni/sem/jena/JenaUtils.java +++ b/src/main/java/zone/cogni/sem/jena/JenaUtils.java @@ -1,30 +1,18 @@ package zone.cogni.sem.jena; import com.google.common.base.Preconditions; -import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.jena.rdf.model.AnonId; -import org.apache.jena.rdf.model.Literal; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.RDFErrorHandler; -import org.apache.jena.rdf.model.RDFNode; import org.apache.jena.rdf.model.RDFReaderI; -import org.apache.jena.rdf.model.RDFVisitor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; -import zone.cogni.core.spring.ResourceHelper; -import zone.cogni.core.util.FileHelper; -import zone.cogni.core.util.IOHelper; -import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -47,29 +35,47 @@ private JenaUtils() { } public static Model read(Resource... resources) { - return read(Arrays.asList(resources)); - } - - public static Model read(Iterable resources) { - return read(resources, null); - } - - public static Model read(Iterable resources, Map readerProperties) { Model model = ModelFactory.createDefaultModel(); for (Resource resource : resources) { InputStream inputstream = null; try { - inputstream = ResourceHelper.getInputStream(resource); + InputStream result; + try { + result = resource.getInputStream(); + } + catch (IOException e) { + throw new RuntimeException(e); + } + inputstream = result; InternalRdfErrorHandler errorHandler = new InternalRdfErrorHandler(resource.getDescription()); - RDFReaderI rdfReader = getReader(model, resource, errorHandler, readerProperties); + String extension = StringUtils.lowerCase(StringUtils.substringAfterLast(resource.getFilename(), ".")); + + // when return value is null, fall back to RDF/XML + String language = extensionToLanguageMap.getOrDefault(extension, null); + RDFReaderI rdfReader1; + try { + rdfReader1 = model.getReader(language); + } + catch (IllegalStateException ignored) { + rdfReader1 = model.getReader(); + } + rdfReader1.setErrorHandler(errorHandler); + RDFReaderI rdfReader = rdfReader1; rdfReader.read(model, inputstream, null); Preconditions.checkState(!errorHandler.isFailure(), errorHandler.getInfo()); } catch (RuntimeException e) { - closeQuietly(model); + Arrays.stream(new Model[]{model}).filter(Objects::nonNull).filter(model1 -> !model1.isClosed()).forEach(model1 -> { + try { + model1.close(); + } + catch (Exception e1) { + log.warn("Closing model failed.", e1); + } + }); throw e; } @@ -81,113 +87,6 @@ public static Model read(Iterable resources, Map reade return model; } - private static RDFReaderI getReader(Model model, Resource resource, RDFErrorHandler rdfErrorHandler, Map readerProperties) { - return getReader(model, rdfErrorHandler, readerProperties, getRdfSyntax(resource)); - } - - private static RDFReaderI getReader(Model model, RDFErrorHandler rdfErrorHandler, Map readerProperties, String language) { - RDFReaderI rdfReader = getReaderByRdfSyntax(model, language); - rdfReader.setErrorHandler(rdfErrorHandler); - if (readerProperties == null) return rdfReader; - - for (String propertyName : readerProperties.keySet()) { - rdfReader.setProperty(propertyName, readerProperties.get(propertyName)); - } - return rdfReader; - } - - private static RDFReaderI getReaderByRdfSyntax(Model model, String language) { - try { - return model.getReader(language); - } - catch (IllegalStateException ignored) { - return model.getReader(); - } - } - - private static String getRdfSyntax(org.springframework.core.io.Resource resource) { - String extension = StringUtils.lowerCase(StringUtils.substringAfterLast(resource.getFilename(), ".")); - - // when return value is null, fall back to RDF/XML - return extensionToLanguageMap.getOrDefault(extension, null); - } - - public static void write(Model model, File file) { - write(model, FileHelper.openOutputStream(file)); - } - - public static void write(Model model, OutputStream out) { - try { - model.write(out); - } - finally { - IOHelper.flushAndClose(out); - } - } - - public static String toString(Model model) { - return toString(model, "RDF/XML"); - } - - public static String toString(Model model, String language) { - try { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - model.write(out, language); - - return out.toString("UTF-8"); - } - catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - - - public static void closeQuietly(Model... models) { - Arrays.stream(models).filter(Objects::nonNull).filter(model -> !model.isClosed()).forEach(model -> { - try { - model.close(); - } - catch (Exception e) { - log.warn("Closing model failed.", e); - } - }); - } - - public static Model readInto(File file, Model model) { - return readInto(file, model, getLangByResourceName(file.getName())); - } - - public static String getLangByResourceName(String resourceName) { - String ext = FilenameUtils.getExtension(resourceName); - if (ext.equalsIgnoreCase("ttl")) return "TTL"; - //TODO: add other types - return null; - } - - public static Model readInto(File file, Model model, String lang) { - try (InputStream inputStream = FileHelper.openInputStream(file)) { - return readInto(inputStream, file.getAbsolutePath(), model, lang); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - - public static Model readInto(InputStream inputStream, String streamName, Model model, String lang) { - try { - RDFReaderI reader = model.getReader(lang); - InternalRdfErrorHandler errorHandler = new InternalRdfErrorHandler(streamName); - reader.setErrorHandler(errorHandler); - reader.read(model, inputStream, null); - - Preconditions.checkState(errorHandler.isFailure(), errorHandler.getInfo()); - return model; - } - finally { - IOUtils.closeQuietly(inputStream); - } - } - private static class InternalRdfErrorHandler implements RDFErrorHandler { private final String info; From e47f40db11f5438a1b0d74b2947e62c7553878f8 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 19 Jun 2024 16:31:40 +0200 Subject: [PATCH 46/58] refactor: cleanup, removing Spring from tests, JDK 11 compatibility --- .../urigenerator/UriGeneratorCalculator.java | 92 ++++++------- .../cube/urigenerator/UriGeneratorResult.java | 2 +- .../cube/urigenerator/UriReplacement.java | 29 ---- .../urigenerator/json/UriGeneratorRoot.java | 40 +++--- .../java/zone/cogni/sem/jena/JenaUtils.java | 130 ------------------ .../asquare/cube/spel/SpelConfiguration.java | 14 -- .../UriGeneratorCalculatorTest.java | 35 +++-- .../UriGeneratorCalculatorTestConfig.java | 26 ---- 8 files changed, 84 insertions(+), 284 deletions(-) delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java delete mode 100644 src/main/java/zone/cogni/sem/jena/JenaUtils.java delete mode 100644 src/test/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java delete mode 100644 src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java index b4ce972..1cb25c9 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -8,9 +8,9 @@ import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.RDFNode; import org.apache.jena.rdf.model.ResourceFactory; +import org.apache.jena.util.ResourceUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.core.io.Resource; import zone.cogni.asquare.cube.spel.TemplateService; import zone.cogni.asquare.cube.urigenerator.json.UriGenerator; import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; @@ -19,7 +19,9 @@ import zone.cogni.sem.jena.template.JenaQueryUtils; import jakarta.annotation.Nonnull; + import java.io.StringWriter; +import java.net.URL; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; @@ -34,9 +36,9 @@ public class UriGeneratorCalculator { private final Map preparedStatements = new HashMap<>(); public UriGeneratorCalculator( - String newUriPrefix, - TemplateService templateService, - Resource uriGeneratorRootResource + String newUriPrefix, + TemplateService templateService, + URL uriGeneratorRootResource ) { this.newUriPrefix = newUriPrefix; this.templateService = templateService; @@ -63,9 +65,9 @@ public Model convert(Model model, Map context) { @Nonnull private List getGeneratorResults(RdfStoreServiceAPI rdfStore) { return uriGeneratorRoot.getGenerators() - .stream() - .map(generator -> getUriGeneratorResult(rdfStore, generator)) - .collect(Collectors.toList()); + .stream() + .map(generator -> getUriGeneratorResult(rdfStore, generator)) + .collect(Collectors.toList()); } @Nonnull @@ -84,9 +86,9 @@ private int inputValidations(Model model, List results) { Set selectedUris = new HashSet<>(); Set duplicates = results.stream() - .flatMap(result -> result.getUris().stream()) - .filter(uri -> !selectedUris.add(uri)) - .collect(Collectors.toSet()); + .flatMap(result -> result.getUris().stream()) + .filter(uri -> !selectedUris.add(uri)) + .collect(Collectors.toSet()); if (!duplicates.isEmpty()) log.error("some uris matched multiple selectors: {}", duplicates); @@ -131,18 +133,16 @@ private int calculateReplacementUrisLoop(Model model, List results) { AtomicInteger count = new AtomicInteger(); - results.forEach(result -> { - result.getUris().forEach(uri -> { - if (result.alreadyReplaced(uri)) return; + results.forEach(result -> result.getUris().forEach(uri -> { + if (result.alreadyReplaced(uri)) return; - Optional possibleNewUri = calculateNewUri(rdfStore, context, result, uri); - if (possibleNewUri.isPresent()) { - count.addAndGet(1); - result.addReplacement(uri, possibleNewUri.get()); - UriReplacement.replace(model, uri, possibleNewUri.get()); - } - }); - }); + Optional possibleNewUri = calculateNewUri(rdfStore, context, result, uri); + if (possibleNewUri.isPresent()) { + count.addAndGet(1); + result.addReplacement(uri, possibleNewUri.get()); + ResourceUtils.renameResource(model.getResource(uri), possibleNewUri.get()); + } + })); return count.get(); } @@ -168,7 +168,7 @@ private Optional calculateNewUri(RdfStoreServiceAPI rdfStore, Optional> variableMap = getQueryMap(contextSupplier, rdfStore, variableQuery); // if one of template variables is still a new URI we should skip calculation for now - if (!variableMap.isPresent()) return Optional.empty(); + if (variableMap.isEmpty()) return Optional.empty(); Map map = variableMap.get(); if (log.isTraceEnabled()) log.trace("query result: {}", map); @@ -214,16 +214,14 @@ private Optional> getQueryMap(Supplier context, Map nodeMap = rows.get(0); boolean isBadMatch = nodeMap.values() - .stream() - .peek(node -> nonNullCheck(nodeMap, node)) - .anyMatch(node -> node.isURIResource() - && node.asResource().getURI().startsWith(newUriPrefix)); + .stream() + .peek(node -> nonNullCheck(nodeMap, node)) + .anyMatch(node -> node.isURIResource() + && node.asResource().getURI().startsWith(newUriPrefix)); if (isBadMatch) return Optional.empty(); Map result = new HashMap<>(); - nodeMap.forEach((k, v) -> { - result.put(k, (v.isResource() ? v.asResource().getURI() : v.asLiteral().getString())); - }); + nodeMap.forEach((k, v) -> result.put(k, (v.isResource() ? v.asResource().getURI() : v.asLiteral().getString()))); return Optional.of(result); } @@ -235,8 +233,7 @@ private void nonNullCheck(Map nodeMap, RDFNode node) { private List> queryForListOfMaps(RdfStoreServiceAPI rdfStore, String variableQuery) { try { return rdfStore.executeSelectQuery(variableQuery, JenaQueryUtils::convertToListOfMaps); - } - catch (RuntimeException e) { + } catch (RuntimeException e) { throw new RuntimeException("Query failed: \n" + variableQuery, e); } } @@ -245,15 +242,14 @@ private Set getNewSelectorUris(RdfStoreServiceAPI rdfStore, UriGenerator String query = uriGeneratorRoot.getPrefixQuery() + generator.getFullUriSelector(); List uris = getUris(rdfStore, query); return uris.stream() - .filter(uri -> uri.startsWith(newUriPrefix)) - .collect(Collectors.toSet()); + .filter(uri -> uri.startsWith(newUriPrefix)) + .collect(Collectors.toSet()); } private List getUris(RdfStoreServiceAPI rdfStore, String query) { try { return rdfStore.executeSelectQuery(query, UriGeneratorCalculator::convertToList); - } - catch (RuntimeException e) { + } catch (RuntimeException e) { throw new RuntimeException("problem with query: \n" + query, e); } } @@ -261,9 +257,9 @@ private List getUris(RdfStoreServiceAPI rdfStore, String query) { private static List convertToList(ResultSet resultSet) { List result = new ArrayList<>(); - resultSet.forEachRemaining(querySolution -> { - result.add(querySolution.get("uri").asResource().getURI()); - }); + resultSet.forEachRemaining(querySolution -> + result.add(querySolution.get("uri").asResource().getURI()) + ); return result; } @@ -282,16 +278,16 @@ private void validate(Model model) { private Set getProblemUris(Model model) { Set problemUris = new HashSet<>(); model.listStatements() - .forEachRemaining(statement -> { - if (statement.getSubject().getURI().startsWith(newUriPrefix)) { - problemUris.add(statement.getSubject().getURI()); - } - - if (statement.getObject().isURIResource() - && statement.getObject().asResource().getURI().startsWith(newUriPrefix)) { - problemUris.add(statement.getObject().asResource().getURI()); - } - }); + .forEachRemaining(statement -> { + if (statement.getSubject().getURI().startsWith(newUriPrefix)) { + problemUris.add(statement.getSubject().getURI()); + } + + if (statement.getObject().isURIResource() + && statement.getObject().asResource().getURI().startsWith(newUriPrefix)) { + problemUris.add(statement.getObject().asResource().getURI()); + } + }); return problemUris; } diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java index a91846e..357bedd 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java @@ -11,7 +11,7 @@ public class UriGeneratorResult { private UriGenerator generator; private Set uris; - private Map replacements = new HashMap<>(); + private final Map replacements = new HashMap<>(); public UriGeneratorResult() { } diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java deleted file mode 100644 index 5d45f1b..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriReplacement.java +++ /dev/null @@ -1,29 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -import org.apache.jena.rdf.model.*; - -import java.util.List; - -public class UriReplacement { - - public static void replace(Model model, String original, String replacement) { - Resource originalResource = ResourceFactory.createResource(original); - Resource replacementResource = ResourceFactory.createResource(replacement); - - List leftStatements = model.listStatements(originalResource, null, (RDFNode) null).toList(); - model.remove(leftStatements); - - leftStatements.forEach(statement -> { - model.add(replacementResource, statement.getPredicate(), statement.getObject()); - }); - - - List rightStatements = model.listStatements(null, null, originalResource).toList(); - model.remove(rightStatements); - - rightStatements.forEach(statement -> { - model.add(statement.getSubject(), statement.getPredicate(), replacementResource); - }); - } - -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java index 395ab9d..5a6d400 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java @@ -2,38 +2,30 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang3.StringUtils; -import org.springframework.core.io.InputStreamSource; -import org.springframework.core.io.Resource; import zone.cogni.asquare.cube.json5.Json5Light; import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class UriGeneratorRoot { - public static UriGeneratorRoot load(InputStreamSource resource) { + public static UriGeneratorRoot load(URL resource) { try { ObjectMapper mapper = Json5Light.getJson5Mapper(); - return mapper.readValue(resource.getInputStream(), UriGeneratorRoot.class); - } - catch (IOException e) { - String extra = getPath(resource) != null ? " Path " + getPath(resource) : ""; - throw new RuntimeException("Unable to load uri generator configuration." + extra, e); - } - } - - private static String getPath(InputStreamSource resource) { - try { - if (resource instanceof Resource r) { - return r.getFile().getPath(); + return mapper.readValue(resource.openStream(), UriGeneratorRoot.class); + } catch (IOException e) { + String extra; + try { + extra = " URL " + resource.toURI(); + } catch (URISyntaxException ex) { + throw new RuntimeException(ex); } + throw new RuntimeException("Unable to load uri generator configuration." + extra, e); } - catch (IOException e) { - return null; - } - return null; } private Map prefixes; @@ -60,11 +52,11 @@ public void setGenerators(List generators) { public String getPrefixQuery() { return prefixes.entrySet() - .stream() - .map(e -> "PREFIX " - + StringUtils.rightPad(e.getKey() + ":", 8) + " <" + e.getValue() + ">\n") - .collect(Collectors.joining()) - + "\n"; + .stream() + .map(e -> "PREFIX " + + StringUtils.rightPad(e.getKey() + ":", 8) + " <" + e.getValue() + ">\n") + .collect(Collectors.joining()) + + "\n"; } } diff --git a/src/main/java/zone/cogni/sem/jena/JenaUtils.java b/src/main/java/zone/cogni/sem/jena/JenaUtils.java deleted file mode 100644 index f7018c0..0000000 --- a/src/main/java/zone/cogni/sem/jena/JenaUtils.java +++ /dev/null @@ -1,130 +0,0 @@ -package zone.cogni.sem.jena; - -import com.google.common.base.Preconditions; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.jena.rdf.model.Model; -import org.apache.jena.rdf.model.ModelFactory; -import org.apache.jena.rdf.model.RDFErrorHandler; -import org.apache.jena.rdf.model.RDFReaderI; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.Resource; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -@Deprecated -public class JenaUtils { - private static final Logger log = LoggerFactory.getLogger(JenaUtils.class); - private static final Map extensionToLanguageMap = Collections.synchronizedMap(new HashMap<>()); - - static { - extensionToLanguageMap.put("nt", "N-TRIPLE"); - extensionToLanguageMap.put("n3", "N3"); - extensionToLanguageMap.put("ttl", "TURTLE"); - extensionToLanguageMap.put("jsonld", "JSONLD"); - } - - private JenaUtils() { - } - - public static Model read(Resource... resources) { - Model model = ModelFactory.createDefaultModel(); - - for (Resource resource : resources) { - InputStream inputstream = null; - try { - InputStream result; - try { - result = resource.getInputStream(); - } - catch (IOException e) { - throw new RuntimeException(e); - } - inputstream = result; - InternalRdfErrorHandler errorHandler = new InternalRdfErrorHandler(resource.getDescription()); - - String extension = StringUtils.lowerCase(StringUtils.substringAfterLast(resource.getFilename(), ".")); - - // when return value is null, fall back to RDF/XML - String language = extensionToLanguageMap.getOrDefault(extension, null); - RDFReaderI rdfReader1; - try { - rdfReader1 = model.getReader(language); - } - catch (IllegalStateException ignored) { - rdfReader1 = model.getReader(); - } - rdfReader1.setErrorHandler(errorHandler); - RDFReaderI rdfReader = rdfReader1; - rdfReader.read(model, inputstream, null); - - Preconditions.checkState(!errorHandler.isFailure(), errorHandler.getInfo()); - } - catch (RuntimeException e) { - Arrays.stream(new Model[]{model}).filter(Objects::nonNull).filter(model1 -> !model1.isClosed()).forEach(model1 -> { - try { - model1.close(); - } - catch (Exception e1) { - log.warn("Closing model failed.", e1); - } - }); - - throw e; - } - finally { - IOUtils.closeQuietly(inputstream); - } - } - - return model; - } - - private static class InternalRdfErrorHandler implements RDFErrorHandler { - - private final String info; - private boolean failure; - - private InternalRdfErrorHandler(String loadedFile) { - info = "Load rdf file (" + loadedFile + ") problem."; - } - - public boolean isFailure() { - return failure; - } - - public String getInfo() { - return info; - } - - @Override - public void warning(Exception e) { - String message = e.getMessage(); - if (null != message && message.contains("ISO-639 does not define language:")) { - log.warn("{}: {}", info, message); - return; - } - log.warn(info, e); - } - - @Override - public void error(Exception e) { - failure = true; - log.error(info, e); - } - - @Override - public void fatalError(Exception e) { - failure = true; - log.error(info, e); - } - } -} - diff --git a/src/test/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java b/src/test/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java deleted file mode 100644 index 38ad49c..0000000 --- a/src/test/java/zone/cogni/asquare/cube/spel/SpelConfiguration.java +++ /dev/null @@ -1,14 +0,0 @@ -package zone.cogni.asquare.cube.spel; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class SpelConfiguration { - - @Bean(name = "spelService") - public SpelService getSpelService() { - return new SpelService(); - } - -} diff --git a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java index 2ef91f5..78e45dc 100644 --- a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java +++ b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java @@ -2,29 +2,40 @@ import com.google.common.collect.ImmutableMap; import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.ResourceFactory; +import org.apache.jena.riot.RDFDataMgr; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.core.io.ClassPathResource; -import zone.cogni.sem.jena.JenaUtils; +import zone.cogni.asquare.cube.spel.SpelService; -import static org.assertj.core.api.Assertions.assertThat; +import java.net.URL; -@SpringBootTest(classes = UriGeneratorCalculatorTestConfig.class) public class UriGeneratorCalculatorTest { - @Autowired - UriGeneratorCalculator uriCalculator; + UriGeneratorCalculator sut; + + @BeforeEach + public void init() { + final URL uriGeneratorsResource = getClass().getResource("/urigenerator/uri-generators.json5"); + sut = new UriGeneratorCalculator("http://resource", + new SpelService(), + uriGeneratorsResource); + } @Test public void test_uris_converted() { + final URL modelUrl = getClass().getResource("/urigenerator/model.ttl"); + assert modelUrl != null; + //given - Model model = JenaUtils.read(new ClassPathResource("urigenerator/model.ttl")); + final Model model = ModelFactory.createDefaultModel(); + RDFDataMgr.read(model, modelUrl.toString()); //when - Model converted = uriCalculator.convert(model, ImmutableMap.of("baseUri", "http://asquare.cogni.zone")); + final Model converted = sut.convert(model, ImmutableMap.of("baseUri", "http://asquare.cogni.zone")); //then - assertThat(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/5"))); - assertThat(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/2021/0005"))); + Assertions.assertTrue(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/5"))); + Assertions.assertTrue(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/2021/0005"))); } } diff --git a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java deleted file mode 100644 index ea38dab..0000000 --- a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTestConfig.java +++ /dev/null @@ -1,26 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import zone.cogni.asquare.cube.spel.SpelService; - -@Configuration -@Import(SpelService.class) -public class UriGeneratorCalculatorTestConfig { - - @Autowired - private SpelService spelService; - - @Bean - public UriGeneratorCalculator uriCalculator() { - Resource uriGeneratorsResource = new ClassPathResource("urigenerator/uri-generators.json5"); - return new UriGeneratorCalculator("http://resource", - spelService, - uriGeneratorsResource); - } -} - From 0607e08388186311386f0223614623e23746a200 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 19 Jun 2024 18:15:32 +0200 Subject: [PATCH 47/58] fix: cleanup, code quality checks (dependencycheck, pmd, jacoco) --- .../urigenerator/UriGeneratorCalculator.java | 116 ++++++++---------- 1 file changed, 52 insertions(+), 64 deletions(-) diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java index 1cb25c9..1d96671 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -29,6 +29,7 @@ public class UriGeneratorCalculator { private static final Logger log = LoggerFactory.getLogger(UriGeneratorCalculator.class); + public static final int EXPECTED_ROW_COUNT = 1; private final String newUriPrefix; private final TemplateService templateService; @@ -51,15 +52,19 @@ private void initPreparedStatements() { } public Model convert(Model model, Map context) { - RdfStoreServiceAPI rdfStore = getRdfStore(model); - List results = getGeneratorResults(rdfStore); + try { + final RdfStoreServiceAPI rdfStore = getRdfStore(model); + final List results = getGeneratorResults(rdfStore); - int replaceCount = inputValidations(model, results); - processReplacements(model, rdfStore, replaceCount, context, results); + int replaceCount = inputValidations(model, results); + processReplacements(model, rdfStore, replaceCount, context, results); - validate(model); + validate(model); - return model; + return model; + } catch(RuntimeException e) { + throw new RuntimeException("An error occurred during URI generation", e); + } } @Nonnull @@ -81,11 +86,11 @@ private UriGeneratorResult getUriGeneratorResult(RdfStoreServiceAPI rdfStore, Ur /** * @return number of uris to be replaces */ - private int inputValidations(Model model, List results) { - Set incomingUris = getProblemUris(model); + private int inputValidations(final Model model, final List results) { + final Set incomingUris = getProblemUris(model); - Set selectedUris = new HashSet<>(); - Set duplicates = results.stream() + final Set selectedUris = new HashSet<>(); + final Set duplicates = results.stream() .flatMap(result -> result.getUris().stream()) .filter(uri -> !selectedUris.add(uri)) .collect(Collectors.toSet()); @@ -93,25 +98,24 @@ private int inputValidations(Model model, List results) { if (!duplicates.isEmpty()) log.error("some uris matched multiple selectors: {}", duplicates); - int size = incomingUris.size(); + final int size = incomingUris.size(); if (size != selectedUris.size()) log.error("incoming uris and selected uris do not match up." + - "\n\t incoming: {}" + - "\n\t selected: {}", incomingUris, selectedUris); + "\n\t incoming: {}" + + "\n\t selected: {}", incomingUris, selectedUris); if (!duplicates.isEmpty() || size != selectedUris.size()) throw new RuntimeException("some validations failed when converting new uris, check logs for more info"); - log.info("(uri generator) replacing {} uris", size); return size; } - private void processReplacements(Model model, - RdfStoreServiceAPI rdfStore, + private void processReplacements(final Model model, + final RdfStoreServiceAPI rdfStore, int replaceCount, - Map context, - List results) { + final Map context, + final List results) { int loopCount = 0; while (true) { int count = calculateReplacementUrisLoop(model, rdfStore, context, results); @@ -127,16 +131,16 @@ private void processReplacements(Model model, } } - private int calculateReplacementUrisLoop(Model model, - RdfStoreServiceAPI rdfStore, - Map context, - List results) { - AtomicInteger count = new AtomicInteger(); + private int calculateReplacementUrisLoop(final Model model, + final RdfStoreServiceAPI rdfStore, + final Map context, + final List results) { + final AtomicInteger count = new AtomicInteger(); results.forEach(result -> result.getUris().forEach(uri -> { if (result.alreadyReplaced(uri)) return; - Optional possibleNewUri = calculateNewUri(rdfStore, context, result, uri); + final Optional possibleNewUri = calculateNewUri(rdfStore, context, result, uri); if (possibleNewUri.isPresent()) { count.addAndGet(1); result.addReplacement(uri, possibleNewUri.get()); @@ -147,37 +151,37 @@ private int calculateReplacementUrisLoop(Model model, return count.get(); } - private Optional calculateNewUri(RdfStoreServiceAPI rdfStore, - Map context, - UriGeneratorResult result, - String oldUri) { + private Optional calculateNewUri(final RdfStoreServiceAPI rdfStore, + final Map context, + final UriGeneratorResult result, + final String oldUri) { if (log.isTraceEnabled()) log.trace("calculate new uri for {}", oldUri); traceModel(rdfStore); - Map variables = new HashMap<>(context); + final Map variables = new HashMap<>(context); variables.put("uri", oldUri); // variable template can also NOT exist: then this step is skipped! - String variableSelector = result.getGenerator().getFullVariableSelector(); + final String variableSelector = result.getGenerator().getFullVariableSelector(); if (StringUtils.isNotBlank(variableSelector)) { - String variableTemplateQuery = uriGeneratorRoot.getPrefixQuery() + variableSelector; - String variableQuery = templateService.processTemplate(variableTemplateQuery, variables); + final String variableTemplateQuery = uriGeneratorRoot.getPrefixQuery() + variableSelector; + final String variableQuery = templateService.processTemplate(variableTemplateQuery, variables); if (log.isTraceEnabled()) log.trace("query: {}", variableQuery); - Supplier contextSupplier = () -> result.getGenerator().getId(); - Optional> variableMap = getQueryMap(contextSupplier, rdfStore, variableQuery); + final Supplier contextSupplier = () -> result.getGenerator().getId(); + final Optional> variableMap = getQueryMap(contextSupplier, rdfStore, variableQuery); // if one of template variables is still a new URI we should skip calculation for now if (variableMap.isEmpty()) return Optional.empty(); - Map map = variableMap.get(); + final Map map = variableMap.get(); if (log.isTraceEnabled()) log.trace("query result: {}", map); variables.putAll(map); } if (log.isTraceEnabled()) log.debug("variables: {}", variables); - String uriTemplate = result.getGenerator().getUriTemplate(); - String newUri = templateService.processTemplate(uriTemplate, variables); + final String uriTemplate = result.getGenerator().getUriTemplate(); + final String newUri = templateService.processTemplate(uriTemplate, variables); if (existsInModel(rdfStore, newUri)) throw new RuntimeException("uri overlap found for " + newUri); @@ -188,14 +192,14 @@ private Optional calculateNewUri(RdfStoreServiceAPI rdfStore, private void traceModel(RdfStoreServiceAPI rdfStore) { if (!log.isTraceEnabled()) return; - Model trace = rdfStore.executeConstructQuery("construct {?s ?p ?o} where {?s ?p ?o}"); - StringWriter out = new StringWriter(); + final Model trace = rdfStore.executeConstructQuery("construct {?s ?p ?o} where {?s ?p ?o}"); + final StringWriter out = new StringWriter(); trace.write(out, "ttl"); log.trace("model: {}", out); } private boolean existsInModel(RdfStoreServiceAPI rdfStore, String newUri) { - QuerySolutionMap querySolution = new QuerySolutionMap(); + final QuerySolutionMap querySolution = new QuerySolutionMap(); querySolution.add("x", ResourceFactory.createResource(newUri)); return rdfStore.executeAskQuery(preparedStatements.get("exists-uri"), querySolution); @@ -208,11 +212,11 @@ private boolean existsInModel(RdfStoreServiceAPI rdfStore, String newUri) { private Optional> getQueryMap(Supplier context, RdfStoreServiceAPI rdfStore, String variableQuery) { - List> rows = queryForListOfMaps(rdfStore, variableQuery); - if (rows.size() != 1) - throw new RuntimeException("[" + context.get() + "] expected 1 row, found " + rows); + final List> result1 = rdfStore.executeSelectQuery(variableQuery, JenaQueryUtils::convertToListOfMaps); + if (result1.size() != EXPECTED_ROW_COUNT) + throw new RuntimeException("[" + context.get() + "] expected 1 row, found " + result1); - Map nodeMap = rows.get(0); + final Map nodeMap = result1.get(0); boolean isBadMatch = nodeMap.values() .stream() .peek(node -> nonNullCheck(nodeMap, node)) @@ -220,7 +224,7 @@ private Optional> getQueryMap(Supplier context, && node.asResource().getURI().startsWith(newUriPrefix)); if (isBadMatch) return Optional.empty(); - Map result = new HashMap<>(); + final Map result = new HashMap<>(); nodeMap.forEach((k, v) -> result.put(k, (v.isResource() ? v.asResource().getURI() : v.asLiteral().getString()))); return Optional.of(result); @@ -230,30 +234,14 @@ private void nonNullCheck(Map nodeMap, RDFNode node) { if (node == null) throw new RuntimeException("variableSelector result has some null values: " + nodeMap); } - private List> queryForListOfMaps(RdfStoreServiceAPI rdfStore, String variableQuery) { - try { - return rdfStore.executeSelectQuery(variableQuery, JenaQueryUtils::convertToListOfMaps); - } catch (RuntimeException e) { - throw new RuntimeException("Query failed: \n" + variableQuery, e); - } - } - private Set getNewSelectorUris(RdfStoreServiceAPI rdfStore, UriGenerator generator) { - String query = uriGeneratorRoot.getPrefixQuery() + generator.getFullUriSelector(); - List uris = getUris(rdfStore, query); - return uris.stream() + final String query = uriGeneratorRoot.getPrefixQuery() + generator.getFullUriSelector(); + return rdfStore + .executeSelectQuery(query, UriGeneratorCalculator::convertToList).stream() .filter(uri -> uri.startsWith(newUriPrefix)) .collect(Collectors.toSet()); } - private List getUris(RdfStoreServiceAPI rdfStore, String query) { - try { - return rdfStore.executeSelectQuery(query, UriGeneratorCalculator::convertToList); - } catch (RuntimeException e) { - throw new RuntimeException("problem with query: \n" + query, e); - } - } - private static List convertToList(ResultSet resultSet) { List result = new ArrayList<>(); From d145c0ce92562ba8a16ebe1029d27b8e22754c92 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Thu, 20 Jun 2024 08:51:19 +0200 Subject: [PATCH 48/58] feat: basic support for JSON-LD 1.1 inputs --- .../asquare/cube/urigenerator/Format.java | 6 ++ .../JsonLdObjectMapperFactory.java | 25 ++++++++ .../urigenerator/UriGeneratorCalculator.java | 5 +- .../asquare/cube/urigenerator/Utils.java | 19 ++++++ .../asquare/cube/urigenerator/Vocabulary.java | 17 ++++++ .../cube/urigenerator/json/Prefix.java | 23 ++++++++ .../cube/urigenerator/json/UriGenerator.java | 50 +++++----------- .../urigenerator/json/UriGeneratorRoot.java | 59 ++++++------------- .../UriGeneratorCalculatorTest.java | 24 +++++--- .../urigenerator/uri-generators.json | 19 ++++++ 10 files changed, 159 insertions(+), 88 deletions(-) create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java create mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java create mode 100644 src/test/resources/urigenerator/uri-generators.json diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java new file mode 100644 index 0000000..b7a109e --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java @@ -0,0 +1,6 @@ +package zone.cogni.asquare.cube.urigenerator; + +public enum Format { + JSON5, + JSONLD11 +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java new file mode 100644 index 0000000..56b106a --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java @@ -0,0 +1,25 @@ +package zone.cogni.asquare.cube.urigenerator; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import cz.cvut.kbss.jsonld.ConfigParam; +import cz.cvut.kbss.jsonld.jackson.JsonLdModule; +import cz.cvut.kbss.jsonld.jackson.serialization.SerializationConstants; + +import static cz.cvut.kbss.jsonld.ConfigParam.ASSUME_TARGET_TYPE; + +public class JsonLdObjectMapperFactory { + + public static ObjectMapper getJsonLdMapper() { + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + final JsonLdModule module = new JsonLdModule(); + module.configure(ASSUME_TARGET_TYPE, Boolean.TRUE.toString()); + module.configure(ConfigParam.SCAN_PACKAGE, "zone.cogni.asquare.cube.urigenerator.json"); + module.configure(SerializationConstants.FORM, SerializationConstants.FORM_COMPACT_WITH_CONTEXT); + objectMapper.registerModule(module); + return objectMapper; + } +} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java index 1d96671..9bf02fd 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java @@ -39,11 +39,12 @@ public class UriGeneratorCalculator { public UriGeneratorCalculator( String newUriPrefix, TemplateService templateService, - URL uriGeneratorRootResource + URL uriGeneratorRootResource, + Format format ) { this.newUriPrefix = newUriPrefix; this.templateService = templateService; - this.uriGeneratorRoot = UriGeneratorRoot.load(uriGeneratorRootResource); + this.uriGeneratorRoot = Utils.load(uriGeneratorRootResource, format); initPreparedStatements(); } diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java new file mode 100644 index 0000000..2db6b35 --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java @@ -0,0 +1,19 @@ +package zone.cogni.asquare.cube.urigenerator; + +import com.fasterxml.jackson.databind.ObjectMapper; +import zone.cogni.asquare.cube.json5.Json5Light; +import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; + +import java.io.IOException; +import java.net.URL; + +public class Utils { + public static UriGeneratorRoot load(URL resource, Format format) { + try { + ObjectMapper mapper = format.equals(Format.JSON5) ? Json5Light.getJson5Mapper() : JsonLdObjectMapperFactory.getJsonLdMapper(); + return mapper.readValue(resource.openStream(), UriGeneratorRoot.class); + } catch (IOException e) { + throw new RuntimeException("Unable to load uri generator configuration." + resource, e); + } + } +} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java new file mode 100644 index 0000000..3e97649 --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java @@ -0,0 +1,17 @@ +package zone.cogni.asquare.cube.urigenerator; + +public class Vocabulary { + private static final String NS = "https://data.cogni.zone/voc/irigenerator/"; + public static final String C_IRI_GENERATOR = NS + "iri-generator"; + public static final String P_IRI_SELECTOR = NS + "iri-selector"; + public static final String P_VARIABLE_SELECTOR = NS + "variable-selector"; + public static final String P_IRI_TEMPLATE = NS + "iri-template"; + + public static final String C_GENERATOR_SPECIFICATION = NS + "generator-specification"; + public static final String P_PREFIX = NS + "prefix"; + public static final String P_GENERATOR = NS + "generator"; + + public static final String C_PREFIX = NS + "prefix-class"; + public static final String P_PREFIX_NAME = NS + "prefix-name"; + public static final String P_NAMESPACE = NS + "namespace"; +} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java new file mode 100644 index 0000000..46c4108 --- /dev/null +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java @@ -0,0 +1,23 @@ +package zone.cogni.asquare.cube.urigenerator.json; + +import cz.cvut.kbss.jopa.model.annotations.Id; +import cz.cvut.kbss.jopa.model.annotations.OWLClass; +import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty; +import lombok.Data; +import zone.cogni.asquare.cube.urigenerator.Vocabulary; + +import java.net.URI; + +@Data +@OWLClass(iri = Vocabulary.C_PREFIX) +public class Prefix { + + @Id + private URI id; + + @OWLDataProperty(iri = Vocabulary.P_PREFIX_NAME) + private String key; + + @OWLDataProperty(iri = Vocabulary.P_NAMESPACE) + private String value; +} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java index a1fbe4b..5d87c1d 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java @@ -1,46 +1,26 @@ package zone.cogni.asquare.cube.urigenerator.json; +import cz.cvut.kbss.jopa.model.annotations.Id; +import cz.cvut.kbss.jopa.model.annotations.OWLClass; +import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty; +import lombok.Data; +import zone.cogni.asquare.cube.urigenerator.Vocabulary; + +@Data +@OWLClass(iri = Vocabulary.C_IRI_GENERATOR) public class UriGenerator { + @Id private String id; - private String uriSelector; - private String variableSelector; - private String uriTemplate; - - public UriGenerator() { - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getUriSelector() { - return uriSelector; - } - public void setUriSelector(String uriSelector) { - this.uriSelector = uriSelector; - } - - public String getVariableSelector() { - return variableSelector; - } - - public void setVariableSelector(String variableSelector) { - this.variableSelector = variableSelector; - } + @OWLDataProperty(iri = Vocabulary.P_IRI_SELECTOR) + private String uriSelector; - public String getUriTemplate() { - return uriTemplate; - } + @OWLDataProperty(iri = Vocabulary.P_VARIABLE_SELECTOR) + private String variableSelector; - public void setUriTemplate(String uriTemplate) { - this.uriTemplate = uriTemplate; - } + @OWLDataProperty(iri = Vocabulary.P_IRI_TEMPLATE) + private String uriTemplate; public String getFullUriSelector() { if (uriSelector == null) return ""; diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java index 5a6d400..900b9da 100644 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java +++ b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java @@ -1,62 +1,37 @@ package zone.cogni.asquare.cube.urigenerator.json; -import com.fasterxml.jackson.databind.ObjectMapper; +import cz.cvut.kbss.jopa.model.annotations.Id; +import cz.cvut.kbss.jopa.model.annotations.OWLClass; +import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty; +import lombok.Data; import org.apache.commons.lang3.StringUtils; -import zone.cogni.asquare.cube.json5.Json5Light; +import zone.cogni.asquare.cube.urigenerator.Vocabulary; -import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; +import java.net.URI; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; +@Data +@OWLClass(iri = Vocabulary.C_GENERATOR_SPECIFICATION) public class UriGeneratorRoot { - public static UriGeneratorRoot load(URL resource) { - try { - ObjectMapper mapper = Json5Light.getJson5Mapper(); - return mapper.readValue(resource.openStream(), UriGeneratorRoot.class); - } catch (IOException e) { - String extra; - try { - extra = " URL " + resource.toURI(); - } catch (URISyntaxException ex) { - throw new RuntimeException(ex); - } - throw new RuntimeException("Unable to load uri generator configuration." + extra, e); - } - } - - private Map prefixes; - private List generators; + @Id + private URI id; - public UriGeneratorRoot() { - } + @OWLObjectProperty(iri = Vocabulary.P_PREFIX) + private List prefixes; +// private Map prefixes; - public Map getPrefixes() { - return prefixes; - } - - public void setPrefixes(Map prefixes) { - this.prefixes = prefixes; - } - - public List getGenerators() { - return generators; - } - - public void setGenerators(List generators) { - this.generators = generators; - } + @OWLObjectProperty(iri = Vocabulary.P_GENERATOR) + private List generators; public String getPrefixQuery() { - return prefixes.entrySet() + return prefixes +// .entrySet() .stream() .map(e -> "PREFIX " + StringUtils.rightPad(e.getKey() + ":", 8) + " <" + e.getValue() + ">\n") .collect(Collectors.joining()) + "\n"; } - } diff --git a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java index 78e45dc..3f6e72e 100644 --- a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java +++ b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java @@ -6,7 +6,6 @@ import org.apache.jena.rdf.model.ResourceFactory; import org.apache.jena.riot.RDFDataMgr; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import zone.cogni.asquare.cube.spel.SpelService; @@ -14,18 +13,25 @@ public class UriGeneratorCalculatorTest { - UriGeneratorCalculator sut; - @BeforeEach - public void init() { - final URL uriGeneratorsResource = getClass().getResource("/urigenerator/uri-generators.json5"); - sut = new UriGeneratorCalculator("http://resource", - new SpelService(), - uriGeneratorsResource); + @Test + public void testURIConvertedForJsonLD11() { + testURIConvertedForSyntax("/urigenerator/uri-generators.json", Format.JSONLD11); } @Test - public void test_uris_converted() { + public void testURIConvertedForJson5() { + testURIConvertedForSyntax("/urigenerator/uri-generators.json5", Format.JSON5); + } + + private void testURIConvertedForSyntax(String generatorsResource, Format format) { + final URL uriGeneratorsResource = getClass().getResource(generatorsResource); + + final UriGeneratorCalculator sut = new UriGeneratorCalculator("http://resource", + new SpelService(), + uriGeneratorsResource, + format); + final URL modelUrl = getClass().getResource("/urigenerator/model.ttl"); assert modelUrl != null; diff --git a/src/test/resources/urigenerator/uri-generators.json b/src/test/resources/urigenerator/uri-generators.json new file mode 100644 index 0000000..3e778e1 --- /dev/null +++ b/src/test/resources/urigenerator/uri-generators.json @@ -0,0 +1,19 @@ +{ + "@context": "file:/home/psiotwo/soft/cognizone/irigenerator/src/main/resources/context.json", + "prefixes": { + "prefix-name": "demo", + "namespace": "http://demo.com/model#" + }, + "generators": [ + { + "uriSelector": "select ?uri { ?uri a demo:One }", + "variableSelector": "select ?id where { <#{[uri]}> demo:id ?id }", + "uriTemplate": "#{[baseUri]}/#{[id]}" + }, + { + "uriSelector": "select ?uri { ?uri a demo:Two }", + "variableSelector": "select ?year ?sequence where { <#{[uri]}> demo:year ?year ; demo:sequence ?sequence}", + "uriTemplate": "#{[baseUri]}/#{[year]}/#{[sequence]}" + } + ] +} \ No newline at end of file From 3555bcbd6d48ab3908fca3dbd51a3d95c1bc947e Mon Sep 17 00:00:00 2001 From: psiotwo Date: Sat, 22 Jun 2024 09:55:49 +0200 Subject: [PATCH 49/58] refactor: move to the package zone.cogni.semantics.irigenerator, renaming URIs to IRIs --- .../asquare/cube/urigenerator/Format.java | 6 --- .../JsonLdObjectMapperFactory.java | 25 ---------- .../cube/urigenerator/UriGeneratorResult.java | 42 ----------------- .../asquare/cube/urigenerator/Vocabulary.java | 17 ------- .../UriGeneratorCalculatorTest.java | 47 ------------------- .../{urigenerator => irigenerator}/model.ttl | 0 .../uri-generators.json | 0 .../uri-generators.json5 | 0 8 files changed, 137 deletions(-) delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java delete mode 100644 src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java rename src/test/resources/{urigenerator => irigenerator}/model.ttl (100%) rename src/test/resources/{urigenerator => irigenerator}/uri-generators.json (100%) rename src/test/resources/{urigenerator => irigenerator}/uri-generators.json5 (100%) diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java deleted file mode 100644 index b7a109e..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/Format.java +++ /dev/null @@ -1,6 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -public enum Format { - JSON5, - JSONLD11 -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java deleted file mode 100644 index 56b106a..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/JsonLdObjectMapperFactory.java +++ /dev/null @@ -1,25 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import cz.cvut.kbss.jsonld.ConfigParam; -import cz.cvut.kbss.jsonld.jackson.JsonLdModule; -import cz.cvut.kbss.jsonld.jackson.serialization.SerializationConstants; - -import static cz.cvut.kbss.jsonld.ConfigParam.ASSUME_TARGET_TYPE; - -public class JsonLdObjectMapperFactory { - - public static ObjectMapper getJsonLdMapper() { - final ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - final JsonLdModule module = new JsonLdModule(); - module.configure(ASSUME_TARGET_TYPE, Boolean.TRUE.toString()); - module.configure(ConfigParam.SCAN_PACKAGE, "zone.cogni.asquare.cube.urigenerator.json"); - module.configure(SerializationConstants.FORM, SerializationConstants.FORM_COMPACT_WITH_CONTEXT); - objectMapper.registerModule(module); - return objectMapper; - } -} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java deleted file mode 100644 index 357bedd..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorResult.java +++ /dev/null @@ -1,42 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - - -import zone.cogni.asquare.cube.urigenerator.json.UriGenerator; - -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -public class UriGeneratorResult { - - private UriGenerator generator; - private Set uris; - private final Map replacements = new HashMap<>(); - - public UriGeneratorResult() { - } - - public UriGenerator getGenerator() { - return generator; - } - - public void setGenerator(UriGenerator generator) { - this.generator = generator; - } - - public Set getUris() { - return uris; - } - - public void setUris(Set uris) { - this.uris = uris; - } - - public boolean alreadyReplaced(String oldUri) { - return replacements.containsKey(oldUri); - } - - public void addReplacement(String oldUri, String newUri) { - replacements.put(oldUri, newUri); - } -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java deleted file mode 100644 index 3e97649..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/Vocabulary.java +++ /dev/null @@ -1,17 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -public class Vocabulary { - private static final String NS = "https://data.cogni.zone/voc/irigenerator/"; - public static final String C_IRI_GENERATOR = NS + "iri-generator"; - public static final String P_IRI_SELECTOR = NS + "iri-selector"; - public static final String P_VARIABLE_SELECTOR = NS + "variable-selector"; - public static final String P_IRI_TEMPLATE = NS + "iri-template"; - - public static final String C_GENERATOR_SPECIFICATION = NS + "generator-specification"; - public static final String P_PREFIX = NS + "prefix"; - public static final String P_GENERATOR = NS + "generator"; - - public static final String C_PREFIX = NS + "prefix-class"; - public static final String P_PREFIX_NAME = NS + "prefix-name"; - public static final String P_NAMESPACE = NS + "namespace"; -} \ No newline at end of file diff --git a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java b/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java deleted file mode 100644 index 3f6e72e..0000000 --- a/src/test/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculatorTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -import com.google.common.collect.ImmutableMap; -import org.apache.jena.rdf.model.Model; -import org.apache.jena.rdf.model.ModelFactory; -import org.apache.jena.rdf.model.ResourceFactory; -import org.apache.jena.riot.RDFDataMgr; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import zone.cogni.asquare.cube.spel.SpelService; - -import java.net.URL; - -public class UriGeneratorCalculatorTest { - - - @Test - public void testURIConvertedForJsonLD11() { - testURIConvertedForSyntax("/urigenerator/uri-generators.json", Format.JSONLD11); - } - - @Test - public void testURIConvertedForJson5() { - testURIConvertedForSyntax("/urigenerator/uri-generators.json5", Format.JSON5); - } - - private void testURIConvertedForSyntax(String generatorsResource, Format format) { - final URL uriGeneratorsResource = getClass().getResource(generatorsResource); - - final UriGeneratorCalculator sut = new UriGeneratorCalculator("http://resource", - new SpelService(), - uriGeneratorsResource, - format); - - final URL modelUrl = getClass().getResource("/urigenerator/model.ttl"); - assert modelUrl != null; - - //given - final Model model = ModelFactory.createDefaultModel(); - RDFDataMgr.read(model, modelUrl.toString()); - //when - final Model converted = sut.convert(model, ImmutableMap.of("baseUri", "http://asquare.cogni.zone")); - //then - Assertions.assertTrue(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/5"))); - Assertions.assertTrue(converted.containsResource(ResourceFactory.createResource("http://asquare.cogni.zone/2021/0005"))); - } -} diff --git a/src/test/resources/urigenerator/model.ttl b/src/test/resources/irigenerator/model.ttl similarity index 100% rename from src/test/resources/urigenerator/model.ttl rename to src/test/resources/irigenerator/model.ttl diff --git a/src/test/resources/urigenerator/uri-generators.json b/src/test/resources/irigenerator/uri-generators.json similarity index 100% rename from src/test/resources/urigenerator/uri-generators.json rename to src/test/resources/irigenerator/uri-generators.json diff --git a/src/test/resources/urigenerator/uri-generators.json5 b/src/test/resources/irigenerator/uri-generators.json5 similarity index 100% rename from src/test/resources/urigenerator/uri-generators.json5 rename to src/test/resources/irigenerator/uri-generators.json5 From 0edd0c975427a42e3e1f36bccd6e459d2adf0b7d Mon Sep 17 00:00:00 2001 From: psiotwo Date: Sun, 18 Aug 2024 19:54:14 +0200 Subject: [PATCH 50/58] refactor: moving default example to 'demo' folder --- src/test/resources/irigenerator/{ => demo}/model.ttl | 0 src/test/resources/irigenerator/{ => demo}/uri-generators.json | 0 src/test/resources/irigenerator/{ => demo}/uri-generators.json5 | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/test/resources/irigenerator/{ => demo}/model.ttl (100%) rename src/test/resources/irigenerator/{ => demo}/uri-generators.json (100%) rename src/test/resources/irigenerator/{ => demo}/uri-generators.json5 (100%) diff --git a/src/test/resources/irigenerator/model.ttl b/src/test/resources/irigenerator/demo/model.ttl similarity index 100% rename from src/test/resources/irigenerator/model.ttl rename to src/test/resources/irigenerator/demo/model.ttl diff --git a/src/test/resources/irigenerator/uri-generators.json b/src/test/resources/irigenerator/demo/uri-generators.json similarity index 100% rename from src/test/resources/irigenerator/uri-generators.json rename to src/test/resources/irigenerator/demo/uri-generators.json diff --git a/src/test/resources/irigenerator/uri-generators.json5 b/src/test/resources/irigenerator/demo/uri-generators.json5 similarity index 100% rename from src/test/resources/irigenerator/uri-generators.json5 rename to src/test/resources/irigenerator/demo/uri-generators.json5 From c0c8358dd432bb8960089915915bc8c525787d7f Mon Sep 17 00:00:00 2001 From: psiotwo Date: Mon, 19 Aug 2024 08:12:25 +0200 Subject: [PATCH 51/58] feat: test parameterization and improved logging --- src/test/resources/irigenerator/demo/expected-model.ttl | 8 ++++++++ .../irigenerator/demo/{model.ttl => original-model.ttl} | 0 2 files changed, 8 insertions(+) create mode 100644 src/test/resources/irigenerator/demo/expected-model.ttl rename src/test/resources/irigenerator/demo/{model.ttl => original-model.ttl} (100%) diff --git a/src/test/resources/irigenerator/demo/expected-model.ttl b/src/test/resources/irigenerator/demo/expected-model.ttl new file mode 100644 index 0000000..10e9a70 --- /dev/null +++ b/src/test/resources/irigenerator/demo/expected-model.ttl @@ -0,0 +1,8 @@ +@prefix demo: . + + a demo:One ; + demo:id "5" . + + a demo:Two ; + demo:year "2021" ; + demo:sequence "0005" . \ No newline at end of file diff --git a/src/test/resources/irigenerator/demo/model.ttl b/src/test/resources/irigenerator/demo/original-model.ttl similarity index 100% rename from src/test/resources/irigenerator/demo/model.ttl rename to src/test/resources/irigenerator/demo/original-model.ttl From e630ac2342f3c47b8e2f26d7c26e841da7cb4c19 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 21 Aug 2024 09:45:18 +0200 Subject: [PATCH 52/58] refactor: test IRIs --- .../irigenerator/demo/expected-model.ttl | 12 +++--- .../irigenerator/demo/original-model.ttl | 12 +++--- .../irigenerator/demo/uri-generators.json | 42 +++++++++++++++---- .../irigenerator/demo/uri-generators.json5 | 12 +++--- 4 files changed, 52 insertions(+), 26 deletions(-) diff --git a/src/test/resources/irigenerator/demo/expected-model.ttl b/src/test/resources/irigenerator/demo/expected-model.ttl index 10e9a70..baddb9b 100644 --- a/src/test/resources/irigenerator/demo/expected-model.ttl +++ b/src/test/resources/irigenerator/demo/expected-model.ttl @@ -1,8 +1,8 @@ -@prefix demo: . +@prefix eczm: . - a demo:One ; - demo:id "5" . + a eczm:One ; + eczm:id "5" . - a demo:Two ; - demo:year "2021" ; - demo:sequence "0005" . \ No newline at end of file + a eczm:Two ; + eczm:year "2021" ; + eczm:sequence "0005" . \ No newline at end of file diff --git a/src/test/resources/irigenerator/demo/original-model.ttl b/src/test/resources/irigenerator/demo/original-model.ttl index efd8442..bf9bfad 100644 --- a/src/test/resources/irigenerator/demo/original-model.ttl +++ b/src/test/resources/irigenerator/demo/original-model.ttl @@ -1,8 +1,8 @@ -@prefix demo: . +@prefix eczm: . - a demo:One ; - demo:id "5" . + a eczm:One ; + eczm:id "5" . - a demo:Two ; - demo:year "2021" ; - demo:sequence "0005" . \ No newline at end of file + a eczm:Two ; + eczm:year "2021" ; + eczm:sequence "0005" . \ No newline at end of file diff --git a/src/test/resources/irigenerator/demo/uri-generators.json b/src/test/resources/irigenerator/demo/uri-generators.json index 3e778e1..ef6f6d3 100644 --- a/src/test/resources/irigenerator/demo/uri-generators.json +++ b/src/test/resources/irigenerator/demo/uri-generators.json @@ -1,18 +1,44 @@ { - "@context": "file:/home/psiotwo/soft/cognizone/irigenerator/src/main/resources/context.json", - "prefixes": { - "prefix-name": "demo", - "namespace": "http://demo.com/model#" + "@context": { + "@version": 1.1, + "irigenerator": "https://data.cogni.zone/voc/irigenerator/", + "uri": "@id", + "types": "@type", + "prefixes": { + "@id": "irigenerator:prefix", + "@type": "irigenerator:prefix-class", + "@context": { + "uri": "@id", + "types": "@type", + "prefix-name": "irigenerator:prefix-name", + "namespace": "irigenerator:namespace" + } + }, + "generators": { + "@id": "irigenerator:generator", + "@type": "irigenerator:iri-generator", + "@context": { + "uri": "@id", + "types": "@type", + "uriSelector": "irigenerator:iri-selector", + "variableSelector": "irigenerator:variable-selector", + "uriTemplate": "irigenerator:iri-template" + } + } }, + "prefixes": [{ + "prefix-name": "eczm", + "namespace": "https://example.cogni.zone/model#" + }], "generators": [ { - "uriSelector": "select ?uri { ?uri a demo:One }", - "variableSelector": "select ?id where { <#{[uri]}> demo:id ?id }", + "uriSelector": "select ?uri { ?uri a eczm:One }", + "variableSelector": "select ?id where { <#{[uri]}> eczm:id ?id }", "uriTemplate": "#{[baseUri]}/#{[id]}" }, { - "uriSelector": "select ?uri { ?uri a demo:Two }", - "variableSelector": "select ?year ?sequence where { <#{[uri]}> demo:year ?year ; demo:sequence ?sequence}", + "uriSelector": "select ?uri { ?uri a eczm:Two }", + "variableSelector": "select ?year ?sequence where { <#{[uri]}> eczm:year ?year ; eczm:sequence ?sequence}", "uriTemplate": "#{[baseUri]}/#{[year]}/#{[sequence]}" } ] diff --git a/src/test/resources/irigenerator/demo/uri-generators.json5 b/src/test/resources/irigenerator/demo/uri-generators.json5 index ba71dad..89e4737 100644 --- a/src/test/resources/irigenerator/demo/uri-generators.json5 +++ b/src/test/resources/irigenerator/demo/uri-generators.json5 @@ -1,20 +1,20 @@ { prefixes: { - demo: "http://demo.com/model#" + "eczm": "https://example.cogni.zone/model#" }, generators: [ { id: "One", - uriSelector: "select ?uri { ?uri a demo:One }", - variableSelector: "select ?id where { <#{[uri]}> demo:id ?id }", + uriSelector: "select ?uri { ?uri a eczm:One }", + variableSelector: "select ?id where { <#{[uri]}> eczm:id ?id }", uriTemplate: "#{[baseUri]}/#{[id]}" }, { id: "Two", - uriSelector: "select ?uri { ?uri a demo:Two }", + uriSelector: "select ?uri { ?uri a eczm:Two }", variableSelector: "select ?year ?sequence where { \ - <#{[uri]}> demo:year ?year ; \ - demo:sequence ?sequence \ + <#{[uri]}> eczm:year ?year ; \ + eczm:sequence ?sequence \ }", uriTemplate: "#{[baseUri]}/#{[year]}/#{[sequence]}" } From aab67a7faa1072785e8434704a3243f4958ae4df Mon Sep 17 00:00:00 2001 From: psiotwo Date: Wed, 21 Aug 2024 09:47:52 +0200 Subject: [PATCH 53/58] refactor: test case naming --- .../irigenerator/demo/expected-model.ttl | 8 ---- .../irigenerator/demo/original-model.ttl | 8 ---- .../irigenerator/demo/uri-generators.json | 45 ------------------- .../irigenerator/demo/uri-generators.json5 | 22 --------- 4 files changed, 83 deletions(-) delete mode 100644 src/test/resources/irigenerator/demo/expected-model.ttl delete mode 100644 src/test/resources/irigenerator/demo/original-model.ttl delete mode 100644 src/test/resources/irigenerator/demo/uri-generators.json delete mode 100644 src/test/resources/irigenerator/demo/uri-generators.json5 diff --git a/src/test/resources/irigenerator/demo/expected-model.ttl b/src/test/resources/irigenerator/demo/expected-model.ttl deleted file mode 100644 index baddb9b..0000000 --- a/src/test/resources/irigenerator/demo/expected-model.ttl +++ /dev/null @@ -1,8 +0,0 @@ -@prefix eczm: . - - a eczm:One ; - eczm:id "5" . - - a eczm:Two ; - eczm:year "2021" ; - eczm:sequence "0005" . \ No newline at end of file diff --git a/src/test/resources/irigenerator/demo/original-model.ttl b/src/test/resources/irigenerator/demo/original-model.ttl deleted file mode 100644 index bf9bfad..0000000 --- a/src/test/resources/irigenerator/demo/original-model.ttl +++ /dev/null @@ -1,8 +0,0 @@ -@prefix eczm: . - - a eczm:One ; - eczm:id "5" . - - a eczm:Two ; - eczm:year "2021" ; - eczm:sequence "0005" . \ No newline at end of file diff --git a/src/test/resources/irigenerator/demo/uri-generators.json b/src/test/resources/irigenerator/demo/uri-generators.json deleted file mode 100644 index ef6f6d3..0000000 --- a/src/test/resources/irigenerator/demo/uri-generators.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "@context": { - "@version": 1.1, - "irigenerator": "https://data.cogni.zone/voc/irigenerator/", - "uri": "@id", - "types": "@type", - "prefixes": { - "@id": "irigenerator:prefix", - "@type": "irigenerator:prefix-class", - "@context": { - "uri": "@id", - "types": "@type", - "prefix-name": "irigenerator:prefix-name", - "namespace": "irigenerator:namespace" - } - }, - "generators": { - "@id": "irigenerator:generator", - "@type": "irigenerator:iri-generator", - "@context": { - "uri": "@id", - "types": "@type", - "uriSelector": "irigenerator:iri-selector", - "variableSelector": "irigenerator:variable-selector", - "uriTemplate": "irigenerator:iri-template" - } - } - }, - "prefixes": [{ - "prefix-name": "eczm", - "namespace": "https://example.cogni.zone/model#" - }], - "generators": [ - { - "uriSelector": "select ?uri { ?uri a eczm:One }", - "variableSelector": "select ?id where { <#{[uri]}> eczm:id ?id }", - "uriTemplate": "#{[baseUri]}/#{[id]}" - }, - { - "uriSelector": "select ?uri { ?uri a eczm:Two }", - "variableSelector": "select ?year ?sequence where { <#{[uri]}> eczm:year ?year ; eczm:sequence ?sequence}", - "uriTemplate": "#{[baseUri]}/#{[year]}/#{[sequence]}" - } - ] -} \ No newline at end of file diff --git a/src/test/resources/irigenerator/demo/uri-generators.json5 b/src/test/resources/irigenerator/demo/uri-generators.json5 deleted file mode 100644 index 89e4737..0000000 --- a/src/test/resources/irigenerator/demo/uri-generators.json5 +++ /dev/null @@ -1,22 +0,0 @@ -{ - prefixes: { - "eczm": "https://example.cogni.zone/model#" - }, - generators: [ - { - id: "One", - uriSelector: "select ?uri { ?uri a eczm:One }", - variableSelector: "select ?id where { <#{[uri]}> eczm:id ?id }", - uriTemplate: "#{[baseUri]}/#{[id]}" - }, - { - id: "Two", - uriSelector: "select ?uri { ?uri a eczm:Two }", - variableSelector: "select ?year ?sequence where { \ - <#{[uri]}> eczm:year ?year ; \ - eczm:sequence ?sequence \ - }", - uriTemplate: "#{[baseUri]}/#{[year]}/#{[sequence]}" - } - ] -} \ No newline at end of file From 2746800fe26e351a036dfc6b19ac069d5cb5c4a8 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Wed, 4 Sep 2024 16:16:33 +0300 Subject: [PATCH 54/58] Update build.gradle.kts --- build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 7349e4f..75aa60d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -50,7 +50,6 @@ scmVersion { } - pmd { isIgnoreFailures = true isConsoleOutput = true From 6a2f07c5168cc5ecddef205e8cd9bfc625d5f12c Mon Sep 17 00:00:00 2001 From: psiotwo Date: Thu, 5 Sep 2024 10:27:56 +0200 Subject: [PATCH 55/58] fix: rebasing to main --- .../urigenerator/UriGeneratorCalculator.java | 283 ------------------ .../asquare/cube/urigenerator/Utils.java | 19 -- .../cube/urigenerator/json/Prefix.java | 23 -- .../cube/urigenerator/json/UriGenerator.java | 34 --- .../urigenerator/json/UriGeneratorRoot.java | 37 --- 5 files changed, 396 deletions(-) delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java delete mode 100644 src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java deleted file mode 100644 index 9bf02fd..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/UriGeneratorCalculator.java +++ /dev/null @@ -1,283 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -import org.apache.commons.lang3.StringUtils; -import org.apache.jena.query.Query; -import org.apache.jena.query.QueryFactory; -import org.apache.jena.query.QuerySolutionMap; -import org.apache.jena.query.ResultSet; -import org.apache.jena.rdf.model.Model; -import org.apache.jena.rdf.model.RDFNode; -import org.apache.jena.rdf.model.ResourceFactory; -import org.apache.jena.util.ResourceUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import zone.cogni.asquare.cube.spel.TemplateService; -import zone.cogni.asquare.cube.urigenerator.json.UriGenerator; -import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; -import zone.cogni.asquare.triplestore.RdfStoreServiceAPI; -import zone.cogni.asquare.triplestore.InternalRdfStoreService; -import zone.cogni.sem.jena.template.JenaQueryUtils; - -import jakarta.annotation.Nonnull; - -import java.io.StringWriter; -import java.net.URL; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -public class UriGeneratorCalculator { - private static final Logger log = LoggerFactory.getLogger(UriGeneratorCalculator.class); - public static final int EXPECTED_ROW_COUNT = 1; - - private final String newUriPrefix; - private final TemplateService templateService; - private final UriGeneratorRoot uriGeneratorRoot; - private final Map preparedStatements = new HashMap<>(); - - public UriGeneratorCalculator( - String newUriPrefix, - TemplateService templateService, - URL uriGeneratorRootResource, - Format format - ) { - this.newUriPrefix = newUriPrefix; - this.templateService = templateService; - this.uriGeneratorRoot = Utils.load(uriGeneratorRootResource, format); - initPreparedStatements(); - } - - private void initPreparedStatements() { - preparedStatements.put("exists-uri", QueryFactory.create("ask { { ?x ?p ?o } union { ?s ?p ?x } } ")); - } - - public Model convert(Model model, Map context) { - try { - final RdfStoreServiceAPI rdfStore = getRdfStore(model); - final List results = getGeneratorResults(rdfStore); - - int replaceCount = inputValidations(model, results); - processReplacements(model, rdfStore, replaceCount, context, results); - - validate(model); - - return model; - } catch(RuntimeException e) { - throw new RuntimeException("An error occurred during URI generation", e); - } - } - - @Nonnull - private List getGeneratorResults(RdfStoreServiceAPI rdfStore) { - return uriGeneratorRoot.getGenerators() - .stream() - .map(generator -> getUriGeneratorResult(rdfStore, generator)) - .collect(Collectors.toList()); - } - - @Nonnull - private UriGeneratorResult getUriGeneratorResult(RdfStoreServiceAPI rdfStore, UriGenerator generator) { - UriGeneratorResult uriGeneratorResult = new UriGeneratorResult(); - uriGeneratorResult.setGenerator(generator); - uriGeneratorResult.setUris(getNewSelectorUris(rdfStore, generator)); - return uriGeneratorResult; - } - - /** - * @return number of uris to be replaces - */ - private int inputValidations(final Model model, final List results) { - final Set incomingUris = getProblemUris(model); - - final Set selectedUris = new HashSet<>(); - final Set duplicates = results.stream() - .flatMap(result -> result.getUris().stream()) - .filter(uri -> !selectedUris.add(uri)) - .collect(Collectors.toSet()); - - if (!duplicates.isEmpty()) - log.error("some uris matched multiple selectors: {}", duplicates); - - final int size = incomingUris.size(); - if (size != selectedUris.size()) - log.error("incoming uris and selected uris do not match up." + - "\n\t incoming: {}" + - "\n\t selected: {}", incomingUris, selectedUris); - - if (!duplicates.isEmpty() || size != selectedUris.size()) - throw new RuntimeException("some validations failed when converting new uris, check logs for more info"); - - log.info("(uri generator) replacing {} uris", size); - return size; - } - - private void processReplacements(final Model model, - final RdfStoreServiceAPI rdfStore, - int replaceCount, - final Map context, - final List results) { - int loopCount = 0; - while (true) { - int count = calculateReplacementUrisLoop(model, rdfStore, context, results); - replaceCount -= count; - - log.info("(uri generator) loop {} processed {} uris", ++loopCount, count); - - // stop loop when all uris are processed - if (replaceCount == 0) break; - - // stop loop when no replacement where processed - if (count == 0) break; - } - } - - private int calculateReplacementUrisLoop(final Model model, - final RdfStoreServiceAPI rdfStore, - final Map context, - final List results) { - final AtomicInteger count = new AtomicInteger(); - - results.forEach(result -> result.getUris().forEach(uri -> { - if (result.alreadyReplaced(uri)) return; - - final Optional possibleNewUri = calculateNewUri(rdfStore, context, result, uri); - if (possibleNewUri.isPresent()) { - count.addAndGet(1); - result.addReplacement(uri, possibleNewUri.get()); - ResourceUtils.renameResource(model.getResource(uri), possibleNewUri.get()); - } - })); - - return count.get(); - } - - private Optional calculateNewUri(final RdfStoreServiceAPI rdfStore, - final Map context, - final UriGeneratorResult result, - final String oldUri) { - if (log.isTraceEnabled()) log.trace("calculate new uri for {}", oldUri); - traceModel(rdfStore); - - final Map variables = new HashMap<>(context); - variables.put("uri", oldUri); - - // variable template can also NOT exist: then this step is skipped! - final String variableSelector = result.getGenerator().getFullVariableSelector(); - if (StringUtils.isNotBlank(variableSelector)) { - final String variableTemplateQuery = uriGeneratorRoot.getPrefixQuery() + variableSelector; - final String variableQuery = templateService.processTemplate(variableTemplateQuery, variables); - if (log.isTraceEnabled()) log.trace("query: {}", variableQuery); - - final Supplier contextSupplier = () -> result.getGenerator().getId(); - final Optional> variableMap = getQueryMap(contextSupplier, rdfStore, variableQuery); - - // if one of template variables is still a new URI we should skip calculation for now - if (variableMap.isEmpty()) return Optional.empty(); - - final Map map = variableMap.get(); - if (log.isTraceEnabled()) log.trace("query result: {}", map); - variables.putAll(map); - } - if (log.isTraceEnabled()) log.debug("variables: {}", variables); - - final String uriTemplate = result.getGenerator().getUriTemplate(); - final String newUri = templateService.processTemplate(uriTemplate, variables); - - if (existsInModel(rdfStore, newUri)) - throw new RuntimeException("uri overlap found for " + newUri); - - return Optional.of(newUri); - } - - private void traceModel(RdfStoreServiceAPI rdfStore) { - if (!log.isTraceEnabled()) return; - - final Model trace = rdfStore.executeConstructQuery("construct {?s ?p ?o} where {?s ?p ?o}"); - final StringWriter out = new StringWriter(); - trace.write(out, "ttl"); - log.trace("model: {}", out); - } - - private boolean existsInModel(RdfStoreServiceAPI rdfStore, String newUri) { - final QuerySolutionMap querySolution = new QuerySolutionMap(); - querySolution.add("x", ResourceFactory.createResource(newUri)); - - return rdfStore.executeAskQuery(preparedStatements.get("exists-uri"), querySolution); - } - - /** - * @return empty optional if one of resources start with a newUriPrefix ! - * else a map of variables to be used in uri template! - */ - private Optional> getQueryMap(Supplier context, - RdfStoreServiceAPI rdfStore, - String variableQuery) { - final List> result1 = rdfStore.executeSelectQuery(variableQuery, JenaQueryUtils::convertToListOfMaps); - if (result1.size() != EXPECTED_ROW_COUNT) - throw new RuntimeException("[" + context.get() + "] expected 1 row, found " + result1); - - final Map nodeMap = result1.get(0); - boolean isBadMatch = nodeMap.values() - .stream() - .peek(node -> nonNullCheck(nodeMap, node)) - .anyMatch(node -> node.isURIResource() - && node.asResource().getURI().startsWith(newUriPrefix)); - if (isBadMatch) return Optional.empty(); - - final Map result = new HashMap<>(); - nodeMap.forEach((k, v) -> result.put(k, (v.isResource() ? v.asResource().getURI() : v.asLiteral().getString()))); - - return Optional.of(result); - } - - private void nonNullCheck(Map nodeMap, RDFNode node) { - if (node == null) throw new RuntimeException("variableSelector result has some null values: " + nodeMap); - } - - private Set getNewSelectorUris(RdfStoreServiceAPI rdfStore, UriGenerator generator) { - final String query = uriGeneratorRoot.getPrefixQuery() + generator.getFullUriSelector(); - return rdfStore - .executeSelectQuery(query, UriGeneratorCalculator::convertToList).stream() - .filter(uri -> uri.startsWith(newUriPrefix)) - .collect(Collectors.toSet()); - } - - private static List convertToList(ResultSet resultSet) { - List result = new ArrayList<>(); - - resultSet.forEachRemaining(querySolution -> - result.add(querySolution.get("uri").asResource().getURI()) - ); - - return result; - } - - private RdfStoreServiceAPI getRdfStore(Model model) { - return new InternalRdfStoreService(model); - } - - private void validate(Model model) { - Set problemUris = getProblemUris(model); - - if (!problemUris.isEmpty()) throw new RuntimeException("some uris could not be replaced: " + problemUris); - } - - @Nonnull - private Set getProblemUris(Model model) { - Set problemUris = new HashSet<>(); - model.listStatements() - .forEachRemaining(statement -> { - if (statement.getSubject().getURI().startsWith(newUriPrefix)) { - problemUris.add(statement.getSubject().getURI()); - } - - if (statement.getObject().isURIResource() - && statement.getObject().asResource().getURI().startsWith(newUriPrefix)) { - problemUris.add(statement.getObject().asResource().getURI()); - } - }); - return problemUris; - } - -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java deleted file mode 100644 index 2db6b35..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/Utils.java +++ /dev/null @@ -1,19 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator; - -import com.fasterxml.jackson.databind.ObjectMapper; -import zone.cogni.asquare.cube.json5.Json5Light; -import zone.cogni.asquare.cube.urigenerator.json.UriGeneratorRoot; - -import java.io.IOException; -import java.net.URL; - -public class Utils { - public static UriGeneratorRoot load(URL resource, Format format) { - try { - ObjectMapper mapper = format.equals(Format.JSON5) ? Json5Light.getJson5Mapper() : JsonLdObjectMapperFactory.getJsonLdMapper(); - return mapper.readValue(resource.openStream(), UriGeneratorRoot.class); - } catch (IOException e) { - throw new RuntimeException("Unable to load uri generator configuration." + resource, e); - } - } -} \ No newline at end of file diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java deleted file mode 100644 index 46c4108..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/Prefix.java +++ /dev/null @@ -1,23 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator.json; - -import cz.cvut.kbss.jopa.model.annotations.Id; -import cz.cvut.kbss.jopa.model.annotations.OWLClass; -import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty; -import lombok.Data; -import zone.cogni.asquare.cube.urigenerator.Vocabulary; - -import java.net.URI; - -@Data -@OWLClass(iri = Vocabulary.C_PREFIX) -public class Prefix { - - @Id - private URI id; - - @OWLDataProperty(iri = Vocabulary.P_PREFIX_NAME) - private String key; - - @OWLDataProperty(iri = Vocabulary.P_NAMESPACE) - private String value; -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java deleted file mode 100644 index 5d87c1d..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGenerator.java +++ /dev/null @@ -1,34 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator.json; - -import cz.cvut.kbss.jopa.model.annotations.Id; -import cz.cvut.kbss.jopa.model.annotations.OWLClass; -import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty; -import lombok.Data; -import zone.cogni.asquare.cube.urigenerator.Vocabulary; - -@Data -@OWLClass(iri = Vocabulary.C_IRI_GENERATOR) -public class UriGenerator { - - @Id - private String id; - - @OWLDataProperty(iri = Vocabulary.P_IRI_SELECTOR) - private String uriSelector; - - @OWLDataProperty(iri = Vocabulary.P_VARIABLE_SELECTOR) - private String variableSelector; - - @OWLDataProperty(iri = Vocabulary.P_IRI_TEMPLATE) - private String uriTemplate; - - public String getFullUriSelector() { - if (uriSelector == null) return ""; - return uriSelector; - } - - public String getFullVariableSelector() { - if (variableSelector == null) return ""; - return variableSelector; - } -} diff --git a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java b/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java deleted file mode 100644 index 900b9da..0000000 --- a/src/main/java/zone/cogni/asquare/cube/urigenerator/json/UriGeneratorRoot.java +++ /dev/null @@ -1,37 +0,0 @@ -package zone.cogni.asquare.cube.urigenerator.json; - -import cz.cvut.kbss.jopa.model.annotations.Id; -import cz.cvut.kbss.jopa.model.annotations.OWLClass; -import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty; -import lombok.Data; -import org.apache.commons.lang3.StringUtils; -import zone.cogni.asquare.cube.urigenerator.Vocabulary; - -import java.net.URI; -import java.util.List; -import java.util.stream.Collectors; - -@Data -@OWLClass(iri = Vocabulary.C_GENERATOR_SPECIFICATION) -public class UriGeneratorRoot { - - @Id - private URI id; - - @OWLObjectProperty(iri = Vocabulary.P_PREFIX) - private List prefixes; -// private Map prefixes; - - @OWLObjectProperty(iri = Vocabulary.P_GENERATOR) - private List generators; - - public String getPrefixQuery() { - return prefixes -// .entrySet() - .stream() - .map(e -> "PREFIX " - + StringUtils.rightPad(e.getKey() + ":", 8) + " <" + e.getValue() + ">\n") - .collect(Collectors.joining()) - + "\n"; - } -} From 92ae40a8197eaf4f5e03aff65c65706cf2a365fb Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Thu, 5 Sep 2024 12:13:16 +0300 Subject: [PATCH 56/58] Delete LICENSE.txt --- LICENSE.txt | 201 ---------------------------------------------------- 1 file changed, 201 deletions(-) delete mode 100644 LICENSE.txt diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index df7f8b1..0000000 --- a/LICENSE.txt +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright 2024 Cognizone (BV) - -Licensed 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. \ No newline at end of file From 20da516690dd6a9d74e077506893a5e286b90804 Mon Sep 17 00:00:00 2001 From: salihkadir <139787733+salihkadir@users.noreply.github.com> Date: Thu, 5 Sep 2024 13:16:31 +0300 Subject: [PATCH 57/58] Update build.gradle.kts --- build.gradle.kts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 75aa60d..c012c70 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -156,16 +156,7 @@ tasks.withType { } signing { - useInMemoryPgpKeys( - project.findProperty("signing.keyId")?.toString(), - project.findProperty("signing.password")?.toString(), - project.findProperty("signing.secretKeyRingFile")?.toString() - ) if (project.hasProperty("publishToMavenCentral")) { sign(publishing.publications["mavenJava"]) } } - -tasks.withType { - dependsOn(tasks.withType()) -} From bd908c5ac6a2142fde3c2e7c52c7179945898009 Mon Sep 17 00:00:00 2001 From: psiotwo Date: Thu, 5 Sep 2024 12:21:27 +0200 Subject: [PATCH 58/58] fix: fixed version for spring --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index c012c70..f56912f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,6 @@ val jenaVersion = "4.10.0" val guavaVersion = "33.3.0-jre" -val springVersion = "5.3.+" +val springVersion = "5.3.39" val jakartaAnnotationApiVersion = "3.0.0" val jb4jsonldJacksonVersion = "0.14.3" val logbackVersion = "1.5.7"