You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2020/10/11 09:50:33 UTC

[jena] branch master updated: JENA-1979: Protect against complex paths for $PATH

This is an automated email from the ASF dual-hosted git repository.

andy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jena.git


The following commit(s) were added to refs/heads/master by this push:
     new 54b1f50  JENA-1979: Protect against complex paths for $PATH
     new 7e98a8a  Merge pull request #810 from afs/jena1979-shacl-path
54b1f50 is described below

commit 54b1f508498d172fe2f5d690a56eec525b681022
Author: Andy Seaborne <an...@apache.org>
AuthorDate: Sat Oct 10 16:14:14 2020 +0100

    JENA-1979: Protect against complex paths for $PATH
---
 .../org/apache/jena/shacl/engine/ShaclPaths.java   |  3 +-
 .../jena/shacl/engine/SparqlConstraints.java       | 53 ++++++++++++++++------
 .../constraint/ConstraintComponentSPARQL.java      |  4 +-
 .../shacl/engine/constraint/SparqlValidation.java  | 10 +++-
 4 files changed, 50 insertions(+), 20 deletions(-)

diff --git a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/ShaclPaths.java b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/ShaclPaths.java
index efdef05..f0266c0 100644
--- a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/ShaclPaths.java
+++ b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/ShaclPaths.java
@@ -204,8 +204,7 @@ public class ShaclPaths {
         if ( n == null )
             out.print(PathWriter.asString(path));
         else
-            nodeFmt.format(out, n);;
-
+            nodeFmt.format(out, n);
     }
 
 
diff --git a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/SparqlConstraints.java b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/SparqlConstraints.java
index a803675..5496027 100644
--- a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/SparqlConstraints.java
+++ b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/SparqlConstraints.java
@@ -18,6 +18,8 @@
 
 package org.apache.jena.shacl.engine;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.StringJoiner;
 
 import org.apache.jena.atlas.iterator.Iter;
