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 2019/04/24 07:59:59 UTC

[jena] branch master updated: Support configuring syntax for Parameterized SPARQL (JENA-1705)

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 9b1f2ea  Support configuring syntax for Parameterized SPARQL (JENA-1705)
     new a4717c2  Merge pull request #558 from rvesse/JENA-1705
9b1f2ea is described below

commit 9b1f2eab825519a1407c4be226275795b0b776b7
Author: Rob Vesse <rv...@apache.org>
AuthorDate: Tue Apr 23 10:16:23 2019 +0100

    Support configuring syntax for Parameterized SPARQL (JENA-1705)
    
    - Add getSyntax()/setSyntax()
    - Add overloads of asQuery() and asUpdate() that take the desired Syntax
    - Some white space and formatting clean up
---
 .../jena/query/ParameterizedSparqlString.java      | 178 ++++++++++++++-------
 1 file changed, 119 insertions(+), 59 deletions(-)

diff --git a/jena-arq/src/main/java/org/apache/jena/query/ParameterizedSparqlString.java b/jena-arq/src/main/java/org/apache/jena/query/ParameterizedSparqlString.java
index 6c02e26..b77b4de 100644
--- a/jena-arq/src/main/java/org/apache/jena/query/ParameterizedSparqlString.java
+++ b/jena-arq/src/main/java/org/apache/jena/query/ParameterizedSparqlString.java
@@ -34,22 +34,22 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import org.apache.jena.atlas.lib.Pair;
-import org.apache.jena.datatypes.RDFDatatype ;
-import org.apache.jena.graph.Node ;
-import org.apache.jena.graph.NodeFactory ;
+import org.apache.jena.datatypes.RDFDatatype;
+import org.apache.jena.graph.Node;
+import org.apache.jena.graph.NodeFactory;
 import org.apache.jena.iri.IRI;
