Skip to content

Commit

Permalink
Merge branch 'shacl-1.4.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
HolgerKnublauch committed Oct 8, 2021
2 parents 22dc34a + 3218860 commit 5f595af
Show file tree
Hide file tree
Showing 152 changed files with 4,795 additions and 6,206 deletions.
9 changes: 6 additions & 3 deletions .settings/org.eclipse.jdt.core.prefs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
org.eclipse.jdt.core.compiler.compliance=11
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=11
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ This API also serves as a reference implementation of the SHACL spec.
Coverage:
* [SHACL Core and SHACL-SPARQL validation](https://www.w3.org/TR/shacl/)
* [SHACL Advanced Features (Rules etc)](https://www.w3.org/TR/shacl-af/)
* [SHACL JavaScript Extensions](https://www.w3.org/TR/shacl-js/)
* [SHACL Compact Syntax](https://w3c.github.io/shacl/shacl-compact-syntax/)

Former Coverage until version 1.3.2
* [SHACL JavaScript Extensions](https://www.w3.org/TR/shacl-js/)

The TopBraid SHACL API is internally used by the European Commission's generic [SHACL-based RDF validator](https://www.itb.ec.europa.eu/shacl/any/upload) (used to validate RDF content against SHACL shapes)
and [SHACL shape validator](https://www.itb.ec.europa.eu/shacl/shacl/upload) (used to validate SHACL shapes themselves).

The same code is used in the TopBraid products (currently aligned with the TopBraid 6.3 release).
The same code is used in the TopBraid products (currently aligned with the TopBraid 7.1 release).

Feedback and questions should become GitHub issues or sent to TopBraid Users mailing list:
https://groups.google.com/forum/#!forum/topbraid-users
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

<groupId>org.topbraid</groupId>
<artifactId>shacl</artifactId>
<version>1.3.3-SNAPSHOT</version>
<version>1.4.0</version>
<packaging>jar</packaging>

<name>TopBraid SHACL API</name>
Expand Down Expand Up @@ -63,7 +63,7 @@
<url>https://github.com/TopQuadrant/shacl</url>
<connection>scm:git:https://github.com/TopQuadrant/shacl</connection>
<developerConnection>scm:git:[email protected]:TopQuadrant/shacl.git</developerConnection>
<tag>shacl-1.3.2</tag>
<tag>shacl-1.4.0</tag>
</scm>

<properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.util.Iterator;

import org.apache.jena.query.ARQ;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.sparql.function.FunctionFactory;
import org.apache.jena.sparql.function.FunctionRegistry;
Expand Down Expand Up @@ -59,26 +60,45 @@ public class CurrentThreadFunctionRegistry extends FunctionRegistry {

private static ThreadLocal<CurrentThreadFunctions> localFunctions = new ThreadLocal<>();

private static CurrentThreadFunctionRegistry singleton = new CurrentThreadFunctionRegistry(FunctionRegistry.get());


public static CurrentThreadFunctionRegistry get() {
return singleton;
}


/**
* Registers a set of extra SPIN functions from a given Model for the current
* Thread.
* @param model the Model containing the SPIN functions
* @return any old object that was registered for the current Thread, so that
* the old value can be restored when done.
* @return a Runnable that must be called (in a finally block) when done to restore the previous state
*/
public static CurrentThreadFunctions register(Model model) {
public static Runnable register(Model model) {
CurrentThreadFunctions old = localFunctions.get();
CurrentThreadFunctions neo = new CurrentThreadFunctions(model);
localFunctions.set(neo);
return old;
FunctionRegistry oldFR = FunctionRegistry.get();
if(oldFR != singleton) {
FunctionRegistry.set(ARQ.getContext(), singleton);
return () -> {
unregister(old);
FunctionRegistry.set(ARQ.getContext(), oldFR);
};
}
else {
return () -> {
unregister(old);
};
}
}


/**
* Unregisters the current Model for the current Thread.
* @param old the old functions that shall be restored or null
*/
public static void unregister(CurrentThreadFunctions old) {
private static void unregister(CurrentThreadFunctions old) {
if(old != null) {
localFunctions.set(old);
}
Expand All @@ -93,7 +113,7 @@ public static CurrentThreadFunctions getFunctions() {

private FunctionRegistry base;

public CurrentThreadFunctionRegistry(FunctionRegistry base) {
private CurrentThreadFunctionRegistry(FunctionRegistry base) {
this.base = base;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@
import org.apache.jena.rdf.model.StmtIterator;
import org.topbraid.jenax.util.JenaDatatypes;
import org.topbraid.jenax.util.JenaUtil;
import org.topbraid.shacl.arq.SHACLFunctionDriver;
import org.topbraid.shacl.arq.functions.SHACLSPARQLFunctionDriver;
import org.topbraid.shacl.vocabulary.DASH;
import org.topbraid.shacl.vocabulary.SH;


/**
* The singleton that creates ARQ FunctionFactories from (SHACL, SPIN) function declarations.
* Can be used by applications to install a different singleton with support
* for different kinds of functions, such as SPINx.
* for different kinds of functions, such as SHACL-JS or Script-based functions.
*
* @author Holger Knublauch
*/
Expand All @@ -58,9 +58,8 @@ public static void set(DeclarativeFunctionDrivers value) {
private Map<Property,DeclarativeFunctionDriver> drivers = new HashMap<>();

DeclarativeFunctionDrivers() {
register(SH.ask, new SHACLFunctionDriver());
register(SH.select, new SHACLFunctionDriver());
register(SH.jsLibrary, new SHACLFunctionDriver());
register(SH.ask, new SHACLSPARQLFunctionDriver());
register(SH.select, new SHACLSPARQLFunctionDriver());
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,6 @@ public Iterator<Node> listGraphNodes() {


@Override
public PrefixMap prefixes() {
return Prefixes.adapt(dataset.getPrefixMapping());
}


@Override
public Iterator<Quad> find(Node g, Node s, Node p, Node o) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException();
Expand Down Expand Up @@ -239,4 +233,14 @@ public void end() {
public boolean supportsTransactions() {
return dataset.supportsTransactions();
}


@Override
public PrefixMap prefixes() {
Model defaultModel = dataset.getDefaultModel();
if (defaultModel != null) {
return Prefixes.adapt(defaultModel);
}
return null;
}
}
58 changes: 33 additions & 25 deletions src/main/java/org/topbraid/jenax/util/DiffGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,21 @@
import org.apache.jena.util.iterator.ExtendedIterator;


// TODO: note this graph does not correctly implement GraphWithPerform and event notification contracts
/**
* A WrappedGraph that filters out deleted triples or adds added triples, without
* modifying the underlying base graph.
*
* Similar to BufferingGraph in TopBraid, but with minimal code dependencies
* and simpler contracts that are just right for use in SPARQLMotion.
* This class is for single-threaded use only, typically used as temporary graph layer on top of an existing
* graph for the duration of some algorithm.
*
* This runs in two modes, based on the updateBaseGraph flag.
*
* By default/legacy (false) the system will only add triples that exist in none of the subgraphs of the delegate graph
* and claim to delete triples even if they exist in subgraphs only.
*
* If true, the adds will always be applied even if one of the subgraphs already contains the triple.
* This is making sure that transformations will always produce all requested triples.
* Furthermore this mode is more correct w.r.t. deletes because it will only allow deleting triples from the editable graph.
*
* @author Holger Knublauch
*/
Expand All @@ -32,16 +40,29 @@ public class DiffGraph extends TransparentWrappedGraph {
protected GraphWithPerform addedGraph = new GraphMem();

/**
* This Set has triples that are in the delegate but are excluded
* from the filtered graph.
* This Set has triples that are in the delegate but are excluded from the filtered graph.
*/
protected Set<Triple> deletedTriples = new HashSet<Triple>();
protected Set<Triple> deletedTriples = new HashSet<>();

private PrefixMapping pm;

// The graph that the triples will be added to
private Graph updateableGraph;


public DiffGraph(Graph base) {
super(base);
public DiffGraph(Graph delegate) {
this(delegate, false);
}


public DiffGraph(Graph delegate, boolean updateBaseGraph) {
super(delegate);
if(updateBaseGraph) {
updateableGraph = JenaUtil.getBaseGraph(delegate);
}
else {
updateableGraph = delegate;
}
}


Expand Down Expand Up @@ -91,7 +112,7 @@ public boolean contains(Triple t) {
// but sameValueAs then this code is incorrect.
// Specifically we should be able to show bugs with TDB which does
// something different from either equals or sameValueAs.
protected boolean containsByEquals(Graph g,Triple t) {
protected boolean containsByEquals(Graph g, Triple t) {
ExtendedIterator<Triple> it = g.find(t);
try {
while (it.hasNext()) {
Expand Down Expand Up @@ -179,34 +200,21 @@ public boolean isIsomorphicWith(Graph g) {
public void performAdd(Triple t) {
if (deletedTriples.contains(t)) {
deletedTriples.remove(t);
// getEventManager().notifyAddTriple(this, t);
}
else if (containsByEquals(addedGraph,t) || containsByEquals(base, t) ) {
// notify even unsuccessful adds - see javadoc for graphlistener
// getEventManager().notifyAddTriple(this, t);
}
else {
// addedGraph does notification for us.
else if(!containsByEquals(addedGraph, t) && !containsByEquals(updateableGraph, t)) {
addedGraph.add(t);
}
}


@Override
public void performDelete(Triple t) {
if( containsByEquals(addedGraph,t) ) {
// addedGraph does notification for us.
if(containsByEquals(addedGraph, t)) {
addedGraph.delete(t);
}
else if ( containsByEquals(base, t) ) {
else if(containsByEquals(updateableGraph, t)) {
deletedTriples.add(t);
// getEventManager().notifyDeleteTriple(this, t);
}
else {
// notify even unsuccessful deletes - see javadoc for graphlistener
// getEventManager().notifyDeleteTriple(this, t);
return;
}
}


Expand Down
3 changes: 2 additions & 1 deletion src/main/java/org/topbraid/jenax/util/ExceptionUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public static <EX extends Throwable> EX throwDeepCauseChecked(Throwable t, Class
}
catch (Exception e) {
try {
rslt = clazz.newInstance();
rslt = clazz.getDeclaredConstructor().newInstance();
rslt.initCause(t);
}
catch (Exception e1) {
Expand Down Expand Up @@ -166,6 +166,7 @@ public static String getDeepMessage(Throwable t) {
}

public static String getStackTrace(Throwable t) {
if (t == null) return null;
StringWriter writer = new StringWriter();
t.printStackTrace(new PrintWriter(writer));
return writer.getBuffer().toString();
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/org/topbraid/jenax/util/ExtraPrefixes.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ public class ExtraPrefixes {
private static Map<String,String> map = new HashMap<String,String>();

static {
map.put("afn", "http://jena.apache.org/ARQ/function#");
map.put("fn", "http://www.w3.org/2005/xpath-functions#");
map.put("jfn", "java:org.apache.jena.sparql.function.library.");
map.put("afn", "http://jena.hpl.hp.com/ARQ/function#");
map.put("fn", "http://www.w3.org/2005/xpath-functions#");
map.put("jfn", "java:org.apache.jena.sparql.function.library.");
map.put("list", "http://jena.apache.org/ARQ/list#");
map.put("pf", "http://jena.apache.org/ARQ/property#");
map.put("smf", "http://topbraid.org/sparqlmotionfunctions#");
map.put("pf", "http://jena.hpl.hp.com/ARQ/property#");
map.put("smf", "http://topbraid.org/sparqlmotionfunctions#");
map.put("tops", "http://www.topbraid.org/tops#");
}

Expand Down
14 changes: 10 additions & 4 deletions src/main/java/org/topbraid/jenax/util/JenaUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
import org.apache.jena.sparql.util.Context;
import org.apache.jena.sparql.util.NodeFactoryExtra;
import org.apache.jena.sparql.util.NodeUtils;
import org.apache.jena.util.iterator.ExtendedIterator;
import org.apache.jena.vocabulary.OWL;
import org.apache.jena.vocabulary.RDF;
import org.apache.jena.vocabulary.RDFS;
Expand Down Expand Up @@ -498,11 +499,12 @@ public static Literal getBestStringLiteral(Resource resource, List<String> langs
}


public static Literal getBestStringLiteral(Resource resource, List<String> langs, Iterable<Property> properties, BiFunction<Resource,Property,Iterator<Statement>> getter) {
public static Literal getBestStringLiteral(Resource resource, List<String> langs, Iterable<Property> properties, BiFunction<Resource,Property,ExtendedIterator<Statement>> getter) {
String prefLang = langs.isEmpty() ? null : langs.get(0);
Literal label = null;
int bestLang = -1;
for(Property predicate : properties) {
Iterator<Statement> it = getter.apply(resource, predicate);
ExtendedIterator<Statement> it = getter.apply(resource, predicate);
while(it.hasNext()) {
RDFNode object = it.next().getObject();
if(object.isLiteral()) {
Expand All @@ -511,18 +513,22 @@ public static Literal getBestStringLiteral(Resource resource, List<String> langs
if(lang.length() == 0 && label == null) {
label = literal;
}
else if(prefLang != null && prefLang.equalsIgnoreCase(lang)) {
it.close();
return literal;
}
else {
// 1) Never use a less suitable language
// 2) Never replace an already existing label (esp: skos:prefLabel) unless new lang is better
// 3) Fall back to more special languages if no other was found (e.g. use en-GB if only "en" is accepted)
int startLang = bestLang < 0 ? langs.size() - 1 : (label != null ? bestLang - 1 : bestLang);
for(int i = startLang; i >= 0; i--) {
for(int i = startLang; i > 0; i--) {
String langi = langs.get(i);
if(langi.equalsIgnoreCase(lang)) {
label = literal;
bestLang = i;
}
else if(lang.contains("-") && NodeFunctions.langMatches(lang, langi) && label == null) {
else if(label == null && lang.contains("-") && NodeFunctions.langMatches(lang, langi)) {
label = literal;
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/topbraid/shacl/arq/SHACLARQFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.query.Dataset;
import org.apache.jena.query.DatasetFactory;
import org.apache.jena.query.QuerySolution;
import org.apache.jena.query.QuerySolutionMap;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.sparql.core.DatasetImpl;
import org.apache.jena.sparql.core.Substitute;
import org.apache.jena.sparql.engine.binding.Binding;
import org.apache.jena.sparql.expr.Expr;
Expand All @@ -43,8 +43,8 @@
import org.apache.jena.sparql.sse.SSE;
import org.apache.jena.sparql.util.ExprUtils;
import org.apache.jena.sparql.util.FmtUtils;
import org.topbraid.jenax.functions.OptionalArgsFunction;
import org.topbraid.jenax.functions.DeclarativeFunctionFactory;
import org.topbraid.jenax.functions.OptionalArgsFunction;
import org.topbraid.jenax.statistics.ExecStatistics;
import org.topbraid.jenax.statistics.ExecStatisticsManager;
import org.topbraid.jenax.util.JenaDatatypes;
Expand Down Expand Up @@ -154,7 +154,7 @@ else if(!optional.get(i)) {
}
}

Dataset dataset = DatasetImpl.wrap(env.getDataset());
Dataset dataset = DatasetFactory.wrap(env.getDataset());

if(ExecStatisticsManager.get().isRecording() && ExecStatisticsManager.get().isRecordingDeclarativeFunctions()) {
StringBuffer sb = new StringBuffer();
Expand Down
Loading

0 comments on commit 5f595af

Please sign in to comment.