@@ -49,15 +51,6 @@ public class SparqlConstraints {
     //        5.3.1 Pre-bound Variables in SPARQL Constraints ($this, $shapesGraph, $currentShape)
     //        5.3.2 Mapping of Solution Bindings to Result Properties
 
-    private static String prefixesQueryString = StrUtils.strjoinNL
-        ("PREFIX owl:     <http://www.w3.org/2002/07/owl#>"
-        ,"PREFIX sh:      <http://www.w3.org/ns/shacl#>"
-        ,"SELECT * { ?x sh:prefixes/owl:imports*/sh:declare [ sh:prefix ?prefix ; sh:namespace ?namespace ] }"
-        );
-    private static Query prefixesQuery = QueryFactory.create(prefixesQueryString);
-    private static Var varPrefix = Var.alloc("prefix");
-    private static Var varNamespace = Var.alloc("namespace");
-
     public static Constraint parseSparqlConstraint(Graph shapesGraph, Node shape, Node p, Node sparqlConstraintNode) {
         /*
            sh:sparql [
@@ -86,15 +79,34 @@ public class SparqlConstraints {
         String selectQuery = selectNode.getLiteralLexicalForm();
         // If parse error - constraint failure.
         String qs = prefixes+"\n"+selectQuery;
-        try { 
-            Query query = QueryFactory.create(qs);
-            String msg = (message != null && message.isLiteral() ? message.getLiteralLexicalForm() : null );
+        String msg = (message != null && message.isLiteral() ? message.getLiteralLexicalForm() : null );
+        try {
+            Query query = parseQueryString(qs);
             return new SparqlConstraint(query, msg);
         } catch (QueryParseException ex) {
+//            Log.warn("SHACL", "SPARQL parse error: "+ex.getMessage()+"\n"+qs);
+//            return new SparqlConstraint(new Query(), msg);
             throw new ShaclParseException("SPARQL parse error: "+ex.getMessage()+"\n"+qs);
         }
     }
-    
+
+    /** 
+     * Parse a string to produce a {@link Query}.
+     * All {@link Query} should go through this function to allow of inserting default prefixes. 
+     */
+    public static Query parseQueryString(String queryString) {
+        Query query = new Query();
+        // The SHACL spec does not define any default prefixes.
+        // But for identified practical reasons some may be added such as: 
+//        query.getPrefixMapping().setNsPrefix("owl",  OWL.getURI());
+//        query.getPrefixMapping().setNsPrefix("rdf",  RDF.getURI());
+//        query.getPrefixMapping().setNsPrefix("rdfs", RDFS.getURI());
+//        query.getPrefixMapping().setNsPrefix("sh",   SHACL.getURI());
+//        query.getPrefixMapping().setNsPrefix("xsd",  XSD.getURI());
+        QueryFactory.parse(query, queryString, null,  Syntax.defaultQuerySyntax);
+        return query;
+    }
+
     /**
      * Test for zero or one occurrences of a tripel pattern that is expected to be   
      * Returns false for zero, true for one. 
@@ -114,13 +126,21 @@ public class SparqlConstraints {
         finally { iter.close(); }
     }
 
-
+    private static String prefixesQueryString = StrUtils.strjoinNL
+        ("PREFIX owl:     <http://www.w3.org/2002/07/owl#>"
+        ,"PREFIX sh:      <http://www.w3.org/ns/shacl#>"
+        ,"SELECT * { ?x sh:prefixes/owl:imports*/sh:declare [ sh:prefix ?prefix ; sh:namespace ?namespace ] }"
+        );
+    private static Query prefixesQuery = QueryFactory.create(prefixesQueryString);
+    private static Var varPrefix = Var.alloc("prefix");
+    private static Var varNamespace = Var.alloc("namespace");
 
     public static String prefixes(Graph shapesGraph, Node sparqlNode) {
         // XXX Ignores sparqlNode ATM
         StringJoiner prefixesSJ = new StringJoiner("\n");
         QueryExecution qExec = QueryExecutionFactory.create(prefixesQuery, DatasetGraphFactory.wrap(shapesGraph));
         ResultSet rs = qExec.execSelect();
+        Map<String, String> seen = new HashMap<>();
 
         while(rs.hasNext()) {
             Binding binding = rs.nextBinding();
@@ -128,7 +148,12 @@ public class SparqlConstraints {
             Node nNamespace = binding.get(varNamespace);
             String prefix = nPrefix.getLiteralLexicalForm();
             String ns = nNamespace.getLiteralLexicalForm();
+            if ( seen.containsKey(prefix) ) {
+                if ( seen.get(prefix).equals(ns) )
+                    continue;
+            }
             prefixesSJ.add("PREFIX "+prefix+": <"+ns+">");
+            seen.put(prefix, ns);
         }
         return prefixesSJ.toString();
     }
diff --git a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ConstraintComponentSPARQL.java b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ConstraintComponentSPARQL.java
index 9060693..150d49e 100644
--- a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ConstraintComponentSPARQL.java
+++ b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/ConstraintComponentSPARQL.java
@@ -26,10 +26,10 @@ import org.apache.jena.ext.com.google.common.collect.Multimap;
 import org.apache.jena.graph.Graph;
 import org.apache.jena.graph.Node;
 import org.apache.jena.query.Query;
-import org.apache.jena.query.QueryFactory;
 import org.apache.jena.query.QueryParseException;
 import org.apache.jena.riot.out.NodeFormatter;
 import org.apache.jena.shacl.engine.Parameter;
+import org.apache.jena.shacl.engine.SparqlConstraints;
 import org.apache.jena.shacl.engine.ValidationContext;
 import org.apache.jena.shacl.parser.Constraint;
 import org.apache.jena.shacl.parser.ShaclParseException;
@@ -51,7 +51,7 @@ public class ConstraintComponentSPARQL implements Constraint {
 
         String qs =  sparqlConstraintComponent.getSparqlString();
         try {
-            this.query = QueryFactory.create(sparqlConstraintComponent.getSparqlString());
+            this.query = SparqlConstraints.parseQueryString(sparqlConstraintComponent.getSparqlString());
             if ( !query.isAskType() && !query.isSelectType() )
                 throw new ShaclParseException("Not a SELECT or ASK query");
         } catch (QueryParseException ex) {
diff --git a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/SparqlValidation.java b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/SparqlValidation.java
index d0b9130..51b85e3 100644
--- a/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/SparqlValidation.java
+++ b/jena-shacl/src/main/java/org/apache/jena/shacl/engine/constraint/SparqlValidation.java
@@ -234,8 +234,14 @@ import org.apache.jena.sparql.util.ModelUtils;
         }
         qsm.add("this", ModelUtils.convertGraphNodeToRDFNode(thisNode, model));
         if ( path != null ) {
-            RDFNode z = ModelUtils.convertGraphNodeToRDFNode(ShaclPaths.pathNode(path), model);
-            qsm.add("PATH" , z);
+            Node pn = ShaclPaths.pathNode(path);
+            // If 'path' can not be translated into a substituted form, then ignore
+            // PATH. This means that is the path is not a simple link, it could only be
+            // done by textually substitution of the SPARQL query string.
+            if ( pn != null ) {
+                RDFNode z = ModelUtils.convertGraphNodeToRDFNode(pn, model);
+                qsm.add("PATH", z);
+            }
         }
         return qsm;
     }