-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.RDFNode ;
-import org.apache.jena.shared.PrefixMapping ;
-import org.apache.jena.shared.impl.PrefixMappingImpl ;
-import org.apache.jena.sparql.ARQException ;
-import org.apache.jena.sparql.serializer.SerializationContext ;
-import org.apache.jena.sparql.util.FmtUtils ;
-import org.apache.jena.sparql.util.NodeFactoryExtra ;
-import org.apache.jena.update.UpdateFactory ;
-import org.apache.jena.update.UpdateRequest ;
+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.RDFNode;
+import org.apache.jena.shared.PrefixMapping;
+import org.apache.jena.shared.impl.PrefixMappingImpl;
+import org.apache.jena.sparql.ARQException;
+import org.apache.jena.sparql.serializer.SerializationContext;
+import org.apache.jena.sparql.util.FmtUtils;
+import org.apache.jena.sparql.util.NodeFactoryExtra;
+import org.apache.jena.update.UpdateFactory;
+import org.apache.jena.update.UpdateRequest;
 
 /**
  * <p>
@@ -70,7 +70,8 @@ import org.apache.jena.update.UpdateRequest ;
  * Any variable in the command may have a value injected to it, injecting a
  * value replaces all usages of that variable in the command i.e. substitutes
  * the variable for a constant, injection is done by textual substitution.
- * </p> <h4>Positional Parameters</h4>
+ * </p>
+ * <h4>Positional Parameters</h4>
  * <p>
  * You can use JDBC style positional parameters if you prefer, a JDBC style
  * parameter is a single {@code ?} followed by whitespace or certain punctuation
@@ -78,10 +79,13 @@ import org.apache.jena.update.UpdateRequest ;
  * index which reflects the order in which they appear in the string. Positional
  * parameters use a zero based index.
  * </p>
- * <h4>Buffer Usage</h3> </p> Additionally you may use this purely as a
- * {@link StringBuffer} replacement for creating queries since it provides a
- * large variety of convenience methods for appending things either as-is or as
- * nodes (which causes appropriate formatting to be applied). </p>
+ * <h4>Buffer Usage</h3>
+ * </p>
+ * Additionally you may use this purely as a {@link StringBuffer} replacement
+ * for creating queries since it provides a large variety of convenience methods
+ * for appending things either as-is or as nodes (which causes appropriate
+ * formatting to be applied).
+ * </p>
  * <h3>Intended Usage</h3>
  * <p>
  * The intended usage of this is where using a {@link QuerySolutionMap} as
@@ -96,7 +100,8 @@ import org.apache.jena.update.UpdateRequest ;
  * variables</li>
  * <li>Defending against SPARQL injection when creating a query/update using
  * some external input, see SPARQL Injection notes for limitations.</li>
- * <li>Provide a more convenient way to prepend common prefixes to your query</li>
+ * <li>Provide a more convenient way to prepend common prefixes to your
+ * query</li>
  * </ul>
  * <p>
  * This class is useful for preparing both queries and updates hence the generic
@@ -144,6 +149,7 @@ public class ParameterizedSparqlString implements PrefixMapping {
     private Map<Integer, Node> positionalParams = new HashMap<>();
     private PrefixMapping prefixes;
     private Map<String, ValueReplacement> valuesReplacements = new HashMap<>();
+    private Syntax syntax = Syntax.defaultQuerySyntax;
 
     /**
      * Creates a new parameterized string
@@ -295,6 +301,31 @@ public class ParameterizedSparqlString implements PrefixMapping {
     }
 
     /**
+     * Gets the syntax used for parsing when calling {@link #asQuery()} or
+     * {@link #asUpdate()}
+     * 
+     * 
+     * @return Syntax
+     */
+    public Syntax getSyntax() {
+        return this.syntax;
+    }
+
+    /**
+     * Sets the syntax used for parsing when calling {@link #asQuery()} or
+     * {@link #asUpdate()}
+     * 
+     * @param syntax
+     *            Syntax
+     */
+    public void setSyntax(Syntax syntax) {
+        if (syntax == null)
+            return;
+
+        this.syntax = syntax;
+    }
+
+    /**
      * Sets the command text, overwriting any existing command text. If you want
      * to append to the command text use one of the {@link #append(String)},
      * {@link #appendIri(String)}, {@link #appendLiteral(String)} or
@@ -1160,7 +1191,7 @@ public class ParameterizedSparqlString implements PrefixMapping {
 
     /**
      * Clears the value for a variable or values parameter so the given variable
-     * will not     * have a value injected
+     * will not * have a value injected
      * 
      * @param var
      *            Variable
@@ -1212,10 +1243,8 @@ public class ParameterizedSparqlString implements PrefixMapping {
         Pattern p = Pattern.compile("\"[?$]" + var + "\"|'[?$]" + var + "'");
 
         if (p.matcher(command).find() && n.isLiteral()) {
-            throw new ARQException(
-                    "Command string is vunerable to injection attack, variable ?"
-                            + var
-                            + " appears surrounded directly by quotes and is bound to a literal which provides a SPARQL injection attack vector");
+            throw new ARQException("Command string is vunerable to injection attack, variable ?" + var
+                    + " appears surrounded directly by quotes and is bound to a literal which provides a SPARQL injection attack vector");
         }
 
         // Parse out delimiter info
@@ -1229,10 +1258,8 @@ public class ParameterizedSparqlString implements PrefixMapping {
 
             if (n.isLiteral()) {
                 if (delims.isInsideLiteral(posMatch.start(1), posMatch.end(1))) {
-                    throw new ARQException(
-                            "Command string is vunerable to injection attack, variable ?"
-                                    + var
-                                    + " appears inside of a literal and is bound to a literal which provides a SPARQL injection attack vector");
+                    throw new ARQException("Command string is vunerable to injection attack, variable ?" + var
+                            + " appears inside of a literal and is bound to a literal which provides a SPARQL injection attack vector");
                 }
             }
         }
@@ -1262,10 +1289,9 @@ public class ParameterizedSparqlString implements PrefixMapping {
         // Check each occurrence of the variable for safety
         if (n.isLiteral()) {
             if (delims.isInsideLiteral(position, position)) {
-                throw new ARQException(
-                        "Command string is vunerable to injection attack, a positional paramter (index "
-                                + index
-                                + ") appears inside of a literal and is bound to a literal which provides a SPARQL injection attack vector");
+                throw new ARQException("Command string is vunerable to injection attack, a positional paramter (index "
+                        + index
+                        + ") appears inside of a literal and is bound to a literal which provides a SPARQL injection attack vector");
             }
         }
     }
@@ -1335,7 +1361,7 @@ public class ParameterizedSparqlString implements PrefixMapping {
 
         // Inject Values Parameters
         command = applyValues(command, context);
-        
+
         // Then inject Positional Parameters
         // To do this we need to find the ? we will replace
         p = Pattern.compile("(\\?)[\\s;,.]");
@@ -1393,7 +1419,20 @@ public class ParameterizedSparqlString implements PrefixMapping {
      *                Thrown if the command text does not parse
      */
     public Query asQuery() throws QueryException {
-        return QueryFactory.create(this.toString());
+        return asQuery(this.syntax);
+    }
+
+    /**
+     * Attempts to take the command text with parameters injected from the
+     * {@link #toString()} method and parse it as a {@link Query} using the
+     * given {@link Syntax} syntax
+     * 
+     * @return Query if the command text is a valid SPARQL query
+     * @exception QueryException
+     *                Thrown if the command text does not parse
+     */
+    public Query asQuery(Syntax syntax) {
+        return QueryFactory.create(this.toString(), syntax);
     }
 
     /**
@@ -1404,7 +1443,19 @@ public class ParameterizedSparqlString implements PrefixMapping {
      *         (one/more update commands)
      */
     public UpdateRequest asUpdate() {
-        return UpdateFactory.create(this.toString());
+        return asUpdate(this.syntax);
+    }
+
+    /**
+     * Attempts to take the command text with parameters injected from the
+     * {@link #toString()} method and parse it as a {@link UpdateRequest} using
+     * the given {@link Syntax}
+     * 
+     * @return Update if the command text is a valid SPARQL Update request
+     *         (one/more update commands)
+     */
+    public UpdateRequest asUpdate(Syntax syntax) {
+        return UpdateFactory.create(this.toString(), syntax);
     }
 
     /**
@@ -1452,6 +1503,7 @@ public class ParameterizedSparqlString implements PrefixMapping {
                 copy.setParam(entry.getKey(), entry.getValue());
             }
         }
+        copy.setSyntax(copy.getSyntax());
         return copy;
     }
 
@@ -1467,9 +1519,9 @@ public class ParameterizedSparqlString implements PrefixMapping {
 
     @Override
     public PrefixMapping clearNsPrefixMap() {
-        return this.prefixes.clearNsPrefixMap() ;
+        return this.prefixes.clearNsPrefixMap();
     }
-    
+
     @Override
     public PrefixMapping setNsPrefixes(PrefixMapping other) {
         return this.prefixes.setNsPrefixes(other);
@@ -1519,12 +1571,12 @@ public class ParameterizedSparqlString implements PrefixMapping {
     public boolean hasNoMappings() {
         return this.prefixes.hasNoMappings();
     }
-    
+
     @Override
     public int numPrefixes() {
         return this.prefixes.numPrefixes();
-    }    
-    
+    }
+
     @Override
     public PrefixMapping lock() {
         return this.prefixes.lock();
@@ -1725,7 +1777,7 @@ public class ParameterizedSparqlString implements PrefixMapping {
                 return false;
             }
         }
-        
+
         @Override
         public String toString() {
             StringBuilder builder = new StringBuilder();
@@ -1742,14 +1794,14 @@ public class ParameterizedSparqlString implements PrefixMapping {
         }
 
     }
-    
+
     /**
      * Assign a VALUES valueName with a multiple items.<br>
      * Can be used to assign multiple values to a single variable or single
      * value to multiple variables (if using a List) in the SPARQL query.<br>
      * See setRowValues to assign multiple values to multiple variables.<br>
      * Using "valueName" with list(prop_A, obj_A) on query "VALUES (?p ?o)
-     * {?valueName}"     * would produce "VALUES (?p ?o) {(prop_A obj_A)}".
+     * {?valueName}" * would produce "VALUES (?p ?o) {(prop_A obj_A)}".
      *
      *
      * @param valueName
@@ -1758,10 +1810,10 @@ public class ParameterizedSparqlString implements PrefixMapping {
     public void setValues(String valueName, Collection<? extends RDFNode> items) {
         items.forEach(item -> validateParameterValue(item.asNode()));
 
-        //Ensure that a list is used for the items.
+        // Ensure that a list is used for the items.
         Collection<List<? extends RDFNode>> rowItems = new ArrayList<>();
         if (items instanceof List) {
-            rowItems.add((List<? extends RDFNode>)items);
+            rowItems.add((List<? extends RDFNode>) items);
         } else {
             rowItems.add(new ArrayList<>(items));
         }
@@ -1771,7 +1823,7 @@ public class ParameterizedSparqlString implements PrefixMapping {
     /**
      * Assign a VALUES valueName with a single item.<br>
      * Using "valueName" with Literal obj_A on query "VALUES ?o {?valueName}"
-     * would produce     * "VALUES ?o {obj_A}".
+     * would produce * "VALUES ?o {obj_A}".
      *
      * @param valueName
      * @param item
@@ -1781,8 +1833,7 @@ public class ParameterizedSparqlString implements PrefixMapping {
     }
 
     /**
-     * **
-     * Sets a map of VALUES valueNames and their items.<br>
+     * ** Sets a map of VALUES valueNames and their items.<br>
      * Can be used to assign multiple values to a single variable or single
      * value to multiple variables (if using a List) in the SPARQL query.<br>
      * See setRowValues to assign multiple values to multiple variables.
@@ -1797,7 +1848,7 @@ public class ParameterizedSparqlString implements PrefixMapping {
      * Allocate multiple lists of variables to a single VALUES valueName.<br>
      * Using "valuesName" with list(list(prop_A, obj_A), list(prop_B, obj_B)) on
      * query "VALUES (?p ?o) {?valuesName}" would produce "VALUES (?p ?o)
-     * {(prop_A obj_A)     * (prop_B obj_B)}".
+     * {(prop_A obj_A) * (prop_B obj_B)}".
      *
      * @param valueName
      * @param rowItems
@@ -1818,15 +1869,21 @@ public class ParameterizedSparqlString implements PrefixMapping {
     private static final String VALUES_KEYWORD = "values";
 
     protected static String[] extractTargetVars(String command, String valueName) {
-        String[] targetVars = new String[]{};
+        String[] targetVars = new String[] {};
 
         int valueIndex = command.indexOf(valueName);
         if (valueIndex > -1) {
-            String subCmd = command.substring(0, valueIndex).toLowerCase(); //Truncate the command at the valueName. Lowercase to search both cases of VALUES keyword.
+            // Truncate the command at the valueName.
+            // Lowercase to search both cases of VALUES keyword.
+            String subCmd = command.substring(0, valueIndex).toLowerCase();
             int valuesIndex = subCmd.lastIndexOf(VALUES_KEYWORD);
             int openBracesIndex = subCmd.lastIndexOf("{");
             int closeBracesIndex = subCmd.lastIndexOf("}");
-            if (valuesIndex > -1 && valuesIndex < openBracesIndex && closeBracesIndex < valuesIndex) { //Ensure that VALUES keyword is found, open braces index is located after the VALUES and any close braces is located before the VALUES.
+
+            // Ensure that VALUES keyword is found, open braces index is located
+            // after the VALUES and any close braces is located before the
+            // VALUES.
+            if (valuesIndex > -1 && valuesIndex < openBracesIndex && closeBracesIndex < valuesIndex) {
                 String vars = command.substring(valuesIndex + VALUES_KEYWORD.length(), openBracesIndex);
                 targetVars = vars.replaceAll("[(?$)]", "").trim().split(" ");
             }
@@ -1856,7 +1913,8 @@ public class ParameterizedSparqlString implements PrefixMapping {
 
             String[] targetVars = extractTargetVars(command, valueName);
             if (targetVars.length == 0) {
-                //VALUES keyword has not been found or there is another issue so do not modify the command.
+                // VALUES keyword has not been found or there is another issue
+                // so do not modify the command.
                 return command;
             }
 
@@ -1921,7 +1979,8 @@ public class ParameterizedSparqlString implements PrefixMapping {
         protected void validateValuesSafeToInject(String command, String[] targetVars) {
 
             if (targetVars.length == 1) {
-                //Single var with one or more items so all checked against the same var.
+                // Single var with one or more items so all checked against the
+                // same var.
                 String targetVar = targetVars[0];
                 for (List<? extends RDFNode> row : rowItems) {
                     for (RDFNode item : row) {
@@ -1929,7 +1988,7 @@ public class ParameterizedSparqlString implements PrefixMapping {
                     }
                 }
             } else {
-                //Multiple var with one or more rows.
+                // Multiple var with one or more rows.
                 for (int i = 0; i < targetVars.length; i++) {
                     String targetVar = targetVars[i];
                     for (List<? extends RDFNode> row : rowItems) {
@@ -1938,12 +1997,13 @@ public class ParameterizedSparqlString implements PrefixMapping {
                             validateSafeToInject(command, targetVar, item.asNode());
                         } else {
                             String rowString = row.stream().map(RDFNode::toString).collect(Collectors.joining(","));
-                            throw new ARQException("Number of VALUES variables (" + String.join(", ", targetVars) + ") does not equal replacement row (" + rowString + ").");
+                            throw new ARQException("Number of VALUES variables (" + String.join(", ", targetVars)
+                                    + ") does not equal replacement row (" + rowString + ").");
                         }
                     }
                 }
             }
         }
     }
-    
+
 }