You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by rv...@apache.org on 2012/11/19 20:26:09 UTC

svn commit: r1411358 - in /jena/trunk/jena-arq/src: main/java/com/hp/hpl/jena/sparql/function/ main/java/com/hp/hpl/jena/sparql/function/user/ test/java/com/hp/hpl/jena/sparql/function/ test/java/com/hp/hpl/jena/sparql/function/user/

Author: rvesse
Date: Mon Nov 19 19:26:08 2012
New Revision: 1411358

URL: http://svn.apache.org/viewvc?rev=1411358&view=rev
Log:
Initial framework for user defined functions

Added:
    jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/
    jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/ExprTransformExpand.java
    jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunction.java
    jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionDefinition.java
    jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionFactory.java
    jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/
    jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/
    jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS_UserFunctions.java
    jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestFunctionExpansion.java
    jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserDefinedFunctionFactory.java
    jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserFunctionsInSparql.java
Modified:
    jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Function.java
    jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/FunctionFactory.java

Modified: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Function.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Function.java?rev=1411358&r1=1411357&r2=1411358&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Function.java (original)
+++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Function.java Mon Nov 19 19:26:08 2012
@@ -30,7 +30,7 @@ public interface Function
     /** Called during query plan construction immediately after the
      * construction of the extension instance.
      * Can throw ExprBuildException if something is wrong (like wrong number of arguments). 
-     * @param args The parsed arguements
+     * @param args The parsed arguments
      */ 
     public void build(String uri, ExprList args) ;
 

Modified: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/FunctionFactory.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/FunctionFactory.java?rev=1411358&r1=1411357&r2=1411358&view=diff
==============================================================================
--- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/FunctionFactory.java (original)
+++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/FunctionFactory.java Mon Nov 19 19:26:08 2012
@@ -18,10 +18,18 @@
 
 package com.hp.hpl.jena.sparql.function;
 
+import com.hp.hpl.jena.sparql.sse.builders.ExprBuildException;
 
-/** Interface for function factories. */ 
-
+/**
+ *  Interface for function factories. 
+ */ 
 public interface FunctionFactory
 {
+    /**
+     * Create a function with the given URI
+     * @param uri URI
+     * @return Function
+     * @throws ExprBuildException May be thrown if there is a problem creating a function
+     */
     public Function create(String uri) ;
 }

Added: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/ExprTransformExpand.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/ExprTransformExpand.java?rev=1411358&view=auto
==============================================================================
--- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/ExprTransformExpand.java (added)
+++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/ExprTransformExpand.java Mon Nov 19 19:26:08 2012
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2012 YarcData LLC All Rights Reserved.
+ */ 
+
+package com.hp.hpl.jena.sparql.function.user;
+
+import java.util.Map;
+
+import com.hp.hpl.jena.sparql.algebra.Op;
+import com.hp.hpl.jena.sparql.expr.Expr;
+import com.hp.hpl.jena.sparql.expr.ExprFunction;
+import com.hp.hpl.jena.sparql.expr.ExprFunction0;
+import com.hp.hpl.jena.sparql.expr.ExprFunction1;
+import com.hp.hpl.jena.sparql.expr.ExprFunction2;
+import com.hp.hpl.jena.sparql.expr.ExprFunction3;
+import com.hp.hpl.jena.sparql.expr.ExprFunctionN;
+import com.hp.hpl.jena.sparql.expr.ExprFunctionOp;
+import com.hp.hpl.jena.sparql.expr.ExprList;
+import com.hp.hpl.jena.sparql.expr.ExprTransformCopy;
+
+/**
+ * An expression transformer that will expand user defined expressions so they do not explicitly rely on other user defined functions
+ * @author rvesse
+ *
+ */
+public class ExprTransformExpand extends ExprTransformCopy {
+    
+    private Map<String, UserDefinedFunctionDefinition> definitions;
+    
+    /**
+     * Creates a new transformer
+     * @param defs User defined function definitions
+     */
+    public ExprTransformExpand(Map<String, UserDefinedFunctionDefinition> defs) {
+        if (defs == null) throw new IllegalArgumentException("defs cannot be null");
+        this.definitions = defs;
+    }
+
+    @Override
+    public Expr transform(ExprFunction0 func) {
+        ExprFunction f = func.getFunction();
+        if (this.shouldExpand(f)) {
+            //TODO Need to expand the function
+            return super.transform(func);
+        } else {
+            return super.transform(func);
+        }
+    }
+
+    @Override
+    public Expr transform(ExprFunction1 func, Expr expr1) {
+        // TODO Auto-generated method stub
+        return super.transform(func, expr1);
+    }
+
+    @Override
+    public Expr transform(ExprFunction2 func, Expr expr1, Expr expr2) {
+        // TODO Auto-generated method stub
+        return super.transform(func, expr1, expr2);
+    }
+
+    @Override
+    public Expr transform(ExprFunction3 func, Expr expr1, Expr expr2, Expr expr3) {
+        // TODO Auto-generated method stub
+        return super.transform(func, expr1, expr2, expr3);
+    }
+
+    @Override
+    public Expr transform(ExprFunctionN func, ExprList args) {
+        // TODO Auto-generated method stub
+        return super.transform(func, args);
+    }
+
+    @Override
+    public Expr transform(ExprFunctionOp funcOp, ExprList args, Op opArg) {
+        // TODO Auto-generated method stub
+        return super.transform(funcOp, args, opArg);
+    }
+    
+    private boolean shouldExpand(ExprFunction func) {
+        return this.definitions.containsKey(func.getFunctionIRI());
+    }
+
+}

Added: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunction.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunction.java?rev=1411358&view=auto
==============================================================================
--- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunction.java (added)
+++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunction.java Mon Nov 19 19:26:08 2012
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012 YarcData LLC All Rights Reserved.
+ */ 
+
+package com.hp.hpl.jena.sparql.function.user;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.engine.binding.Binding;
+import com.hp.hpl.jena.sparql.expr.Expr;
+import com.hp.hpl.jena.sparql.expr.ExprList;
+import com.hp.hpl.jena.sparql.expr.ExprTransformSubstitute;
+import com.hp.hpl.jena.sparql.expr.ExprTransformer;
+import com.hp.hpl.jena.sparql.expr.NodeValue;
+import com.hp.hpl.jena.sparql.function.Function;
+import com.hp.hpl.jena.sparql.function.FunctionEnv;
+import com.hp.hpl.jena.sparql.sse.builders.ExprBuildException;
+
+/**
+ * Represents a user defined function
+ * @author rvesse
+ *
+ */
+public class UserDefinedFunction extends UserDefinedFunctionDefinition implements Function {
+
+    private Expr actualExpr;
+    
+    /**
+     * Creates a new user defined function
+     * @param def Function Definition
+     */
+    public UserDefinedFunction(UserDefinedFunctionDefinition def) {
+        super(def.getUri(), def.getBaseExpr(), def.getArgList());
+    }
+    
+    /**
+     * Creates a user defined function
+     * @param url Function URL
+     * @param e Expression
+     * @param argList Arguments
+     */
+    public UserDefinedFunction(String url, Expr e, List<Var> argList) {
+        super(url, e, argList);
+    }
+
+    /**
+     * Builds the expression substituting the arguments given into the base expression to yield the actual expression to evaluate
+     * @throws ExprBuildException Thrown if an expression cannot be generated
+     */
+    @Override
+    public void build(String uri, ExprList args) {
+        //Substitutes the arguments into the base expression to give the actual expression to evaluate
+        if (uri == null || !uri.equals(this.getUri())) throw new ExprBuildException("Incorrect URI passed to build() call, expected <" + this.getUri() + "> but got <" + uri + ">");
+        if (this.getArgList().size() != args.size()) throw new ExprBuildException("Incorrect number of arguments for user defined <" + this.getUri() + "> function");
+        
+        Map<String, Expr> substitutions = new HashMap<String, Expr>();
+        for (int i = 0; i < this.getArgList().size(); i++) {
+            substitutions.put(this.getArgList().get(i).getVarName(), args.get(i));
+        }
+        
+        this.actualExpr = ExprTransformer.transform(new ExprTransformSubstitute(substitutions), this.getBaseExpr());
+    }
+
+    /**
+     * Executes the function
+     */
+    @Override
+    public NodeValue exec(Binding binding, ExprList args, String uri, FunctionEnv env) {
+        //Evaluate the actual expression
+        return this.actualExpr.eval(binding, env);
+    }
+    
+    /**
+     * Gets the actual expression that was built for the function, assuming {@link #build(String, ExprList)} has been called
+     * @return Expression if built, null otherwise
+     */
+    public Expr getActualExpr() {
+        return this.actualExpr;
+    }
+}

Added: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionDefinition.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionDefinition.java?rev=1411358&view=auto
==============================================================================
--- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionDefinition.java (added)
+++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionDefinition.java Mon Nov 19 19:26:08 2012
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012 YarcData LLC All Rights Reserved.
+ */ 
+
+package com.hp.hpl.jena.sparql.function.user;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.expr.Expr;
+import com.hp.hpl.jena.sparql.function.Function;
+
+/**
+ * Represents the definition of a user defined function
+ * @author rvesse
+ *
+ */
+public class UserDefinedFunctionDefinition {
+
+    private String uri;
+    private Expr expr;
+    private List<Var> argList;
+    
+    /**
+     * Creates a user defined function definition
+     * @param uri Function URL
+     * @param e Expression
+     * @param argList Arguments
+     */
+    public UserDefinedFunctionDefinition(String uri, Expr e, List<Var> argList) {
+        this.uri = uri;
+        this.expr = e;
+        this.argList = new ArrayList<Var>(argList);
+    }
+    
+    /**
+     * Gets the base expression
+     * @return Expression
+     */
+    public Expr getBaseExpr() {
+        return this.expr;
+    }
+    
+    /**
+     * Gets the argument list
+     * @return Arguments
+     */
+    public List<Var> getArgList() {
+        return this.argList;
+    }
+    
+    /**
+     * Gets the function URI
+     * @return URI
+     */
+    public String getUri() {
+        return this.uri;
+    }
+    
+    /**
+     * Gets an instance of an actual {@link Function} that can be used to evaluate this function
+     * @return Function instance
+     */
+    public Function newFunctionInstance() {
+        return new UserDefinedFunction(this);
+    }
+}

Added: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionFactory.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionFactory.java?rev=1411358&view=auto
==============================================================================
--- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionFactory.java (added)
+++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionFactory.java Mon Nov 19 19:26:08 2012
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2012 YarcData LLC All Rights Reserved.
+ */ 
+
+package com.hp.hpl.jena.sparql.function.user;
+
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.expr.Expr;
+import com.hp.hpl.jena.sparql.function.Function;
+import com.hp.hpl.jena.sparql.function.FunctionFactory;
+import com.hp.hpl.jena.sparql.function.FunctionRegistry;
+import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
+import com.hp.hpl.jena.sparql.lang.sparql_11.SPARQLParser11;
+import com.hp.hpl.jena.sparql.sse.builders.ExprBuildException;
+
+/**
+ * A function factory for managing user defined functions
+ * <p>
+ * User defined functions provide a simple mechanism for a user to inject custom functions into SPARQL processing
+ * without the need to write any code.  These functions essentially act as aliases for another SPARQL expression
+ * and serve as a means to aid users in simplifying their SPARQL queries.
+ * </p>
+ * <p>
+ * For example we can define a <strong>square</strong> function like so:
+ * </p>
+ * <pre>
+ * List&lt;Var&gt; args = new ArrayList&lt;Var&gt;(Var.alloc("x"));
+ * UserDefinedFunctionFactory.getFactory().add("http://example/square", "?x * ?x", args);
+ * </pre>
+ * <p>
+ * We can then use this in queries like so:
+ * </p>
+ * <pre>
+ * SELECT (&lt;http://example/square&gt;(3) AS ?ThreeSquared) { }
+ * </pre>
+ * <p>
+ * Internally the call to the <strong>square</strong> function is translated into it's equivalent SPARQL expression and executed in that form.
+ * </p>
+ * @author rvesse
+ *
+ */
+public class UserDefinedFunctionFactory implements FunctionFactory {
+    
+    private static UserDefinedFunctionFactory factory = new UserDefinedFunctionFactory();    
+    
+    /**
+     * Gets the static instance of the factory
+     * @return Function Factory
+     */
+    public static UserDefinedFunctionFactory getFactory() {
+        return factory;
+    }
+
+    private Map<String, UserDefinedFunctionDefinition> definitions = new HashMap<String, UserDefinedFunctionDefinition>();
+    
+    /**
+     * Private constructor prevents instantiation
+     */
+    private UserDefinedFunctionFactory() { }
+        
+    /**
+     * Creates a function for the given URI
+     * @throws ExprBuildException Thrown if the given URI is not a known function
+     */
+    @Override
+    public Function create(String uri) {
+        UserDefinedFunctionDefinition def = this.definitions.get(uri);
+        if (def == null) throw new ExprBuildException("Function <" + uri + "> not known by this function factory");
+        return def.newFunctionInstance();
+    }
+    
+    /**
+     * Adds a function
+     * @param uri URI
+     * @param e Expression
+     * @param args Arguments
+     */
+    public void add(String uri, Expr e, List<Var> args) {
+        UserDefinedFunctionDefinition def = new UserDefinedFunctionDefinition(uri, e, args);
+        this.definitions.put(uri, def);
+        FunctionRegistry.get().put(uri, this);
+    }
+    
+    /**
+     * Adds a function
+     * <p>
+     * This method will build the expression to use based on the expression string given, strings must match the SPARQL expression syntax e.g.
+     * </p>
+     * <pre>
+     * (?x * ?y) + 5
+     * </pre>
+     * @param uri URI
+     * @param expr Expression String (in SPARQL syntax)
+     * @param args Arguments
+     * @throws ParseException Thrown if the expression string is not valid syntax
+     */
+    public void add(String uri, String expr, List<Var> args) throws ParseException {
+        Expr e = new SPARQLParser11(new StringReader(expr)).Expression();
+        UserDefinedFunctionDefinition def = new UserDefinedFunctionDefinition(uri, e, args);
+        this.definitions.put(uri, def);
+        FunctionRegistry.get().put(uri, this);
+    }
+    
+    /**
+     * Removes a function definition
+     * @param uri URI
+     * @throws NoSuchElementException Thrown if a function with the given URI does not exist
+     */
+    public void remove(String uri) {
+        if (!this.definitions.containsKey(uri)) throw new NoSuchElementException("No function definition is associated with the URI <" + uri + ">");
+        this.definitions.remove(uri);
+        FunctionRegistry.get().remove(uri);
+    }
+    
+    /**
+     * Gets the definition of the function (if registered)
+     * @param uri URI
+     * @return Function Definition if registered, null otherwise
+     */
+    public UserDefinedFunctionDefinition get(String uri) {
+        if (!this.definitions.containsKey(uri)) return null;
+        return this.definitions.get(uri);
+    }
+    
+    /**
+     * Gets whether a function with the given URI has been registered
+     * @param uri URI
+     * @return True if registered, false otherwise
+     */
+    public boolean isRegistered(String uri) {
+        return this.definitions.containsKey(uri);
+    }
+    
+    /**
+     * Clears all function definitions
+     */
+    public void clear() {
+        for (String uri : this.definitions.keySet()) {
+            FunctionRegistry.get().remove(uri);
+        }
+        this.definitions.clear();
+    }
+}

Added: jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS_UserFunctions.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS_UserFunctions.java?rev=1411358&view=auto
==============================================================================
--- jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS_UserFunctions.java (added)
+++ jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS_UserFunctions.java Mon Nov 19 19:26:08 2012
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2012 YarcData LLC All Rights Reserved.
+ */ 
+
+package com.hp.hpl.jena.sparql.function.user;
+
+import junit.framework.JUnit4TestAdapter;
+
+import org.junit.BeforeClass;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+import com.hp.hpl.jena.sparql.expr.TS_Expr;
+
+@RunWith(Suite.class)
+@SuiteClasses( {
+    TestUserDefinedFunctionFactory.class,
+    TestFunctionExpansion.class,
+    TestUserFunctionsInSparql.class
+})
+public class TS_UserFunctions {
+    
+    public static junit.framework.Test suite() {
+        return new JUnit4TestAdapter(TS_Expr.class);
+      }
+}

Added: jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestFunctionExpansion.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestFunctionExpansion.java?rev=1411358&view=auto
==============================================================================
--- jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestFunctionExpansion.java (added)
+++ jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestFunctionExpansion.java Mon Nov 19 19:26:08 2012
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2012 YarcData LLC All Rights Reserved.
+ */ 
+
+package com.hp.hpl.jena.sparql.function.user;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.expr.E_Multiply;
+import com.hp.hpl.jena.sparql.expr.Expr;
+import com.hp.hpl.jena.sparql.expr.ExprList;
+import com.hp.hpl.jena.sparql.expr.ExprVar;
+import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueBoolean;
+import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueInteger;
+
+/**
+ * Test for checking that functions are appropriately expanded when supplied with actual arguments
+ * @author rvesse
+ *
+ */
+public class TestFunctionExpansion {
+    
+    @BeforeClass
+    public static void setup() {
+        UserDefinedFunctionFactory.getFactory().clear();
+    }
+    
+    @AfterClass
+    public static void teardown() {
+        UserDefinedFunctionFactory.getFactory().clear();
+    }
+
+    @Test
+    public void test_function_expansion_01() {
+        Expr e = new ExprVar("x");
+        UserDefinedFunctionFactory.getFactory().add("http://example/simple", e, new ArrayList<Var>(e.getVarsMentioned()));
+        
+        UserDefinedFunction f = (UserDefinedFunction) UserDefinedFunctionFactory.getFactory().create("http://example/simple");
+        f.build("http://example/simple", new ExprList(new NodeValueBoolean(true)));
+        
+        Expr actual = f.getActualExpr();
+        Assert.assertFalse(e.equals(actual));
+        Assert.assertEquals(0, actual.getVarsMentioned().size());
+        Assert.assertEquals(new NodeValueBoolean(true), actual);
+    }
+    
+    @Test
+    public void test_function_expansion_02() {
+        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
+        UserDefinedFunctionFactory.getFactory().add("http://example/square", e, new ArrayList<Var>(e.getVarsMentioned()));
+        
+        UserDefinedFunction f = (UserDefinedFunction) UserDefinedFunctionFactory.getFactory().create("http://example/square");
+        f.build("http://example/square", new ExprList(new NodeValueInteger(3)));
+        
+        Expr actual = f.getActualExpr();
+        Assert.assertFalse(e.equals(actual));
+        Assert.assertEquals(0, actual.getVarsMentioned().size());
+        Assert.assertEquals(new E_Multiply(new NodeValueInteger(3), new NodeValueInteger(3)), actual);
+    }
+    
+    @Test
+    public void test_function_expansion_03() {
+        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("y"));
+        List<Var> defArgs = new ArrayList<Var>();
+        defArgs.add(Var.alloc("x"));
+        defArgs.add(Var.alloc("y"));
+        UserDefinedFunctionFactory.getFactory().add("http://example/square", e, defArgs);
+        
+        UserDefinedFunction f = (UserDefinedFunction) UserDefinedFunctionFactory.getFactory().create("http://example/square");
+        ExprList args = new ExprList();
+        args.add(new NodeValueInteger(3));
+        args.add(new NodeValueInteger(4));
+        f.build("http://example/square", args);
+        
+        Expr actual = f.getActualExpr();
+        Assert.assertFalse(e.equals(actual));
+        Assert.assertEquals(0, actual.getVarsMentioned().size());
+        Assert.assertEquals(new E_Multiply(new NodeValueInteger(3), new NodeValueInteger(4)), actual);
+    }
+}

Added: jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserDefinedFunctionFactory.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserDefinedFunctionFactory.java?rev=1411358&view=auto
==============================================================================
--- jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserDefinedFunctionFactory.java (added)
+++ jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserDefinedFunctionFactory.java Mon Nov 19 19:26:08 2012
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012 YarcData LLC All Rights Reserved.
+ */ 
+
+package com.hp.hpl.jena.sparql.function.user;
+
+import java.util.ArrayList;
+
+import junit.framework.Assert;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.expr.E_Multiply;
+import com.hp.hpl.jena.sparql.expr.Expr;
+import com.hp.hpl.jena.sparql.expr.ExprVar;
+import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
+
+/**
+ * Tests for the {@link UserDefinedFunctionFactory}
+ * @author rvesse
+ *
+ */
+public class TestUserDefinedFunctionFactory {
+    
+    @BeforeClass
+    public static void setup() {
+        UserDefinedFunctionFactory.getFactory().clear();
+    }
+    
+    @AfterClass
+    public static void teardown() {
+        UserDefinedFunctionFactory.getFactory().clear();
+    }
+    
+    @Test
+    public void test_user_defined_function_factory_instance() {
+        UserDefinedFunctionFactory factory = UserDefinedFunctionFactory.getFactory();
+        Assert.assertNotNull(factory);
+    }
+    
+    @Test
+    public void test_user_defined_function_factory_add_01() {
+        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
+        UserDefinedFunctionFactory.getFactory().add("http://example/square", e, new ArrayList<Var>(e.getVarsMentioned()));
+        Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("http://example/square"));
+        Assert.assertEquals(e, UserDefinedFunctionFactory.getFactory().get("http://example/square").getBaseExpr());
+    }
+    
+    @Test
+    public void test_user_defined_function_factory_add_02() {
+        Expr e1 = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
+        Expr e2 = new E_Multiply(new ExprVar("y"), new ExprVar("y"));
+        
+        UserDefinedFunctionFactory.getFactory().add("http://example/square", e1, new ArrayList<Var>(e1.getVarsMentioned()));
+        Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("http://example/square"));
+        Assert.assertEquals(e1, UserDefinedFunctionFactory.getFactory().get("http://example/square").getBaseExpr());
+        
+        UserDefinedFunctionFactory.getFactory().add("http://example/square", e2, new ArrayList<Var>(e2.getVarsMentioned()));
+        Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("http://example/square"));
+        Assert.assertEquals(e2, UserDefinedFunctionFactory.getFactory().get("http://example/square").getBaseExpr());
+    }
+    
+    @Test
+    public void test_user_defined_function_factory_add_03() throws ParseException {
+        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
+        
+        //Instead of registering the pre-built expression register using a string for the expression
+        UserDefinedFunctionFactory.getFactory().add("http://example/square", "?x * ?x", new ArrayList<Var>(e.getVarsMentioned()));
+        
+        Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("http://example/square"));
+        Assert.assertEquals(e, UserDefinedFunctionFactory.getFactory().get("http://example/square").getBaseExpr());
+    }
+}

Added: jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserFunctionsInSparql.java
URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserFunctionsInSparql.java?rev=1411358&view=auto
==============================================================================
--- jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserFunctionsInSparql.java (added)
+++ jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserFunctionsInSparql.java Mon Nov 19 19:26:08 2012
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2012 YarcData LLC All Rights Reserved.
+ */ 
+
+package com.hp.hpl.jena.sparql.function.user;
+
+import java.util.ArrayList;
+
+import junit.framework.Assert;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.hp.hpl.jena.graph.Node;
+import com.hp.hpl.jena.query.Query;
+import com.hp.hpl.jena.query.QueryExecution;
+import com.hp.hpl.jena.query.QueryExecutionFactory;
+import com.hp.hpl.jena.query.QueryFactory;
+import com.hp.hpl.jena.query.ResultSet;
+import com.hp.hpl.jena.rdf.model.ModelFactory;
+import com.hp.hpl.jena.sparql.core.Var;
+import com.hp.hpl.jena.sparql.engine.binding.Binding;
+import com.hp.hpl.jena.sparql.expr.E_Multiply;
+import com.hp.hpl.jena.sparql.expr.Expr;
+import com.hp.hpl.jena.sparql.expr.ExprVar;
+import com.hp.hpl.jena.sparql.util.NodeFactory;
+
+/**
+ * Tests that user functions are properly wired in and usable from SPARQL
+ * @author rvesse
+ *
+ */
+public class TestUserFunctionsInSparql {
+
+    @BeforeClass
+    public static void setup() {
+        UserDefinedFunctionFactory.getFactory().clear();
+        
+        //Define a square function
+        Expr square = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
+        UserDefinedFunctionFactory.getFactory().add("http://example/square", square, new ArrayList<Var>(square.getVarsMentioned()));
+    }
+    
+    @AfterClass
+    public static void teardown() {
+        UserDefinedFunctionFactory.getFactory().clear();
+    }
+    
+    @Test
+    public void test_user_functions_in_sparql() {
+        Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("http://example/square"));
+        
+        String query = "SELECT (<http://example/square>(2) AS ?square) { }";
+        Query q = QueryFactory.create(query);
+        
+        QueryExecution qe = QueryExecutionFactory.create(q, ModelFactory.createDefaultModel());
+        ResultSet rset = qe.execSelect();
+        Assert.assertTrue(rset.hasNext());
+        Binding b = rset.nextBinding();
+        Assert.assertFalse(rset.hasNext());
+        qe.close();
+        
+        //Validate returned value
+        Node actual = b.get(Var.alloc("square"));
+        Assert.assertEquals(NodeFactory.intToNode(4), actual);
+    }
+}



Re: svn commit: r1411358 - in /jena/trunk/jena-arq/src: main/java/com/hp/hpl/jena/sparql/function/ main/java/com/hp/hpl/jena/sparql/function/user/ test/java/com/hp/hpl/jena/sparql/function/ test/java/com/hp/hpl/jena/sparql/function/user/

Posted by Andy Seaborne <an...@apache.org>.
On 19/11/12 21:17, Rob Vesse wrote:
> Gah, damn Eclipse code templates
>
> Have I mentioned I hate Eclipse!

Yes, once or twice.

>
> Next commit will correct these, sorry
>
> Rob
>
>
>
> On 11/19/12 12:53 PM, "Stephen Allen" <sa...@apache.org> wrote:
>
>> Hi Rob,
>>
>> Probably an oversight, but the code you checked in in this commit
>> (revision 1411358) and in revision 1411398 have copyright headers for
>> YarcData.  These files need to be removed or the header changed to the
>> Apache copyright if the code is to be added to the project.

Good catch.

Legal pickiness ... IANAL ...

It's the Apache Software License, not a copyright.  Cray, YarcData, 
whatever the legal entity is, retain the copyright on the contribution.

A contribution is licensed to Apache via the CCLA/ICLA/software 
grant/email sign up.  That includes "prepare derivative works" (and the 
patent coverage).

Apache (us, the project and any other project) bundle all the licenses 
up and release a single thing under ASL.  Effect: the end users get one 
license, Apache->user.  That helps with the business friendliness.

((BSD, GPL are different - each contributor is making a direct license 
to the end user.  That's why some project use a copyright assignment to 
consolidate into one license but that ahas other issues as copyright 
assignment is jurisdiction sensitive IIUC))

	Andy

>>
>> -Stephen
>>
>>
>> On Mon, Nov 19, 2012 at 2:26 PM,  <rv...@apache.org> wrote:
>>> Author: rvesse
>>> Date: Mon Nov 19 19:26:08 2012
>>> New Revision: 1411358
>>>
>>> URL: http://svn.apache.org/viewvc?rev=1411358&view=rev
>>> Log:
>>> Initial framework for user defined functions
>>>
>>> Added:
>>>
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/
>>>
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Ex
>>> prTransformExpand.java
>>>
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>> erDefinedFunction.java
>>>
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>> erDefinedFunctionDefinition.java
>>>
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>> erDefinedFunctionFactory.java
>>>      jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/
>>>
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/
>>>
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS
>>> _UserFunctions.java
>>>
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>> stFunctionExpansion.java
>>>
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>> stUserDefinedFunctionFactory.java
>>>
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>> stUserFunctionsInSparql.java
>>> Modified:
>>>
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>> n.java
>>>
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>> nFactory.java
>>>
>>> Modified:
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>> n.java
>>> URL:
>>> http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl
>>> /jena/sparql/function/Function.java?rev=1411358&r1=1411357&r2=1411358&vie
>>> w=diff
>>>
>>> =========================================================================
>>> =====
>>> ---
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>> n.java (original)
>>> +++
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>> n.java Mon Nov 19 19:26:08 2012
>>> @@ -30,7 +30,7 @@ public interface Function
>>>       /** Called during query plan construction immediately after the
>>>        * construction of the extension instance.
>>>        * Can throw ExprBuildException if something is wrong (like wrong
>>> number of arguments).
>>> -     * @param args The parsed arguements
>>> +     * @param args The parsed arguments
>>>        */
>>>       public void build(String uri, ExprList args) ;
>>>
>>>
>>> Modified:
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>> nFactory.java
>>> URL:
>>> http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl
>>> /jena/sparql/function/FunctionFactory.java?rev=1411358&r1=1411357&r2=1411
>>> 358&view=diff
>>>
>>> =========================================================================
>>> =====
>>> ---
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>> nFactory.java (original)
>>> +++
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>> nFactory.java Mon Nov 19 19:26:08 2012
>>> @@ -18,10 +18,18 @@
>>>
>>>   package com.hp.hpl.jena.sparql.function;
>>>
>>> +import com.hp.hpl.jena.sparql.sse.builders.ExprBuildException;
>>>
>>> -/** Interface for function factories. */
>>> -
>>> +/**
>>> + *  Interface for function factories.
>>> + */
>>>   public interface FunctionFactory
>>>   {
>>> +    /**
>>> +     * Create a function with the given URI
>>> +     * @param uri URI
>>> +     * @return Function
>>> +     * @throws ExprBuildException May be thrown if there is a problem
>>> creating a function
>>> +     */
>>>       public Function create(String uri) ;
>>>   }
>>>
>>> Added:
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Ex
>>> prTransformExpand.java
>>> URL:
>>> http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl
>>> /jena/sparql/function/user/ExprTransformExpand.java?rev=1411358&view=auto
>>>
>>> =========================================================================
>>> =====
>>> ---
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Ex
>>> prTransformExpand.java (added)
>>> +++
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Ex
>>> prTransformExpand.java Mon Nov 19 19:26:08 2012
>>> @@ -0,0 +1,84 @@
>>> +/*
>>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>>> + */
>>> +
>>> +package com.hp.hpl.jena.sparql.function.user;
>>> +
>>> +import java.util.Map;
>>> +
>>> +import com.hp.hpl.jena.sparql.algebra.Op;
>>> +import com.hp.hpl.jena.sparql.expr.Expr;
>>> +import com.hp.hpl.jena.sparql.expr.ExprFunction;
>>> +import com.hp.hpl.jena.sparql.expr.ExprFunction0;
>>> +import com.hp.hpl.jena.sparql.expr.ExprFunction1;
>>> +import com.hp.hpl.jena.sparql.expr.ExprFunction2;
>>> +import com.hp.hpl.jena.sparql.expr.ExprFunction3;
>>> +import com.hp.hpl.jena.sparql.expr.ExprFunctionN;
>>> +import com.hp.hpl.jena.sparql.expr.ExprFunctionOp;
>>> +import com.hp.hpl.jena.sparql.expr.ExprList;
>>> +import com.hp.hpl.jena.sparql.expr.ExprTransformCopy;
>>> +
>>> +/**
>>> + * An expression transformer that will expand user defined expressions
>>> so they do not explicitly rely on other user defined functions
>>> + * @author rvesse
>>> + *
>>> + */
>>> +public class ExprTransformExpand extends ExprTransformCopy {
>>> +
>>> +    private Map<String, UserDefinedFunctionDefinition> definitions;
>>> +
>>> +    /**
>>> +     * Creates a new transformer
>>> +     * @param defs User defined function definitions
>>> +     */
>>> +    public ExprTransformExpand(Map<String,
>>> UserDefinedFunctionDefinition> defs) {
>>> +        if (defs == null) throw new IllegalArgumentException("defs
>>> cannot be null");
>>> +        this.definitions = defs;
>>> +    }
>>> +
>>> +    @Override
>>> +    public Expr transform(ExprFunction0 func) {
>>> +        ExprFunction f = func.getFunction();
>>> +        if (this.shouldExpand(f)) {
>>> +            //TODO Need to expand the function
>>> +            return super.transform(func);
>>> +        } else {
>>> +            return super.transform(func);
>>> +        }
>>> +    }
>>> +
>>> +    @Override
>>> +    public Expr transform(ExprFunction1 func, Expr expr1) {
>>> +        // TODO Auto-generated method stub
>>> +        return super.transform(func, expr1);
>>> +    }
>>> +
>>> +    @Override
>>> +    public Expr transform(ExprFunction2 func, Expr expr1, Expr expr2) {
>>> +        // TODO Auto-generated method stub
>>> +        return super.transform(func, expr1, expr2);
>>> +    }
>>> +
>>> +    @Override
>>> +    public Expr transform(ExprFunction3 func, Expr expr1, Expr expr2,
>>> Expr expr3) {
>>> +        // TODO Auto-generated method stub
>>> +        return super.transform(func, expr1, expr2, expr3);
>>> +    }
>>> +
>>> +    @Override
>>> +    public Expr transform(ExprFunctionN func, ExprList args) {
>>> +        // TODO Auto-generated method stub
>>> +        return super.transform(func, args);
>>> +    }
>>> +
>>> +    @Override
>>> +    public Expr transform(ExprFunctionOp funcOp, ExprList args, Op
>>> opArg) {
>>> +        // TODO Auto-generated method stub
>>> +        return super.transform(funcOp, args, opArg);
>>> +    }
>>> +
>>> +    private boolean shouldExpand(ExprFunction func) {
>>> +        return this.definitions.containsKey(func.getFunctionIRI());
>>> +    }
>>> +
>>> +}
>>>
>>> Added:
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>> erDefinedFunction.java
>>> URL:
>>> http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl
>>> /jena/sparql/function/user/UserDefinedFunction.java?rev=1411358&view=auto
>>>
>>> =========================================================================
>>> =====
>>> ---
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>> erDefinedFunction.java (added)
>>> +++
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>> erDefinedFunction.java Mon Nov 19 19:26:08 2012
>>> @@ -0,0 +1,82 @@
>>> +/*
>>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>>> + */
>>> +
>>> +package com.hp.hpl.jena.sparql.function.user;
>>> +
>>> +import java.util.HashMap;
>>> +import java.util.List;
>>> +import java.util.Map;
>>> +import com.hp.hpl.jena.sparql.core.Var;
>>> +import com.hp.hpl.jena.sparql.engine.binding.Binding;
>>> +import com.hp.hpl.jena.sparql.expr.Expr;
>>> +import com.hp.hpl.jena.sparql.expr.ExprList;
>>> +import com.hp.hpl.jena.sparql.expr.ExprTransformSubstitute;
>>> +import com.hp.hpl.jena.sparql.expr.ExprTransformer;
>>> +import com.hp.hpl.jena.sparql.expr.NodeValue;
>>> +import com.hp.hpl.jena.sparql.function.Function;
>>> +import com.hp.hpl.jena.sparql.function.FunctionEnv;
>>> +import com.hp.hpl.jena.sparql.sse.builders.ExprBuildException;
>>> +
>>> +/**
>>> + * Represents a user defined function
>>> + * @author rvesse
>>> + *
>>> + */
>>> +public class UserDefinedFunction extends UserDefinedFunctionDefinition
>>> implements Function {
>>> +
>>> +    private Expr actualExpr;
>>> +
>>> +    /**
>>> +     * Creates a new user defined function
>>> +     * @param def Function Definition
>>> +     */
>>> +    public UserDefinedFunction(UserDefinedFunctionDefinition def) {
>>> +        super(def.getUri(), def.getBaseExpr(), def.getArgList());
>>> +    }
>>> +
>>> +    /**
>>> +     * Creates a user defined function
>>> +     * @param url Function URL
>>> +     * @param e Expression
>>> +     * @param argList Arguments
>>> +     */
>>> +    public UserDefinedFunction(String url, Expr e, List<Var> argList) {
>>> +        super(url, e, argList);
>>> +    }
>>> +
>>> +    /**
>>> +     * Builds the expression substituting the arguments given into the
>>> base expression to yield the actual expression to evaluate
>>> +     * @throws ExprBuildException Thrown if an expression cannot be
>>> generated
>>> +     */
>>> +    @Override
>>> +    public void build(String uri, ExprList args) {
>>> +        //Substitutes the arguments into the base expression to give
>>> the actual expression to evaluate
>>> +        if (uri == null || !uri.equals(this.getUri())) throw new
>>> ExprBuildException("Incorrect URI passed to build() call, expected <" +
>>> this.getUri() + "> but got <" + uri + ">");
>>> +        if (this.getArgList().size() != args.size()) throw new
>>> ExprBuildException("Incorrect number of arguments for user defined <" +
>>> this.getUri() + "> function");
>>> +
>>> +        Map<String, Expr> substitutions = new HashMap<String, Expr>();
>>> +        for (int i = 0; i < this.getArgList().size(); i++) {
>>> +            substitutions.put(this.getArgList().get(i).getVarName(),
>>> args.get(i));
>>> +        }
>>> +
>>> +        this.actualExpr = ExprTransformer.transform(new
>>> ExprTransformSubstitute(substitutions), this.getBaseExpr());
>>> +    }
>>> +
>>> +    /**
>>> +     * Executes the function
>>> +     */
>>> +    @Override
>>> +    public NodeValue exec(Binding binding, ExprList args, String uri,
>>> FunctionEnv env) {
>>> +        //Evaluate the actual expression
>>> +        return this.actualExpr.eval(binding, env);
>>> +    }
>>> +
>>> +    /**
>>> +     * Gets the actual expression that was built for the function,
>>> assuming {@link #build(String, ExprList)} has been called
>>> +     * @return Expression if built, null otherwise
>>> +     */
>>> +    public Expr getActualExpr() {
>>> +        return this.actualExpr;
>>> +    }
>>> +}
>>>
>>> Added:
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>> erDefinedFunctionDefinition.java
>>> URL:
>>> http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl
>>> /jena/sparql/function/user/UserDefinedFunctionDefinition.java?rev=1411358
>>> &view=auto
>>>
>>> =========================================================================
>>> =====
>>> ---
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>> erDefinedFunctionDefinition.java (added)
>>> +++
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>> erDefinedFunctionDefinition.java Mon Nov 19 19:26:08 2012
>>> @@ -0,0 +1,68 @@
>>> +/*
>>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>>> + */
>>> +
>>> +package com.hp.hpl.jena.sparql.function.user;
>>> +
>>> +import java.util.ArrayList;
>>> +import java.util.List;
>>> +
>>> +import com.hp.hpl.jena.sparql.core.Var;
>>> +import com.hp.hpl.jena.sparql.expr.Expr;
>>> +import com.hp.hpl.jena.sparql.function.Function;
>>> +
>>> +/**
>>> + * Represents the definition of a user defined function
>>> + * @author rvesse
>>> + *
>>> + */
>>> +public class UserDefinedFunctionDefinition {
>>> +
>>> +    private String uri;
>>> +    private Expr expr;
>>> +    private List<Var> argList;
>>> +
>>> +    /**
>>> +     * Creates a user defined function definition
>>> +     * @param uri Function URL
>>> +     * @param e Expression
>>> +     * @param argList Arguments
>>> +     */
>>> +    public UserDefinedFunctionDefinition(String uri, Expr e, List<Var>
>>> argList) {
>>> +        this.uri = uri;
>>> +        this.expr = e;
>>> +        this.argList = new ArrayList<Var>(argList);
>>> +    }
>>> +
>>> +    /**
>>> +     * Gets the base expression
>>> +     * @return Expression
>>> +     */
>>> +    public Expr getBaseExpr() {
>>> +        return this.expr;
>>> +    }
>>> +
>>> +    /**
>>> +     * Gets the argument list
>>> +     * @return Arguments
>>> +     */
>>> +    public List<Var> getArgList() {
>>> +        return this.argList;
>>> +    }
>>> +
>>> +    /**
>>> +     * Gets the function URI
>>> +     * @return URI
>>> +     */
>>> +    public String getUri() {
>>> +        return this.uri;
>>> +    }
>>> +
>>> +    /**
>>> +     * Gets an instance of an actual {@link Function} that can be used
>>> to evaluate this function
>>> +     * @return Function instance
>>> +     */
>>> +    public Function newFunctionInstance() {
>>> +        return new UserDefinedFunction(this);
>>> +    }
>>> +}
>>>
>>> Added:
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>> erDefinedFunctionFactory.java
>>> URL:
>>> http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl
>>> /jena/sparql/function/user/UserDefinedFunctionFactory.java?rev=1411358&vi
>>> ew=auto
>>>
>>> =========================================================================
>>> =====
>>> ---
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>> erDefinedFunctionFactory.java (added)
>>> +++
>>> jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>> erDefinedFunctionFactory.java Mon Nov 19 19:26:08 2012
>>> @@ -0,0 +1,149 @@
>>> +/*
>>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>>> + */
>>> +
>>> +package com.hp.hpl.jena.sparql.function.user;
>>> +
>>> +import java.io.StringReader;
>>> +import java.util.HashMap;
>>> +import java.util.List;
>>> +import java.util.Map;
>>> +import java.util.NoSuchElementException;
>>> +
>>> +import com.hp.hpl.jena.sparql.core.Var;
>>> +import com.hp.hpl.jena.sparql.expr.Expr;
>>> +import com.hp.hpl.jena.sparql.function.Function;
>>> +import com.hp.hpl.jena.sparql.function.FunctionFactory;
>>> +import com.hp.hpl.jena.sparql.function.FunctionRegistry;
>>> +import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
>>> +import com.hp.hpl.jena.sparql.lang.sparql_11.SPARQLParser11;
>>> +import com.hp.hpl.jena.sparql.sse.builders.ExprBuildException;
>>> +
>>> +/**
>>> + * A function factory for managing user defined functions
>>> + * <p>
>>> + * User defined functions provide a simple mechanism for a user to
>>> inject custom functions into SPARQL processing
>>> + * without the need to write any code.  These functions essentially
>>> act as aliases for another SPARQL expression
>>> + * and serve as a means to aid users in simplifying their SPARQL
>>> queries.
>>> + * </p>
>>> + * <p>
>>> + * For example we can define a <strong>square</strong> function like
>>> so:
>>> + * </p>
>>> + * <pre>
>>> + * List&lt;Var&gt; args = new ArrayList&lt;Var&gt;(Var.alloc("x"));
>>> + *
>>> UserDefinedFunctionFactory.getFactory().add("http://example/square", "?x
>>> * ?x", args);
>>> + * </pre>
>>> + * <p>
>>> + * We can then use this in queries like so:
>>> + * </p>
>>> + * <pre>
>>> + * SELECT (&lt;http://example/square&gt;(3) AS ?ThreeSquared) { }
>>> + * </pre>
>>> + * <p>
>>> + * Internally the call to the <strong>square</strong> function is
>>> translated into it's equivalent SPARQL expression and executed in that
>>> form.
>>> + * </p>
>>> + * @author rvesse
>>> + *
>>> + */
>>> +public class UserDefinedFunctionFactory implements FunctionFactory {
>>> +
>>> +    private static UserDefinedFunctionFactory factory = new
>>> UserDefinedFunctionFactory();
>>> +
>>> +    /**
>>> +     * Gets the static instance of the factory
>>> +     * @return Function Factory
>>> +     */
>>> +    public static UserDefinedFunctionFactory getFactory() {
>>> +        return factory;
>>> +    }
>>> +
>>> +    private Map<String, UserDefinedFunctionDefinition> definitions =
>>> new HashMap<String, UserDefinedFunctionDefinition>();
>>> +
>>> +    /**
>>> +     * Private constructor prevents instantiation
>>> +     */
>>> +    private UserDefinedFunctionFactory() { }
>>> +
>>> +    /**
>>> +     * Creates a function for the given URI
>>> +     * @throws ExprBuildException Thrown if the given URI is not a
>>> known function
>>> +     */
>>> +    @Override
>>> +    public Function create(String uri) {
>>> +        UserDefinedFunctionDefinition def = this.definitions.get(uri);
>>> +        if (def == null) throw new ExprBuildException("Function <" +
>>> uri + "> not known by this function factory");
>>> +        return def.newFunctionInstance();
>>> +    }
>>> +
>>> +    /**
>>> +     * Adds a function
>>> +     * @param uri URI
>>> +     * @param e Expression
>>> +     * @param args Arguments
>>> +     */
>>> +    public void add(String uri, Expr e, List<Var> args) {
>>> +        UserDefinedFunctionDefinition def = new
>>> UserDefinedFunctionDefinition(uri, e, args);
>>> +        this.definitions.put(uri, def);
>>> +        FunctionRegistry.get().put(uri, this);
>>> +    }
>>> +
>>> +    /**
>>> +     * Adds a function
>>> +     * <p>
>>> +     * This method will build the expression to use based on the
>>> expression string given, strings must match the SPARQL expression syntax
>>> e.g.
>>> +     * </p>
>>> +     * <pre>
>>> +     * (?x * ?y) + 5
>>> +     * </pre>
>>> +     * @param uri URI
>>> +     * @param expr Expression String (in SPARQL syntax)
>>> +     * @param args Arguments
>>> +     * @throws ParseException Thrown if the expression string is not
>>> valid syntax
>>> +     */
>>> +    public void add(String uri, String expr, List<Var> args) throws
>>> ParseException {
>>> +        Expr e = new SPARQLParser11(new
>>> StringReader(expr)).Expression();
>>> +        UserDefinedFunctionDefinition def = new
>>> UserDefinedFunctionDefinition(uri, e, args);
>>> +        this.definitions.put(uri, def);
>>> +        FunctionRegistry.get().put(uri, this);
>>> +    }
>>> +
>>> +    /**
>>> +     * Removes a function definition
>>> +     * @param uri URI
>>> +     * @throws NoSuchElementException Thrown if a function with the
>>> given URI does not exist
>>> +     */
>>> +    public void remove(String uri) {
>>> +        if (!this.definitions.containsKey(uri)) throw new
>>> NoSuchElementException("No function definition is associated with the
>>> URI <" + uri + ">");
>>> +        this.definitions.remove(uri);
>>> +        FunctionRegistry.get().remove(uri);
>>> +    }
>>> +
>>> +    /**
>>> +     * Gets the definition of the function (if registered)
>>> +     * @param uri URI
>>> +     * @return Function Definition if registered, null otherwise
>>> +     */
>>> +    public UserDefinedFunctionDefinition get(String uri) {
>>> +        if (!this.definitions.containsKey(uri)) return null;
>>> +        return this.definitions.get(uri);
>>> +    }
>>> +
>>> +    /**
>>> +     * Gets whether a function with the given URI has been registered
>>> +     * @param uri URI
>>> +     * @return True if registered, false otherwise
>>> +     */
>>> +    public boolean isRegistered(String uri) {
>>> +        return this.definitions.containsKey(uri);
>>> +    }
>>> +
>>> +    /**
>>> +     * Clears all function definitions
>>> +     */
>>> +    public void clear() {
>>> +        for (String uri : this.definitions.keySet()) {
>>> +            FunctionRegistry.get().remove(uri);
>>> +        }
>>> +        this.definitions.clear();
>>> +    }
>>> +}
>>>
>>> Added:
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS
>>> _UserFunctions.java
>>> URL:
>>> http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl
>>> /jena/sparql/function/user/TS_UserFunctions.java?rev=1411358&view=auto
>>>
>>> =========================================================================
>>> =====
>>> ---
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS
>>> _UserFunctions.java (added)
>>> +++
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS
>>> _UserFunctions.java Mon Nov 19 19:26:08 2012
>>> @@ -0,0 +1,27 @@
>>> +/*
>>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>>> + */
>>> +
>>> +package com.hp.hpl.jena.sparql.function.user;
>>> +
>>> +import junit.framework.JUnit4TestAdapter;
>>> +
>>> +import org.junit.BeforeClass;
>>> +import org.junit.runner.RunWith;
>>> +import org.junit.runners.Suite;
>>> +import org.junit.runners.Suite.SuiteClasses;
>>> +
>>> +import com.hp.hpl.jena.sparql.expr.TS_Expr;
>>> +
>>> +@RunWith(Suite.class)
>>> +@SuiteClasses( {
>>> +    TestUserDefinedFunctionFactory.class,
>>> +    TestFunctionExpansion.class,
>>> +    TestUserFunctionsInSparql.class
>>> +})
>>> +public class TS_UserFunctions {
>>> +
>>> +    public static junit.framework.Test suite() {
>>> +        return new JUnit4TestAdapter(TS_Expr.class);
>>> +      }
>>> +}
>>>
>>> Added:
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>> stFunctionExpansion.java
>>> URL:
>>> http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl
>>> /jena/sparql/function/user/TestFunctionExpansion.java?rev=1411358&view=au
>>> to
>>>
>>> =========================================================================
>>> =====
>>> ---
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>> stFunctionExpansion.java (added)
>>> +++
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>> stFunctionExpansion.java Mon Nov 19 19:26:08 2012
>>> @@ -0,0 +1,87 @@
>>> +/*
>>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>>> + */
>>> +
>>> +package com.hp.hpl.jena.sparql.function.user;
>>> +
>>> +import java.util.ArrayList;
>>> +import java.util.List;
>>> +
>>> +import org.junit.AfterClass;
>>> +import org.junit.Assert;
>>> +import org.junit.BeforeClass;
>>> +import org.junit.Test;
>>> +
>>> +import com.hp.hpl.jena.sparql.core.Var;
>>> +import com.hp.hpl.jena.sparql.expr.E_Multiply;
>>> +import com.hp.hpl.jena.sparql.expr.Expr;
>>> +import com.hp.hpl.jena.sparql.expr.ExprList;
>>> +import com.hp.hpl.jena.sparql.expr.ExprVar;
>>> +import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueBoolean;
>>> +import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueInteger;
>>> +
>>> +/**
>>> + * Test for checking that functions are appropriately expanded when
>>> supplied with actual arguments
>>> + * @author rvesse
>>> + *
>>> + */
>>> +public class TestFunctionExpansion {
>>> +
>>> +    @BeforeClass
>>> +    public static void setup() {
>>> +        UserDefinedFunctionFactory.getFactory().clear();
>>> +    }
>>> +
>>> +    @AfterClass
>>> +    public static void teardown() {
>>> +        UserDefinedFunctionFactory.getFactory().clear();
>>> +    }
>>> +
>>> +    @Test
>>> +    public void test_function_expansion_01() {
>>> +        Expr e = new ExprVar("x");
>>> +
>>> UserDefinedFunctionFactory.getFactory().add("http://example/simple", e,
>>> new ArrayList<Var>(e.getVarsMentioned()));
>>> +
>>> +        UserDefinedFunction f = (UserDefinedFunction)
>>> UserDefinedFunctionFactory.getFactory().create("http://example/simple");
>>> +        f.build("http://example/simple", new ExprList(new
>>> NodeValueBoolean(true)));
>>> +
>>> +        Expr actual = f.getActualExpr();
>>> +        Assert.assertFalse(e.equals(actual));
>>> +        Assert.assertEquals(0, actual.getVarsMentioned().size());
>>> +        Assert.assertEquals(new NodeValueBoolean(true), actual);
>>> +    }
>>> +
>>> +    @Test
>>> +    public void test_function_expansion_02() {
>>> +        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
>>> +
>>> UserDefinedFunctionFactory.getFactory().add("http://example/square", e,
>>> new ArrayList<Var>(e.getVarsMentioned()));
>>> +
>>> +        UserDefinedFunction f = (UserDefinedFunction)
>>> UserDefinedFunctionFactory.getFactory().create("http://example/square");
>>> +        f.build("http://example/square", new ExprList(new
>>> NodeValueInteger(3)));
>>> +
>>> +        Expr actual = f.getActualExpr();
>>> +        Assert.assertFalse(e.equals(actual));
>>> +        Assert.assertEquals(0, actual.getVarsMentioned().size());
>>> +        Assert.assertEquals(new E_Multiply(new NodeValueInteger(3),
>>> new NodeValueInteger(3)), actual);
>>> +    }
>>> +
>>> +    @Test
>>> +    public void test_function_expansion_03() {
>>> +        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("y"));
>>> +        List<Var> defArgs = new ArrayList<Var>();
>>> +        defArgs.add(Var.alloc("x"));
>>> +        defArgs.add(Var.alloc("y"));
>>> +
>>> UserDefinedFunctionFactory.getFactory().add("http://example/square", e,
>>> defArgs);
>>> +
>>> +        UserDefinedFunction f = (UserDefinedFunction)
>>> UserDefinedFunctionFactory.getFactory().create("http://example/square");
>>> +        ExprList args = new ExprList();
>>> +        args.add(new NodeValueInteger(3));
>>> +        args.add(new NodeValueInteger(4));
>>> +        f.build("http://example/square", args);
>>> +
>>> +        Expr actual = f.getActualExpr();
>>> +        Assert.assertFalse(e.equals(actual));
>>> +        Assert.assertEquals(0, actual.getVarsMentioned().size());
>>> +        Assert.assertEquals(new E_Multiply(new NodeValueInteger(3),
>>> new NodeValueInteger(4)), actual);
>>> +    }
>>> +}
>>>
>>> Added:
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>> stUserDefinedFunctionFactory.java
>>> URL:
>>> http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl
>>> /jena/sparql/function/user/TestUserDefinedFunctionFactory.java?rev=141135
>>> 8&view=auto
>>>
>>> =========================================================================
>>> =====
>>> ---
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>> stUserDefinedFunctionFactory.java (added)
>>> +++
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>> stUserDefinedFunctionFactory.java Mon Nov 19 19:26:08 2012
>>> @@ -0,0 +1,76 @@
>>> +/*
>>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>>> + */
>>> +
>>> +package com.hp.hpl.jena.sparql.function.user;
>>> +
>>> +import java.util.ArrayList;
>>> +
>>> +import junit.framework.Assert;
>>> +
>>> +import org.junit.AfterClass;
>>> +import org.junit.BeforeClass;
>>> +import org.junit.Test;
>>> +
>>> +import com.hp.hpl.jena.sparql.core.Var;
>>> +import com.hp.hpl.jena.sparql.expr.E_Multiply;
>>> +import com.hp.hpl.jena.sparql.expr.Expr;
>>> +import com.hp.hpl.jena.sparql.expr.ExprVar;
>>> +import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
>>> +
>>> +/**
>>> + * Tests for the {@link UserDefinedFunctionFactory}
>>> + * @author rvesse
>>> + *
>>> + */
>>> +public class TestUserDefinedFunctionFactory {
>>> +
>>> +    @BeforeClass
>>> +    public static void setup() {
>>> +        UserDefinedFunctionFactory.getFactory().clear();
>>> +    }
>>> +
>>> +    @AfterClass
>>> +    public static void teardown() {
>>> +        UserDefinedFunctionFactory.getFactory().clear();
>>> +    }
>>> +
>>> +    @Test
>>> +    public void test_user_defined_function_factory_instance() {
>>> +        UserDefinedFunctionFactory factory =
>>> UserDefinedFunctionFactory.getFactory();
>>> +        Assert.assertNotNull(factory);
>>> +    }
>>> +
>>> +    @Test
>>> +    public void test_user_defined_function_factory_add_01() {
>>> +        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
>>> +
>>> UserDefinedFunctionFactory.getFactory().add("http://example/square", e,
>>> new ArrayList<Var>(e.getVarsMentioned()));
>>> +
>>> Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("h
>>> ttp://example/square"));
>>> +        Assert.assertEquals(e,
>>> UserDefinedFunctionFactory.getFactory().get("http://example/square").getB
>>> aseExpr());
>>> +    }
>>> +
>>> +    @Test
>>> +    public void test_user_defined_function_factory_add_02() {
>>> +        Expr e1 = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
>>> +        Expr e2 = new E_Multiply(new ExprVar("y"), new ExprVar("y"));
>>> +
>>> +
>>> UserDefinedFunctionFactory.getFactory().add("http://example/square", e1,
>>> new ArrayList<Var>(e1.getVarsMentioned()));
>>> +
>>> Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("h
>>> ttp://example/square"));
>>> +        Assert.assertEquals(e1,
>>> UserDefinedFunctionFactory.getFactory().get("http://example/square").getB
>>> aseExpr());
>>> +
>>> +
>>> UserDefinedFunctionFactory.getFactory().add("http://example/square", e2,
>>> new ArrayList<Var>(e2.getVarsMentioned()));
>>> +
>>> Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("h
>>> ttp://example/square"));
>>> +        Assert.assertEquals(e2,
>>> UserDefinedFunctionFactory.getFactory().get("http://example/square").getB
>>> aseExpr());
>>> +    }
>>> +
>>> +    @Test
>>> +    public void test_user_defined_function_factory_add_03() throws
>>> ParseException {
>>> +        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
>>> +
>>> +        //Instead of registering the pre-built expression register
>>> using a string for the expression
>>> +
>>> UserDefinedFunctionFactory.getFactory().add("http://example/square", "?x
>>> * ?x", new ArrayList<Var>(e.getVarsMentioned()));
>>> +
>>> +
>>> Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("h
>>> ttp://example/square"));
>>> +        Assert.assertEquals(e,
>>> UserDefinedFunctionFactory.getFactory().get("http://example/square").getB
>>> aseExpr());
>>> +    }
>>> +}
>>>
>>> Added:
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>> stUserFunctionsInSparql.java
>>> URL:
>>> http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl
>>> /jena/sparql/function/user/TestUserFunctionsInSparql.java?rev=1411358&vie
>>> w=auto
>>>
>>> =========================================================================
>>> =====
>>> ---
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>> stUserFunctionsInSparql.java (added)
>>> +++
>>> jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>> stUserFunctionsInSparql.java Mon Nov 19 19:26:08 2012
>>> @@ -0,0 +1,68 @@
>>> +/*
>>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>>> + */
>>> +
>>> +package com.hp.hpl.jena.sparql.function.user;
>>> +
>>> +import java.util.ArrayList;
>>> +
>>> +import junit.framework.Assert;
>>> +
>>> +import org.junit.AfterClass;
>>> +import org.junit.BeforeClass;
>>> +import org.junit.Test;
>>> +
>>> +import com.hp.hpl.jena.graph.Node;
>>> +import com.hp.hpl.jena.query.Query;
>>> +import com.hp.hpl.jena.query.QueryExecution;
>>> +import com.hp.hpl.jena.query.QueryExecutionFactory;
>>> +import com.hp.hpl.jena.query.QueryFactory;
>>> +import com.hp.hpl.jena.query.ResultSet;
>>> +import com.hp.hpl.jena.rdf.model.ModelFactory;
>>> +import com.hp.hpl.jena.sparql.core.Var;
>>> +import com.hp.hpl.jena.sparql.engine.binding.Binding;
>>> +import com.hp.hpl.jena.sparql.expr.E_Multiply;
>>> +import com.hp.hpl.jena.sparql.expr.Expr;
>>> +import com.hp.hpl.jena.sparql.expr.ExprVar;
>>> +import com.hp.hpl.jena.sparql.util.NodeFactory;
>>> +
>>> +/**
>>> + * Tests that user functions are properly wired in and usable from
>>> SPARQL
>>> + * @author rvesse
>>> + *
>>> + */
>>> +public class TestUserFunctionsInSparql {
>>> +
>>> +    @BeforeClass
>>> +    public static void setup() {
>>> +        UserDefinedFunctionFactory.getFactory().clear();
>>> +
>>> +        //Define a square function
>>> +        Expr square = new E_Multiply(new ExprVar("x"), new
>>> ExprVar("x"));
>>> +
>>> UserDefinedFunctionFactory.getFactory().add("http://example/square",
>>> square, new ArrayList<Var>(square.getVarsMentioned()));
>>> +    }
>>> +
>>> +    @AfterClass
>>> +    public static void teardown() {
>>> +        UserDefinedFunctionFactory.getFactory().clear();
>>> +    }
>>> +
>>> +    @Test
>>> +    public void test_user_functions_in_sparql() {
>>> +
>>> Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("h
>>> ttp://example/square"));
>>> +
>>> +        String query = "SELECT (<http://example/square>(2) AS ?square)
>>> { }";
>>> +        Query q = QueryFactory.create(query);
>>> +
>>> +        QueryExecution qe = QueryExecutionFactory.create(q,
>>> ModelFactory.createDefaultModel());
>>> +        ResultSet rset = qe.execSelect();
>>> +        Assert.assertTrue(rset.hasNext());
>>> +        Binding b = rset.nextBinding();
>>> +        Assert.assertFalse(rset.hasNext());
>>> +        qe.close();
>>> +
>>> +        //Validate returned value
>>> +        Node actual = b.get(Var.alloc("square"));
>>> +        Assert.assertEquals(NodeFactory.intToNode(4), actual);
>>> +    }
>>> +}
>>>
>>>
>


Re: svn commit: r1411358 - in /jena/trunk/jena-arq/src: main/java/com/hp/hpl/jena/sparql/function/ main/java/com/hp/hpl/jena/sparql/function/user/ test/java/com/hp/hpl/jena/sparql/function/ test/java/com/hp/hpl/jena/sparql/function/user/

Posted by Rob Vesse <rv...@yarcdata.com>.
Gah, damn Eclipse code templates

Have I mentioned I hate Eclipse!

Next commit will correct these, sorry

Rob



On 11/19/12 12:53 PM, "Stephen Allen" <sa...@apache.org> wrote:

>Hi Rob,
>
>Probably an oversight, but the code you checked in in this commit
>(revision 1411358) and in revision 1411398 have copyright headers for
>YarcData.  These files need to be removed or the header changed to the
>Apache copyright if the code is to be added to the project.
>
>-Stephen
>
>
>On Mon, Nov 19, 2012 at 2:26 PM,  <rv...@apache.org> wrote:
>> Author: rvesse
>> Date: Mon Nov 19 19:26:08 2012
>> New Revision: 1411358
>>
>> URL: http://svn.apache.org/viewvc?rev=1411358&view=rev
>> Log:
>> Initial framework for user defined functions
>>
>> Added:
>>     
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/
>>     
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Ex
>>prTransformExpand.java
>>     
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>erDefinedFunction.java
>>     
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>erDefinedFunctionDefinition.java
>>     
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>erDefinedFunctionFactory.java
>>     jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/
>>     
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/
>>     
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS
>>_UserFunctions.java
>>     
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>stFunctionExpansion.java
>>     
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>stUserDefinedFunctionFactory.java
>>     
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>stUserFunctionsInSparql.java
>> Modified:
>>     
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>n.java
>>     
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>nFactory.java
>>
>> Modified: 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>n.java
>> URL: 
>>http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl
>>/jena/sparql/function/Function.java?rev=1411358&r1=1411357&r2=1411358&vie
>>w=diff
>> 
>>=========================================================================
>>=====
>> --- 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>n.java (original)
>> +++ 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>n.java Mon Nov 19 19:26:08 2012
>> @@ -30,7 +30,7 @@ public interface Function
>>      /** Called during query plan construction immediately after the
>>       * construction of the extension instance.
>>       * Can throw ExprBuildException if something is wrong (like wrong
>>number of arguments).
>> -     * @param args The parsed arguements
>> +     * @param args The parsed arguments
>>       */
>>      public void build(String uri, ExprList args) ;
>>
>>
>> Modified: 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>nFactory.java
>> URL: 
>>http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl
>>/jena/sparql/function/FunctionFactory.java?rev=1411358&r1=1411357&r2=1411
>>358&view=diff
>> 
>>=========================================================================
>>=====
>> --- 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>nFactory.java (original)
>> +++ 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Functio
>>nFactory.java Mon Nov 19 19:26:08 2012
>> @@ -18,10 +18,18 @@
>>
>>  package com.hp.hpl.jena.sparql.function;
>>
>> +import com.hp.hpl.jena.sparql.sse.builders.ExprBuildException;
>>
>> -/** Interface for function factories. */
>> -
>> +/**
>> + *  Interface for function factories.
>> + */
>>  public interface FunctionFactory
>>  {
>> +    /**
>> +     * Create a function with the given URI
>> +     * @param uri URI
>> +     * @return Function
>> +     * @throws ExprBuildException May be thrown if there is a problem
>>creating a function
>> +     */
>>      public Function create(String uri) ;
>>  }
>>
>> Added: 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Ex
>>prTransformExpand.java
>> URL: 
>>http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl
>>/jena/sparql/function/user/ExprTransformExpand.java?rev=1411358&view=auto
>> 
>>=========================================================================
>>=====
>> --- 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Ex
>>prTransformExpand.java (added)
>> +++ 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Ex
>>prTransformExpand.java Mon Nov 19 19:26:08 2012
>> @@ -0,0 +1,84 @@
>> +/*
>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>> + */
>> +
>> +package com.hp.hpl.jena.sparql.function.user;
>> +
>> +import java.util.Map;
>> +
>> +import com.hp.hpl.jena.sparql.algebra.Op;
>> +import com.hp.hpl.jena.sparql.expr.Expr;
>> +import com.hp.hpl.jena.sparql.expr.ExprFunction;
>> +import com.hp.hpl.jena.sparql.expr.ExprFunction0;
>> +import com.hp.hpl.jena.sparql.expr.ExprFunction1;
>> +import com.hp.hpl.jena.sparql.expr.ExprFunction2;
>> +import com.hp.hpl.jena.sparql.expr.ExprFunction3;
>> +import com.hp.hpl.jena.sparql.expr.ExprFunctionN;
>> +import com.hp.hpl.jena.sparql.expr.ExprFunctionOp;
>> +import com.hp.hpl.jena.sparql.expr.ExprList;
>> +import com.hp.hpl.jena.sparql.expr.ExprTransformCopy;
>> +
>> +/**
>> + * An expression transformer that will expand user defined expressions
>>so they do not explicitly rely on other user defined functions
>> + * @author rvesse
>> + *
>> + */
>> +public class ExprTransformExpand extends ExprTransformCopy {
>> +
>> +    private Map<String, UserDefinedFunctionDefinition> definitions;
>> +
>> +    /**
>> +     * Creates a new transformer
>> +     * @param defs User defined function definitions
>> +     */
>> +    public ExprTransformExpand(Map<String,
>>UserDefinedFunctionDefinition> defs) {
>> +        if (defs == null) throw new IllegalArgumentException("defs
>>cannot be null");
>> +        this.definitions = defs;
>> +    }
>> +
>> +    @Override
>> +    public Expr transform(ExprFunction0 func) {
>> +        ExprFunction f = func.getFunction();
>> +        if (this.shouldExpand(f)) {
>> +            //TODO Need to expand the function
>> +            return super.transform(func);
>> +        } else {
>> +            return super.transform(func);
>> +        }
>> +    }
>> +
>> +    @Override
>> +    public Expr transform(ExprFunction1 func, Expr expr1) {
>> +        // TODO Auto-generated method stub
>> +        return super.transform(func, expr1);
>> +    }
>> +
>> +    @Override
>> +    public Expr transform(ExprFunction2 func, Expr expr1, Expr expr2) {
>> +        // TODO Auto-generated method stub
>> +        return super.transform(func, expr1, expr2);
>> +    }
>> +
>> +    @Override
>> +    public Expr transform(ExprFunction3 func, Expr expr1, Expr expr2,
>>Expr expr3) {
>> +        // TODO Auto-generated method stub
>> +        return super.transform(func, expr1, expr2, expr3);
>> +    }
>> +
>> +    @Override
>> +    public Expr transform(ExprFunctionN func, ExprList args) {
>> +        // TODO Auto-generated method stub
>> +        return super.transform(func, args);
>> +    }
>> +
>> +    @Override
>> +    public Expr transform(ExprFunctionOp funcOp, ExprList args, Op
>>opArg) {
>> +        // TODO Auto-generated method stub
>> +        return super.transform(funcOp, args, opArg);
>> +    }
>> +
>> +    private boolean shouldExpand(ExprFunction func) {
>> +        return this.definitions.containsKey(func.getFunctionIRI());
>> +    }
>> +
>> +}
>>
>> Added: 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>erDefinedFunction.java
>> URL: 
>>http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl
>>/jena/sparql/function/user/UserDefinedFunction.java?rev=1411358&view=auto
>> 
>>=========================================================================
>>=====
>> --- 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>erDefinedFunction.java (added)
>> +++ 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>erDefinedFunction.java Mon Nov 19 19:26:08 2012
>> @@ -0,0 +1,82 @@
>> +/*
>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>> + */
>> +
>> +package com.hp.hpl.jena.sparql.function.user;
>> +
>> +import java.util.HashMap;
>> +import java.util.List;
>> +import java.util.Map;
>> +import com.hp.hpl.jena.sparql.core.Var;
>> +import com.hp.hpl.jena.sparql.engine.binding.Binding;
>> +import com.hp.hpl.jena.sparql.expr.Expr;
>> +import com.hp.hpl.jena.sparql.expr.ExprList;
>> +import com.hp.hpl.jena.sparql.expr.ExprTransformSubstitute;
>> +import com.hp.hpl.jena.sparql.expr.ExprTransformer;
>> +import com.hp.hpl.jena.sparql.expr.NodeValue;
>> +import com.hp.hpl.jena.sparql.function.Function;
>> +import com.hp.hpl.jena.sparql.function.FunctionEnv;
>> +import com.hp.hpl.jena.sparql.sse.builders.ExprBuildException;
>> +
>> +/**
>> + * Represents a user defined function
>> + * @author rvesse
>> + *
>> + */
>> +public class UserDefinedFunction extends UserDefinedFunctionDefinition
>>implements Function {
>> +
>> +    private Expr actualExpr;
>> +
>> +    /**
>> +     * Creates a new user defined function
>> +     * @param def Function Definition
>> +     */
>> +    public UserDefinedFunction(UserDefinedFunctionDefinition def) {
>> +        super(def.getUri(), def.getBaseExpr(), def.getArgList());
>> +    }
>> +
>> +    /**
>> +     * Creates a user defined function
>> +     * @param url Function URL
>> +     * @param e Expression
>> +     * @param argList Arguments
>> +     */
>> +    public UserDefinedFunction(String url, Expr e, List<Var> argList) {
>> +        super(url, e, argList);
>> +    }
>> +
>> +    /**
>> +     * Builds the expression substituting the arguments given into the
>>base expression to yield the actual expression to evaluate
>> +     * @throws ExprBuildException Thrown if an expression cannot be
>>generated
>> +     */
>> +    @Override
>> +    public void build(String uri, ExprList args) {
>> +        //Substitutes the arguments into the base expression to give
>>the actual expression to evaluate
>> +        if (uri == null || !uri.equals(this.getUri())) throw new
>>ExprBuildException("Incorrect URI passed to build() call, expected <" +
>>this.getUri() + "> but got <" + uri + ">");
>> +        if (this.getArgList().size() != args.size()) throw new
>>ExprBuildException("Incorrect number of arguments for user defined <" +
>>this.getUri() + "> function");
>> +
>> +        Map<String, Expr> substitutions = new HashMap<String, Expr>();
>> +        for (int i = 0; i < this.getArgList().size(); i++) {
>> +            substitutions.put(this.getArgList().get(i).getVarName(),
>>args.get(i));
>> +        }
>> +
>> +        this.actualExpr = ExprTransformer.transform(new
>>ExprTransformSubstitute(substitutions), this.getBaseExpr());
>> +    }
>> +
>> +    /**
>> +     * Executes the function
>> +     */
>> +    @Override
>> +    public NodeValue exec(Binding binding, ExprList args, String uri,
>>FunctionEnv env) {
>> +        //Evaluate the actual expression
>> +        return this.actualExpr.eval(binding, env);
>> +    }
>> +
>> +    /**
>> +     * Gets the actual expression that was built for the function,
>>assuming {@link #build(String, ExprList)} has been called
>> +     * @return Expression if built, null otherwise
>> +     */
>> +    public Expr getActualExpr() {
>> +        return this.actualExpr;
>> +    }
>> +}
>>
>> Added: 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>erDefinedFunctionDefinition.java
>> URL: 
>>http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl
>>/jena/sparql/function/user/UserDefinedFunctionDefinition.java?rev=1411358
>>&view=auto
>> 
>>=========================================================================
>>=====
>> --- 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>erDefinedFunctionDefinition.java (added)
>> +++ 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>erDefinedFunctionDefinition.java Mon Nov 19 19:26:08 2012
>> @@ -0,0 +1,68 @@
>> +/*
>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>> + */
>> +
>> +package com.hp.hpl.jena.sparql.function.user;
>> +
>> +import java.util.ArrayList;
>> +import java.util.List;
>> +
>> +import com.hp.hpl.jena.sparql.core.Var;
>> +import com.hp.hpl.jena.sparql.expr.Expr;
>> +import com.hp.hpl.jena.sparql.function.Function;
>> +
>> +/**
>> + * Represents the definition of a user defined function
>> + * @author rvesse
>> + *
>> + */
>> +public class UserDefinedFunctionDefinition {
>> +
>> +    private String uri;
>> +    private Expr expr;
>> +    private List<Var> argList;
>> +
>> +    /**
>> +     * Creates a user defined function definition
>> +     * @param uri Function URL
>> +     * @param e Expression
>> +     * @param argList Arguments
>> +     */
>> +    public UserDefinedFunctionDefinition(String uri, Expr e, List<Var>
>>argList) {
>> +        this.uri = uri;
>> +        this.expr = e;
>> +        this.argList = new ArrayList<Var>(argList);
>> +    }
>> +
>> +    /**
>> +     * Gets the base expression
>> +     * @return Expression
>> +     */
>> +    public Expr getBaseExpr() {
>> +        return this.expr;
>> +    }
>> +
>> +    /**
>> +     * Gets the argument list
>> +     * @return Arguments
>> +     */
>> +    public List<Var> getArgList() {
>> +        return this.argList;
>> +    }
>> +
>> +    /**
>> +     * Gets the function URI
>> +     * @return URI
>> +     */
>> +    public String getUri() {
>> +        return this.uri;
>> +    }
>> +
>> +    /**
>> +     * Gets an instance of an actual {@link Function} that can be used
>>to evaluate this function
>> +     * @return Function instance
>> +     */
>> +    public Function newFunctionInstance() {
>> +        return new UserDefinedFunction(this);
>> +    }
>> +}
>>
>> Added: 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>erDefinedFunctionFactory.java
>> URL: 
>>http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl
>>/jena/sparql/function/user/UserDefinedFunctionFactory.java?rev=1411358&vi
>>ew=auto
>> 
>>=========================================================================
>>=====
>> --- 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>erDefinedFunctionFactory.java (added)
>> +++ 
>>jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/Us
>>erDefinedFunctionFactory.java Mon Nov 19 19:26:08 2012
>> @@ -0,0 +1,149 @@
>> +/*
>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>> + */
>> +
>> +package com.hp.hpl.jena.sparql.function.user;
>> +
>> +import java.io.StringReader;
>> +import java.util.HashMap;
>> +import java.util.List;
>> +import java.util.Map;
>> +import java.util.NoSuchElementException;
>> +
>> +import com.hp.hpl.jena.sparql.core.Var;
>> +import com.hp.hpl.jena.sparql.expr.Expr;
>> +import com.hp.hpl.jena.sparql.function.Function;
>> +import com.hp.hpl.jena.sparql.function.FunctionFactory;
>> +import com.hp.hpl.jena.sparql.function.FunctionRegistry;
>> +import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
>> +import com.hp.hpl.jena.sparql.lang.sparql_11.SPARQLParser11;
>> +import com.hp.hpl.jena.sparql.sse.builders.ExprBuildException;
>> +
>> +/**
>> + * A function factory for managing user defined functions
>> + * <p>
>> + * User defined functions provide a simple mechanism for a user to
>>inject custom functions into SPARQL processing
>> + * without the need to write any code.  These functions essentially
>>act as aliases for another SPARQL expression
>> + * and serve as a means to aid users in simplifying their SPARQL
>>queries.
>> + * </p>
>> + * <p>
>> + * For example we can define a <strong>square</strong> function like
>>so:
>> + * </p>
>> + * <pre>
>> + * List&lt;Var&gt; args = new ArrayList&lt;Var&gt;(Var.alloc("x"));
>> + * 
>>UserDefinedFunctionFactory.getFactory().add("http://example/square", "?x
>>* ?x", args);
>> + * </pre>
>> + * <p>
>> + * We can then use this in queries like so:
>> + * </p>
>> + * <pre>
>> + * SELECT (&lt;http://example/square&gt;(3) AS ?ThreeSquared) { }
>> + * </pre>
>> + * <p>
>> + * Internally the call to the <strong>square</strong> function is
>>translated into it's equivalent SPARQL expression and executed in that
>>form.
>> + * </p>
>> + * @author rvesse
>> + *
>> + */
>> +public class UserDefinedFunctionFactory implements FunctionFactory {
>> +
>> +    private static UserDefinedFunctionFactory factory = new
>>UserDefinedFunctionFactory();
>> +
>> +    /**
>> +     * Gets the static instance of the factory
>> +     * @return Function Factory
>> +     */
>> +    public static UserDefinedFunctionFactory getFactory() {
>> +        return factory;
>> +    }
>> +
>> +    private Map<String, UserDefinedFunctionDefinition> definitions =
>>new HashMap<String, UserDefinedFunctionDefinition>();
>> +
>> +    /**
>> +     * Private constructor prevents instantiation
>> +     */
>> +    private UserDefinedFunctionFactory() { }
>> +
>> +    /**
>> +     * Creates a function for the given URI
>> +     * @throws ExprBuildException Thrown if the given URI is not a
>>known function
>> +     */
>> +    @Override
>> +    public Function create(String uri) {
>> +        UserDefinedFunctionDefinition def = this.definitions.get(uri);
>> +        if (def == null) throw new ExprBuildException("Function <" +
>>uri + "> not known by this function factory");
>> +        return def.newFunctionInstance();
>> +    }
>> +
>> +    /**
>> +     * Adds a function
>> +     * @param uri URI
>> +     * @param e Expression
>> +     * @param args Arguments
>> +     */
>> +    public void add(String uri, Expr e, List<Var> args) {
>> +        UserDefinedFunctionDefinition def = new
>>UserDefinedFunctionDefinition(uri, e, args);
>> +        this.definitions.put(uri, def);
>> +        FunctionRegistry.get().put(uri, this);
>> +    }
>> +
>> +    /**
>> +     * Adds a function
>> +     * <p>
>> +     * This method will build the expression to use based on the
>>expression string given, strings must match the SPARQL expression syntax
>>e.g.
>> +     * </p>
>> +     * <pre>
>> +     * (?x * ?y) + 5
>> +     * </pre>
>> +     * @param uri URI
>> +     * @param expr Expression String (in SPARQL syntax)
>> +     * @param args Arguments
>> +     * @throws ParseException Thrown if the expression string is not
>>valid syntax
>> +     */
>> +    public void add(String uri, String expr, List<Var> args) throws
>>ParseException {
>> +        Expr e = new SPARQLParser11(new
>>StringReader(expr)).Expression();
>> +        UserDefinedFunctionDefinition def = new
>>UserDefinedFunctionDefinition(uri, e, args);
>> +        this.definitions.put(uri, def);
>> +        FunctionRegistry.get().put(uri, this);
>> +    }
>> +
>> +    /**
>> +     * Removes a function definition
>> +     * @param uri URI
>> +     * @throws NoSuchElementException Thrown if a function with the
>>given URI does not exist
>> +     */
>> +    public void remove(String uri) {
>> +        if (!this.definitions.containsKey(uri)) throw new
>>NoSuchElementException("No function definition is associated with the
>>URI <" + uri + ">");
>> +        this.definitions.remove(uri);
>> +        FunctionRegistry.get().remove(uri);
>> +    }
>> +
>> +    /**
>> +     * Gets the definition of the function (if registered)
>> +     * @param uri URI
>> +     * @return Function Definition if registered, null otherwise
>> +     */
>> +    public UserDefinedFunctionDefinition get(String uri) {
>> +        if (!this.definitions.containsKey(uri)) return null;
>> +        return this.definitions.get(uri);
>> +    }
>> +
>> +    /**
>> +     * Gets whether a function with the given URI has been registered
>> +     * @param uri URI
>> +     * @return True if registered, false otherwise
>> +     */
>> +    public boolean isRegistered(String uri) {
>> +        return this.definitions.containsKey(uri);
>> +    }
>> +
>> +    /**
>> +     * Clears all function definitions
>> +     */
>> +    public void clear() {
>> +        for (String uri : this.definitions.keySet()) {
>> +            FunctionRegistry.get().remove(uri);
>> +        }
>> +        this.definitions.clear();
>> +    }
>> +}
>>
>> Added: 
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS
>>_UserFunctions.java
>> URL: 
>>http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl
>>/jena/sparql/function/user/TS_UserFunctions.java?rev=1411358&view=auto
>> 
>>=========================================================================
>>=====
>> --- 
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS
>>_UserFunctions.java (added)
>> +++ 
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS
>>_UserFunctions.java Mon Nov 19 19:26:08 2012
>> @@ -0,0 +1,27 @@
>> +/*
>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>> + */
>> +
>> +package com.hp.hpl.jena.sparql.function.user;
>> +
>> +import junit.framework.JUnit4TestAdapter;
>> +
>> +import org.junit.BeforeClass;
>> +import org.junit.runner.RunWith;
>> +import org.junit.runners.Suite;
>> +import org.junit.runners.Suite.SuiteClasses;
>> +
>> +import com.hp.hpl.jena.sparql.expr.TS_Expr;
>> +
>> +@RunWith(Suite.class)
>> +@SuiteClasses( {
>> +    TestUserDefinedFunctionFactory.class,
>> +    TestFunctionExpansion.class,
>> +    TestUserFunctionsInSparql.class
>> +})
>> +public class TS_UserFunctions {
>> +
>> +    public static junit.framework.Test suite() {
>> +        return new JUnit4TestAdapter(TS_Expr.class);
>> +      }
>> +}
>>
>> Added: 
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>stFunctionExpansion.java
>> URL: 
>>http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl
>>/jena/sparql/function/user/TestFunctionExpansion.java?rev=1411358&view=au
>>to
>> 
>>=========================================================================
>>=====
>> --- 
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>stFunctionExpansion.java (added)
>> +++ 
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>stFunctionExpansion.java Mon Nov 19 19:26:08 2012
>> @@ -0,0 +1,87 @@
>> +/*
>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>> + */
>> +
>> +package com.hp.hpl.jena.sparql.function.user;
>> +
>> +import java.util.ArrayList;
>> +import java.util.List;
>> +
>> +import org.junit.AfterClass;
>> +import org.junit.Assert;
>> +import org.junit.BeforeClass;
>> +import org.junit.Test;
>> +
>> +import com.hp.hpl.jena.sparql.core.Var;
>> +import com.hp.hpl.jena.sparql.expr.E_Multiply;
>> +import com.hp.hpl.jena.sparql.expr.Expr;
>> +import com.hp.hpl.jena.sparql.expr.ExprList;
>> +import com.hp.hpl.jena.sparql.expr.ExprVar;
>> +import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueBoolean;
>> +import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueInteger;
>> +
>> +/**
>> + * Test for checking that functions are appropriately expanded when
>>supplied with actual arguments
>> + * @author rvesse
>> + *
>> + */
>> +public class TestFunctionExpansion {
>> +
>> +    @BeforeClass
>> +    public static void setup() {
>> +        UserDefinedFunctionFactory.getFactory().clear();
>> +    }
>> +
>> +    @AfterClass
>> +    public static void teardown() {
>> +        UserDefinedFunctionFactory.getFactory().clear();
>> +    }
>> +
>> +    @Test
>> +    public void test_function_expansion_01() {
>> +        Expr e = new ExprVar("x");
>> +        
>>UserDefinedFunctionFactory.getFactory().add("http://example/simple", e,
>>new ArrayList<Var>(e.getVarsMentioned()));
>> +
>> +        UserDefinedFunction f = (UserDefinedFunction)
>>UserDefinedFunctionFactory.getFactory().create("http://example/simple");
>> +        f.build("http://example/simple", new ExprList(new
>>NodeValueBoolean(true)));
>> +
>> +        Expr actual = f.getActualExpr();
>> +        Assert.assertFalse(e.equals(actual));
>> +        Assert.assertEquals(0, actual.getVarsMentioned().size());
>> +        Assert.assertEquals(new NodeValueBoolean(true), actual);
>> +    }
>> +
>> +    @Test
>> +    public void test_function_expansion_02() {
>> +        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
>> +        
>>UserDefinedFunctionFactory.getFactory().add("http://example/square", e,
>>new ArrayList<Var>(e.getVarsMentioned()));
>> +
>> +        UserDefinedFunction f = (UserDefinedFunction)
>>UserDefinedFunctionFactory.getFactory().create("http://example/square");
>> +        f.build("http://example/square", new ExprList(new
>>NodeValueInteger(3)));
>> +
>> +        Expr actual = f.getActualExpr();
>> +        Assert.assertFalse(e.equals(actual));
>> +        Assert.assertEquals(0, actual.getVarsMentioned().size());
>> +        Assert.assertEquals(new E_Multiply(new NodeValueInteger(3),
>>new NodeValueInteger(3)), actual);
>> +    }
>> +
>> +    @Test
>> +    public void test_function_expansion_03() {
>> +        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("y"));
>> +        List<Var> defArgs = new ArrayList<Var>();
>> +        defArgs.add(Var.alloc("x"));
>> +        defArgs.add(Var.alloc("y"));
>> +        
>>UserDefinedFunctionFactory.getFactory().add("http://example/square", e,
>>defArgs);
>> +
>> +        UserDefinedFunction f = (UserDefinedFunction)
>>UserDefinedFunctionFactory.getFactory().create("http://example/square");
>> +        ExprList args = new ExprList();
>> +        args.add(new NodeValueInteger(3));
>> +        args.add(new NodeValueInteger(4));
>> +        f.build("http://example/square", args);
>> +
>> +        Expr actual = f.getActualExpr();
>> +        Assert.assertFalse(e.equals(actual));
>> +        Assert.assertEquals(0, actual.getVarsMentioned().size());
>> +        Assert.assertEquals(new E_Multiply(new NodeValueInteger(3),
>>new NodeValueInteger(4)), actual);
>> +    }
>> +}
>>
>> Added: 
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>stUserDefinedFunctionFactory.java
>> URL: 
>>http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl
>>/jena/sparql/function/user/TestUserDefinedFunctionFactory.java?rev=141135
>>8&view=auto
>> 
>>=========================================================================
>>=====
>> --- 
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>stUserDefinedFunctionFactory.java (added)
>> +++ 
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>stUserDefinedFunctionFactory.java Mon Nov 19 19:26:08 2012
>> @@ -0,0 +1,76 @@
>> +/*
>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>> + */
>> +
>> +package com.hp.hpl.jena.sparql.function.user;
>> +
>> +import java.util.ArrayList;
>> +
>> +import junit.framework.Assert;
>> +
>> +import org.junit.AfterClass;
>> +import org.junit.BeforeClass;
>> +import org.junit.Test;
>> +
>> +import com.hp.hpl.jena.sparql.core.Var;
>> +import com.hp.hpl.jena.sparql.expr.E_Multiply;
>> +import com.hp.hpl.jena.sparql.expr.Expr;
>> +import com.hp.hpl.jena.sparql.expr.ExprVar;
>> +import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
>> +
>> +/**
>> + * Tests for the {@link UserDefinedFunctionFactory}
>> + * @author rvesse
>> + *
>> + */
>> +public class TestUserDefinedFunctionFactory {
>> +
>> +    @BeforeClass
>> +    public static void setup() {
>> +        UserDefinedFunctionFactory.getFactory().clear();
>> +    }
>> +
>> +    @AfterClass
>> +    public static void teardown() {
>> +        UserDefinedFunctionFactory.getFactory().clear();
>> +    }
>> +
>> +    @Test
>> +    public void test_user_defined_function_factory_instance() {
>> +        UserDefinedFunctionFactory factory =
>>UserDefinedFunctionFactory.getFactory();
>> +        Assert.assertNotNull(factory);
>> +    }
>> +
>> +    @Test
>> +    public void test_user_defined_function_factory_add_01() {
>> +        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
>> +        
>>UserDefinedFunctionFactory.getFactory().add("http://example/square", e,
>>new ArrayList<Var>(e.getVarsMentioned()));
>> +        
>>Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("h
>>ttp://example/square"));
>> +        Assert.assertEquals(e,
>>UserDefinedFunctionFactory.getFactory().get("http://example/square").getB
>>aseExpr());
>> +    }
>> +
>> +    @Test
>> +    public void test_user_defined_function_factory_add_02() {
>> +        Expr e1 = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
>> +        Expr e2 = new E_Multiply(new ExprVar("y"), new ExprVar("y"));
>> +
>> +        
>>UserDefinedFunctionFactory.getFactory().add("http://example/square", e1,
>>new ArrayList<Var>(e1.getVarsMentioned()));
>> +        
>>Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("h
>>ttp://example/square"));
>> +        Assert.assertEquals(e1,
>>UserDefinedFunctionFactory.getFactory().get("http://example/square").getB
>>aseExpr());
>> +
>> +        
>>UserDefinedFunctionFactory.getFactory().add("http://example/square", e2,
>>new ArrayList<Var>(e2.getVarsMentioned()));
>> +        
>>Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("h
>>ttp://example/square"));
>> +        Assert.assertEquals(e2,
>>UserDefinedFunctionFactory.getFactory().get("http://example/square").getB
>>aseExpr());
>> +    }
>> +
>> +    @Test
>> +    public void test_user_defined_function_factory_add_03() throws
>>ParseException {
>> +        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
>> +
>> +        //Instead of registering the pre-built expression register
>>using a string for the expression
>> +        
>>UserDefinedFunctionFactory.getFactory().add("http://example/square", "?x
>>* ?x", new ArrayList<Var>(e.getVarsMentioned()));
>> +
>> +        
>>Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("h
>>ttp://example/square"));
>> +        Assert.assertEquals(e,
>>UserDefinedFunctionFactory.getFactory().get("http://example/square").getB
>>aseExpr());
>> +    }
>> +}
>>
>> Added: 
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>stUserFunctionsInSparql.java
>> URL: 
>>http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl
>>/jena/sparql/function/user/TestUserFunctionsInSparql.java?rev=1411358&vie
>>w=auto
>> 
>>=========================================================================
>>=====
>> --- 
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>stUserFunctionsInSparql.java (added)
>> +++ 
>>jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/Te
>>stUserFunctionsInSparql.java Mon Nov 19 19:26:08 2012
>> @@ -0,0 +1,68 @@
>> +/*
>> + * Copyright 2012 YarcData LLC All Rights Reserved.
>> + */
>> +
>> +package com.hp.hpl.jena.sparql.function.user;
>> +
>> +import java.util.ArrayList;
>> +
>> +import junit.framework.Assert;
>> +
>> +import org.junit.AfterClass;
>> +import org.junit.BeforeClass;
>> +import org.junit.Test;
>> +
>> +import com.hp.hpl.jena.graph.Node;
>> +import com.hp.hpl.jena.query.Query;
>> +import com.hp.hpl.jena.query.QueryExecution;
>> +import com.hp.hpl.jena.query.QueryExecutionFactory;
>> +import com.hp.hpl.jena.query.QueryFactory;
>> +import com.hp.hpl.jena.query.ResultSet;
>> +import com.hp.hpl.jena.rdf.model.ModelFactory;
>> +import com.hp.hpl.jena.sparql.core.Var;
>> +import com.hp.hpl.jena.sparql.engine.binding.Binding;
>> +import com.hp.hpl.jena.sparql.expr.E_Multiply;
>> +import com.hp.hpl.jena.sparql.expr.Expr;
>> +import com.hp.hpl.jena.sparql.expr.ExprVar;
>> +import com.hp.hpl.jena.sparql.util.NodeFactory;
>> +
>> +/**
>> + * Tests that user functions are properly wired in and usable from
>>SPARQL
>> + * @author rvesse
>> + *
>> + */
>> +public class TestUserFunctionsInSparql {
>> +
>> +    @BeforeClass
>> +    public static void setup() {
>> +        UserDefinedFunctionFactory.getFactory().clear();
>> +
>> +        //Define a square function
>> +        Expr square = new E_Multiply(new ExprVar("x"), new
>>ExprVar("x"));
>> +        
>>UserDefinedFunctionFactory.getFactory().add("http://example/square",
>>square, new ArrayList<Var>(square.getVarsMentioned()));
>> +    }
>> +
>> +    @AfterClass
>> +    public static void teardown() {
>> +        UserDefinedFunctionFactory.getFactory().clear();
>> +    }
>> +
>> +    @Test
>> +    public void test_user_functions_in_sparql() {
>> +        
>>Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("h
>>ttp://example/square"));
>> +
>> +        String query = "SELECT (<http://example/square>(2) AS ?square) 
>>{ }";
>> +        Query q = QueryFactory.create(query);
>> +
>> +        QueryExecution qe = QueryExecutionFactory.create(q, 
>>ModelFactory.createDefaultModel());
>> +        ResultSet rset = qe.execSelect();
>> +        Assert.assertTrue(rset.hasNext());
>> +        Binding b = rset.nextBinding();
>> +        Assert.assertFalse(rset.hasNext());
>> +        qe.close();
>> +
>> +        //Validate returned value
>> +        Node actual = b.get(Var.alloc("square"));
>> +        Assert.assertEquals(NodeFactory.intToNode(4), actual);
>> +    }
>> +}
>>
>>


Re: svn commit: r1411358 - in /jena/trunk/jena-arq/src: main/java/com/hp/hpl/jena/sparql/function/ main/java/com/hp/hpl/jena/sparql/function/user/ test/java/com/hp/hpl/jena/sparql/function/ test/java/com/hp/hpl/jena/sparql/function/user/

Posted by Stephen Allen <sa...@apache.org>.
Hi Rob,

Probably an oversight, but the code you checked in in this commit
(revision 1411358) and in revision 1411398 have copyright headers for
YarcData.  These files need to be removed or the header changed to the
Apache copyright if the code is to be added to the project.

-Stephen


On Mon, Nov 19, 2012 at 2:26 PM,  <rv...@apache.org> wrote:
> Author: rvesse
> Date: Mon Nov 19 19:26:08 2012
> New Revision: 1411358
>
> URL: http://svn.apache.org/viewvc?rev=1411358&view=rev
> Log:
> Initial framework for user defined functions
>
> Added:
>     jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/
>     jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/ExprTransformExpand.java
>     jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunction.java
>     jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionDefinition.java
>     jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionFactory.java
>     jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/
>     jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/
>     jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS_UserFunctions.java
>     jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestFunctionExpansion.java
>     jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserDefinedFunctionFactory.java
>     jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserFunctionsInSparql.java
> Modified:
>     jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Function.java
>     jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/FunctionFactory.java
>
> Modified: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Function.java
> URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Function.java?rev=1411358&r1=1411357&r2=1411358&view=diff
> ==============================================================================
> --- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Function.java (original)
> +++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/Function.java Mon Nov 19 19:26:08 2012
> @@ -30,7 +30,7 @@ public interface Function
>      /** Called during query plan construction immediately after the
>       * construction of the extension instance.
>       * Can throw ExprBuildException if something is wrong (like wrong number of arguments).
> -     * @param args The parsed arguements
> +     * @param args The parsed arguments
>       */
>      public void build(String uri, ExprList args) ;
>
>
> Modified: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/FunctionFactory.java
> URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/FunctionFactory.java?rev=1411358&r1=1411357&r2=1411358&view=diff
> ==============================================================================
> --- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/FunctionFactory.java (original)
> +++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/FunctionFactory.java Mon Nov 19 19:26:08 2012
> @@ -18,10 +18,18 @@
>
>  package com.hp.hpl.jena.sparql.function;
>
> +import com.hp.hpl.jena.sparql.sse.builders.ExprBuildException;
>
> -/** Interface for function factories. */
> -
> +/**
> + *  Interface for function factories.
> + */
>  public interface FunctionFactory
>  {
> +    /**
> +     * Create a function with the given URI
> +     * @param uri URI
> +     * @return Function
> +     * @throws ExprBuildException May be thrown if there is a problem creating a function
> +     */
>      public Function create(String uri) ;
>  }
>
> Added: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/ExprTransformExpand.java
> URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/ExprTransformExpand.java?rev=1411358&view=auto
> ==============================================================================
> --- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/ExprTransformExpand.java (added)
> +++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/ExprTransformExpand.java Mon Nov 19 19:26:08 2012
> @@ -0,0 +1,84 @@
> +/*
> + * Copyright 2012 YarcData LLC All Rights Reserved.
> + */
> +
> +package com.hp.hpl.jena.sparql.function.user;
> +
> +import java.util.Map;
> +
> +import com.hp.hpl.jena.sparql.algebra.Op;
> +import com.hp.hpl.jena.sparql.expr.Expr;
> +import com.hp.hpl.jena.sparql.expr.ExprFunction;
> +import com.hp.hpl.jena.sparql.expr.ExprFunction0;
> +import com.hp.hpl.jena.sparql.expr.ExprFunction1;
> +import com.hp.hpl.jena.sparql.expr.ExprFunction2;
> +import com.hp.hpl.jena.sparql.expr.ExprFunction3;
> +import com.hp.hpl.jena.sparql.expr.ExprFunctionN;
> +import com.hp.hpl.jena.sparql.expr.ExprFunctionOp;
> +import com.hp.hpl.jena.sparql.expr.ExprList;
> +import com.hp.hpl.jena.sparql.expr.ExprTransformCopy;
> +
> +/**
> + * An expression transformer that will expand user defined expressions so they do not explicitly rely on other user defined functions
> + * @author rvesse
> + *
> + */
> +public class ExprTransformExpand extends ExprTransformCopy {
> +
> +    private Map<String, UserDefinedFunctionDefinition> definitions;
> +
> +    /**
> +     * Creates a new transformer
> +     * @param defs User defined function definitions
> +     */
> +    public ExprTransformExpand(Map<String, UserDefinedFunctionDefinition> defs) {
> +        if (defs == null) throw new IllegalArgumentException("defs cannot be null");
> +        this.definitions = defs;
> +    }
> +
> +    @Override
> +    public Expr transform(ExprFunction0 func) {
> +        ExprFunction f = func.getFunction();
> +        if (this.shouldExpand(f)) {
> +            //TODO Need to expand the function
> +            return super.transform(func);
> +        } else {
> +            return super.transform(func);
> +        }
> +    }
> +
> +    @Override
> +    public Expr transform(ExprFunction1 func, Expr expr1) {
> +        // TODO Auto-generated method stub
> +        return super.transform(func, expr1);
> +    }
> +
> +    @Override
> +    public Expr transform(ExprFunction2 func, Expr expr1, Expr expr2) {
> +        // TODO Auto-generated method stub
> +        return super.transform(func, expr1, expr2);
> +    }
> +
> +    @Override
> +    public Expr transform(ExprFunction3 func, Expr expr1, Expr expr2, Expr expr3) {
> +        // TODO Auto-generated method stub
> +        return super.transform(func, expr1, expr2, expr3);
> +    }
> +
> +    @Override
> +    public Expr transform(ExprFunctionN func, ExprList args) {
> +        // TODO Auto-generated method stub
> +        return super.transform(func, args);
> +    }
> +
> +    @Override
> +    public Expr transform(ExprFunctionOp funcOp, ExprList args, Op opArg) {
> +        // TODO Auto-generated method stub
> +        return super.transform(funcOp, args, opArg);
> +    }
> +
> +    private boolean shouldExpand(ExprFunction func) {
> +        return this.definitions.containsKey(func.getFunctionIRI());
> +    }
> +
> +}
>
> Added: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunction.java
> URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunction.java?rev=1411358&view=auto
> ==============================================================================
> --- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunction.java (added)
> +++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunction.java Mon Nov 19 19:26:08 2012
> @@ -0,0 +1,82 @@
> +/*
> + * Copyright 2012 YarcData LLC All Rights Reserved.
> + */
> +
> +package com.hp.hpl.jena.sparql.function.user;
> +
> +import java.util.HashMap;
> +import java.util.List;
> +import java.util.Map;
> +import com.hp.hpl.jena.sparql.core.Var;
> +import com.hp.hpl.jena.sparql.engine.binding.Binding;
> +import com.hp.hpl.jena.sparql.expr.Expr;
> +import com.hp.hpl.jena.sparql.expr.ExprList;
> +import com.hp.hpl.jena.sparql.expr.ExprTransformSubstitute;
> +import com.hp.hpl.jena.sparql.expr.ExprTransformer;
> +import com.hp.hpl.jena.sparql.expr.NodeValue;
> +import com.hp.hpl.jena.sparql.function.Function;
> +import com.hp.hpl.jena.sparql.function.FunctionEnv;
> +import com.hp.hpl.jena.sparql.sse.builders.ExprBuildException;
> +
> +/**
> + * Represents a user defined function
> + * @author rvesse
> + *
> + */
> +public class UserDefinedFunction extends UserDefinedFunctionDefinition implements Function {
> +
> +    private Expr actualExpr;
> +
> +    /**
> +     * Creates a new user defined function
> +     * @param def Function Definition
> +     */
> +    public UserDefinedFunction(UserDefinedFunctionDefinition def) {
> +        super(def.getUri(), def.getBaseExpr(), def.getArgList());
> +    }
> +
> +    /**
> +     * Creates a user defined function
> +     * @param url Function URL
> +     * @param e Expression
> +     * @param argList Arguments
> +     */
> +    public UserDefinedFunction(String url, Expr e, List<Var> argList) {
> +        super(url, e, argList);
> +    }
> +
> +    /**
> +     * Builds the expression substituting the arguments given into the base expression to yield the actual expression to evaluate
> +     * @throws ExprBuildException Thrown if an expression cannot be generated
> +     */
> +    @Override
> +    public void build(String uri, ExprList args) {
> +        //Substitutes the arguments into the base expression to give the actual expression to evaluate
> +        if (uri == null || !uri.equals(this.getUri())) throw new ExprBuildException("Incorrect URI passed to build() call, expected <" + this.getUri() + "> but got <" + uri + ">");
> +        if (this.getArgList().size() != args.size()) throw new ExprBuildException("Incorrect number of arguments for user defined <" + this.getUri() + "> function");
> +
> +        Map<String, Expr> substitutions = new HashMap<String, Expr>();
> +        for (int i = 0; i < this.getArgList().size(); i++) {
> +            substitutions.put(this.getArgList().get(i).getVarName(), args.get(i));
> +        }
> +
> +        this.actualExpr = ExprTransformer.transform(new ExprTransformSubstitute(substitutions), this.getBaseExpr());
> +    }
> +
> +    /**
> +     * Executes the function
> +     */
> +    @Override
> +    public NodeValue exec(Binding binding, ExprList args, String uri, FunctionEnv env) {
> +        //Evaluate the actual expression
> +        return this.actualExpr.eval(binding, env);
> +    }
> +
> +    /**
> +     * Gets the actual expression that was built for the function, assuming {@link #build(String, ExprList)} has been called
> +     * @return Expression if built, null otherwise
> +     */
> +    public Expr getActualExpr() {
> +        return this.actualExpr;
> +    }
> +}
>
> Added: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionDefinition.java
> URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionDefinition.java?rev=1411358&view=auto
> ==============================================================================
> --- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionDefinition.java (added)
> +++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionDefinition.java Mon Nov 19 19:26:08 2012
> @@ -0,0 +1,68 @@
> +/*
> + * Copyright 2012 YarcData LLC All Rights Reserved.
> + */
> +
> +package com.hp.hpl.jena.sparql.function.user;
> +
> +import java.util.ArrayList;
> +import java.util.List;
> +
> +import com.hp.hpl.jena.sparql.core.Var;
> +import com.hp.hpl.jena.sparql.expr.Expr;
> +import com.hp.hpl.jena.sparql.function.Function;
> +
> +/**
> + * Represents the definition of a user defined function
> + * @author rvesse
> + *
> + */
> +public class UserDefinedFunctionDefinition {
> +
> +    private String uri;
> +    private Expr expr;
> +    private List<Var> argList;
> +
> +    /**
> +     * Creates a user defined function definition
> +     * @param uri Function URL
> +     * @param e Expression
> +     * @param argList Arguments
> +     */
> +    public UserDefinedFunctionDefinition(String uri, Expr e, List<Var> argList) {
> +        this.uri = uri;
> +        this.expr = e;
> +        this.argList = new ArrayList<Var>(argList);
> +    }
> +
> +    /**
> +     * Gets the base expression
> +     * @return Expression
> +     */
> +    public Expr getBaseExpr() {
> +        return this.expr;
> +    }
> +
> +    /**
> +     * Gets the argument list
> +     * @return Arguments
> +     */
> +    public List<Var> getArgList() {
> +        return this.argList;
> +    }
> +
> +    /**
> +     * Gets the function URI
> +     * @return URI
> +     */
> +    public String getUri() {
> +        return this.uri;
> +    }
> +
> +    /**
> +     * Gets an instance of an actual {@link Function} that can be used to evaluate this function
> +     * @return Function instance
> +     */
> +    public Function newFunctionInstance() {
> +        return new UserDefinedFunction(this);
> +    }
> +}
>
> Added: jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionFactory.java
> URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionFactory.java?rev=1411358&view=auto
> ==============================================================================
> --- jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionFactory.java (added)
> +++ jena/trunk/jena-arq/src/main/java/com/hp/hpl/jena/sparql/function/user/UserDefinedFunctionFactory.java Mon Nov 19 19:26:08 2012
> @@ -0,0 +1,149 @@
> +/*
> + * Copyright 2012 YarcData LLC All Rights Reserved.
> + */
> +
> +package com.hp.hpl.jena.sparql.function.user;
> +
> +import java.io.StringReader;
> +import java.util.HashMap;
> +import java.util.List;
> +import java.util.Map;
> +import java.util.NoSuchElementException;
> +
> +import com.hp.hpl.jena.sparql.core.Var;
> +import com.hp.hpl.jena.sparql.expr.Expr;
> +import com.hp.hpl.jena.sparql.function.Function;
> +import com.hp.hpl.jena.sparql.function.FunctionFactory;
> +import com.hp.hpl.jena.sparql.function.FunctionRegistry;
> +import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
> +import com.hp.hpl.jena.sparql.lang.sparql_11.SPARQLParser11;
> +import com.hp.hpl.jena.sparql.sse.builders.ExprBuildException;
> +
> +/**
> + * A function factory for managing user defined functions
> + * <p>
> + * User defined functions provide a simple mechanism for a user to inject custom functions into SPARQL processing
> + * without the need to write any code.  These functions essentially act as aliases for another SPARQL expression
> + * and serve as a means to aid users in simplifying their SPARQL queries.
> + * </p>
> + * <p>
> + * For example we can define a <strong>square</strong> function like so:
> + * </p>
> + * <pre>
> + * List&lt;Var&gt; args = new ArrayList&lt;Var&gt;(Var.alloc("x"));
> + * UserDefinedFunctionFactory.getFactory().add("http://example/square", "?x * ?x", args);
> + * </pre>
> + * <p>
> + * We can then use this in queries like so:
> + * </p>
> + * <pre>
> + * SELECT (&lt;http://example/square&gt;(3) AS ?ThreeSquared) { }
> + * </pre>
> + * <p>
> + * Internally the call to the <strong>square</strong> function is translated into it's equivalent SPARQL expression and executed in that form.
> + * </p>
> + * @author rvesse
> + *
> + */
> +public class UserDefinedFunctionFactory implements FunctionFactory {
> +
> +    private static UserDefinedFunctionFactory factory = new UserDefinedFunctionFactory();
> +
> +    /**
> +     * Gets the static instance of the factory
> +     * @return Function Factory
> +     */
> +    public static UserDefinedFunctionFactory getFactory() {
> +        return factory;
> +    }
> +
> +    private Map<String, UserDefinedFunctionDefinition> definitions = new HashMap<String, UserDefinedFunctionDefinition>();
> +
> +    /**
> +     * Private constructor prevents instantiation
> +     */
> +    private UserDefinedFunctionFactory() { }
> +
> +    /**
> +     * Creates a function for the given URI
> +     * @throws ExprBuildException Thrown if the given URI is not a known function
> +     */
> +    @Override
> +    public Function create(String uri) {
> +        UserDefinedFunctionDefinition def = this.definitions.get(uri);
> +        if (def == null) throw new ExprBuildException("Function <" + uri + "> not known by this function factory");
> +        return def.newFunctionInstance();
> +    }
> +
> +    /**
> +     * Adds a function
> +     * @param uri URI
> +     * @param e Expression
> +     * @param args Arguments
> +     */
> +    public void add(String uri, Expr e, List<Var> args) {
> +        UserDefinedFunctionDefinition def = new UserDefinedFunctionDefinition(uri, e, args);
> +        this.definitions.put(uri, def);
> +        FunctionRegistry.get().put(uri, this);
> +    }
> +
> +    /**
> +     * Adds a function
> +     * <p>
> +     * This method will build the expression to use based on the expression string given, strings must match the SPARQL expression syntax e.g.
> +     * </p>
> +     * <pre>
> +     * (?x * ?y) + 5
> +     * </pre>
> +     * @param uri URI
> +     * @param expr Expression String (in SPARQL syntax)
> +     * @param args Arguments
> +     * @throws ParseException Thrown if the expression string is not valid syntax
> +     */
> +    public void add(String uri, String expr, List<Var> args) throws ParseException {
> +        Expr e = new SPARQLParser11(new StringReader(expr)).Expression();
> +        UserDefinedFunctionDefinition def = new UserDefinedFunctionDefinition(uri, e, args);
> +        this.definitions.put(uri, def);
> +        FunctionRegistry.get().put(uri, this);
> +    }
> +
> +    /**
> +     * Removes a function definition
> +     * @param uri URI
> +     * @throws NoSuchElementException Thrown if a function with the given URI does not exist
> +     */
> +    public void remove(String uri) {
> +        if (!this.definitions.containsKey(uri)) throw new NoSuchElementException("No function definition is associated with the URI <" + uri + ">");
> +        this.definitions.remove(uri);
> +        FunctionRegistry.get().remove(uri);
> +    }
> +
> +    /**
> +     * Gets the definition of the function (if registered)
> +     * @param uri URI
> +     * @return Function Definition if registered, null otherwise
> +     */
> +    public UserDefinedFunctionDefinition get(String uri) {
> +        if (!this.definitions.containsKey(uri)) return null;
> +        return this.definitions.get(uri);
> +    }
> +
> +    /**
> +     * Gets whether a function with the given URI has been registered
> +     * @param uri URI
> +     * @return True if registered, false otherwise
> +     */
> +    public boolean isRegistered(String uri) {
> +        return this.definitions.containsKey(uri);
> +    }
> +
> +    /**
> +     * Clears all function definitions
> +     */
> +    public void clear() {
> +        for (String uri : this.definitions.keySet()) {
> +            FunctionRegistry.get().remove(uri);
> +        }
> +        this.definitions.clear();
> +    }
> +}
>
> Added: jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS_UserFunctions.java
> URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS_UserFunctions.java?rev=1411358&view=auto
> ==============================================================================
> --- jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS_UserFunctions.java (added)
> +++ jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TS_UserFunctions.java Mon Nov 19 19:26:08 2012
> @@ -0,0 +1,27 @@
> +/*
> + * Copyright 2012 YarcData LLC All Rights Reserved.
> + */
> +
> +package com.hp.hpl.jena.sparql.function.user;
> +
> +import junit.framework.JUnit4TestAdapter;
> +
> +import org.junit.BeforeClass;
> +import org.junit.runner.RunWith;
> +import org.junit.runners.Suite;
> +import org.junit.runners.Suite.SuiteClasses;
> +
> +import com.hp.hpl.jena.sparql.expr.TS_Expr;
> +
> +@RunWith(Suite.class)
> +@SuiteClasses( {
> +    TestUserDefinedFunctionFactory.class,
> +    TestFunctionExpansion.class,
> +    TestUserFunctionsInSparql.class
> +})
> +public class TS_UserFunctions {
> +
> +    public static junit.framework.Test suite() {
> +        return new JUnit4TestAdapter(TS_Expr.class);
> +      }
> +}
>
> Added: jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestFunctionExpansion.java
> URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestFunctionExpansion.java?rev=1411358&view=auto
> ==============================================================================
> --- jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestFunctionExpansion.java (added)
> +++ jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestFunctionExpansion.java Mon Nov 19 19:26:08 2012
> @@ -0,0 +1,87 @@
> +/*
> + * Copyright 2012 YarcData LLC All Rights Reserved.
> + */
> +
> +package com.hp.hpl.jena.sparql.function.user;
> +
> +import java.util.ArrayList;
> +import java.util.List;
> +
> +import org.junit.AfterClass;
> +import org.junit.Assert;
> +import org.junit.BeforeClass;
> +import org.junit.Test;
> +
> +import com.hp.hpl.jena.sparql.core.Var;
> +import com.hp.hpl.jena.sparql.expr.E_Multiply;
> +import com.hp.hpl.jena.sparql.expr.Expr;
> +import com.hp.hpl.jena.sparql.expr.ExprList;
> +import com.hp.hpl.jena.sparql.expr.ExprVar;
> +import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueBoolean;
> +import com.hp.hpl.jena.sparql.expr.nodevalue.NodeValueInteger;
> +
> +/**
> + * Test for checking that functions are appropriately expanded when supplied with actual arguments
> + * @author rvesse
> + *
> + */
> +public class TestFunctionExpansion {
> +
> +    @BeforeClass
> +    public static void setup() {
> +        UserDefinedFunctionFactory.getFactory().clear();
> +    }
> +
> +    @AfterClass
> +    public static void teardown() {
> +        UserDefinedFunctionFactory.getFactory().clear();
> +    }
> +
> +    @Test
> +    public void test_function_expansion_01() {
> +        Expr e = new ExprVar("x");
> +        UserDefinedFunctionFactory.getFactory().add("http://example/simple", e, new ArrayList<Var>(e.getVarsMentioned()));
> +
> +        UserDefinedFunction f = (UserDefinedFunction) UserDefinedFunctionFactory.getFactory().create("http://example/simple");
> +        f.build("http://example/simple", new ExprList(new NodeValueBoolean(true)));
> +
> +        Expr actual = f.getActualExpr();
> +        Assert.assertFalse(e.equals(actual));
> +        Assert.assertEquals(0, actual.getVarsMentioned().size());
> +        Assert.assertEquals(new NodeValueBoolean(true), actual);
> +    }
> +
> +    @Test
> +    public void test_function_expansion_02() {
> +        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
> +        UserDefinedFunctionFactory.getFactory().add("http://example/square", e, new ArrayList<Var>(e.getVarsMentioned()));
> +
> +        UserDefinedFunction f = (UserDefinedFunction) UserDefinedFunctionFactory.getFactory().create("http://example/square");
> +        f.build("http://example/square", new ExprList(new NodeValueInteger(3)));
> +
> +        Expr actual = f.getActualExpr();
> +        Assert.assertFalse(e.equals(actual));
> +        Assert.assertEquals(0, actual.getVarsMentioned().size());
> +        Assert.assertEquals(new E_Multiply(new NodeValueInteger(3), new NodeValueInteger(3)), actual);
> +    }
> +
> +    @Test
> +    public void test_function_expansion_03() {
> +        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("y"));
> +        List<Var> defArgs = new ArrayList<Var>();
> +        defArgs.add(Var.alloc("x"));
> +        defArgs.add(Var.alloc("y"));
> +        UserDefinedFunctionFactory.getFactory().add("http://example/square", e, defArgs);
> +
> +        UserDefinedFunction f = (UserDefinedFunction) UserDefinedFunctionFactory.getFactory().create("http://example/square");
> +        ExprList args = new ExprList();
> +        args.add(new NodeValueInteger(3));
> +        args.add(new NodeValueInteger(4));
> +        f.build("http://example/square", args);
> +
> +        Expr actual = f.getActualExpr();
> +        Assert.assertFalse(e.equals(actual));
> +        Assert.assertEquals(0, actual.getVarsMentioned().size());
> +        Assert.assertEquals(new E_Multiply(new NodeValueInteger(3), new NodeValueInteger(4)), actual);
> +    }
> +}
>
> Added: jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserDefinedFunctionFactory.java
> URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserDefinedFunctionFactory.java?rev=1411358&view=auto
> ==============================================================================
> --- jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserDefinedFunctionFactory.java (added)
> +++ jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserDefinedFunctionFactory.java Mon Nov 19 19:26:08 2012
> @@ -0,0 +1,76 @@
> +/*
> + * Copyright 2012 YarcData LLC All Rights Reserved.
> + */
> +
> +package com.hp.hpl.jena.sparql.function.user;
> +
> +import java.util.ArrayList;
> +
> +import junit.framework.Assert;
> +
> +import org.junit.AfterClass;
> +import org.junit.BeforeClass;
> +import org.junit.Test;
> +
> +import com.hp.hpl.jena.sparql.core.Var;
> +import com.hp.hpl.jena.sparql.expr.E_Multiply;
> +import com.hp.hpl.jena.sparql.expr.Expr;
> +import com.hp.hpl.jena.sparql.expr.ExprVar;
> +import com.hp.hpl.jena.sparql.lang.sparql_11.ParseException;
> +
> +/**
> + * Tests for the {@link UserDefinedFunctionFactory}
> + * @author rvesse
> + *
> + */
> +public class TestUserDefinedFunctionFactory {
> +
> +    @BeforeClass
> +    public static void setup() {
> +        UserDefinedFunctionFactory.getFactory().clear();
> +    }
> +
> +    @AfterClass
> +    public static void teardown() {
> +        UserDefinedFunctionFactory.getFactory().clear();
> +    }
> +
> +    @Test
> +    public void test_user_defined_function_factory_instance() {
> +        UserDefinedFunctionFactory factory = UserDefinedFunctionFactory.getFactory();
> +        Assert.assertNotNull(factory);
> +    }
> +
> +    @Test
> +    public void test_user_defined_function_factory_add_01() {
> +        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
> +        UserDefinedFunctionFactory.getFactory().add("http://example/square", e, new ArrayList<Var>(e.getVarsMentioned()));
> +        Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("http://example/square"));
> +        Assert.assertEquals(e, UserDefinedFunctionFactory.getFactory().get("http://example/square").getBaseExpr());
> +    }
> +
> +    @Test
> +    public void test_user_defined_function_factory_add_02() {
> +        Expr e1 = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
> +        Expr e2 = new E_Multiply(new ExprVar("y"), new ExprVar("y"));
> +
> +        UserDefinedFunctionFactory.getFactory().add("http://example/square", e1, new ArrayList<Var>(e1.getVarsMentioned()));
> +        Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("http://example/square"));
> +        Assert.assertEquals(e1, UserDefinedFunctionFactory.getFactory().get("http://example/square").getBaseExpr());
> +
> +        UserDefinedFunctionFactory.getFactory().add("http://example/square", e2, new ArrayList<Var>(e2.getVarsMentioned()));
> +        Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("http://example/square"));
> +        Assert.assertEquals(e2, UserDefinedFunctionFactory.getFactory().get("http://example/square").getBaseExpr());
> +    }
> +
> +    @Test
> +    public void test_user_defined_function_factory_add_03() throws ParseException {
> +        Expr e = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
> +
> +        //Instead of registering the pre-built expression register using a string for the expression
> +        UserDefinedFunctionFactory.getFactory().add("http://example/square", "?x * ?x", new ArrayList<Var>(e.getVarsMentioned()));
> +
> +        Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("http://example/square"));
> +        Assert.assertEquals(e, UserDefinedFunctionFactory.getFactory().get("http://example/square").getBaseExpr());
> +    }
> +}
>
> Added: jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserFunctionsInSparql.java
> URL: http://svn.apache.org/viewvc/jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserFunctionsInSparql.java?rev=1411358&view=auto
> ==============================================================================
> --- jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserFunctionsInSparql.java (added)
> +++ jena/trunk/jena-arq/src/test/java/com/hp/hpl/jena/sparql/function/user/TestUserFunctionsInSparql.java Mon Nov 19 19:26:08 2012
> @@ -0,0 +1,68 @@
> +/*
> + * Copyright 2012 YarcData LLC All Rights Reserved.
> + */
> +
> +package com.hp.hpl.jena.sparql.function.user;
> +
> +import java.util.ArrayList;
> +
> +import junit.framework.Assert;
> +
> +import org.junit.AfterClass;
> +import org.junit.BeforeClass;
> +import org.junit.Test;
> +
> +import com.hp.hpl.jena.graph.Node;
> +import com.hp.hpl.jena.query.Query;
> +import com.hp.hpl.jena.query.QueryExecution;
> +import com.hp.hpl.jena.query.QueryExecutionFactory;
> +import com.hp.hpl.jena.query.QueryFactory;
> +import com.hp.hpl.jena.query.ResultSet;
> +import com.hp.hpl.jena.rdf.model.ModelFactory;
> +import com.hp.hpl.jena.sparql.core.Var;
> +import com.hp.hpl.jena.sparql.engine.binding.Binding;
> +import com.hp.hpl.jena.sparql.expr.E_Multiply;
> +import com.hp.hpl.jena.sparql.expr.Expr;
> +import com.hp.hpl.jena.sparql.expr.ExprVar;
> +import com.hp.hpl.jena.sparql.util.NodeFactory;
> +
> +/**
> + * Tests that user functions are properly wired in and usable from SPARQL
> + * @author rvesse
> + *
> + */
> +public class TestUserFunctionsInSparql {
> +
> +    @BeforeClass
> +    public static void setup() {
> +        UserDefinedFunctionFactory.getFactory().clear();
> +
> +        //Define a square function
> +        Expr square = new E_Multiply(new ExprVar("x"), new ExprVar("x"));
> +        UserDefinedFunctionFactory.getFactory().add("http://example/square", square, new ArrayList<Var>(square.getVarsMentioned()));
> +    }
> +
> +    @AfterClass
> +    public static void teardown() {
> +        UserDefinedFunctionFactory.getFactory().clear();
> +    }
> +
> +    @Test
> +    public void test_user_functions_in_sparql() {
> +        Assert.assertTrue(UserDefinedFunctionFactory.getFactory().isRegistered("http://example/square"));
> +
> +        String query = "SELECT (<http://example/square>(2) AS ?square) { }";
> +        Query q = QueryFactory.create(query);
> +
> +        QueryExecution qe = QueryExecutionFactory.create(q, ModelFactory.createDefaultModel());
> +        ResultSet rset = qe.execSelect();
> +        Assert.assertTrue(rset.hasNext());
> +        Binding b = rset.nextBinding();
> +        Assert.assertFalse(rset.hasNext());
> +        qe.close();
> +
> +        //Validate returned value
> +        Node actual = b.get(Var.alloc("square"));
> +        Assert.assertEquals(NodeFactory.intToNode(4), actual);
> +    }
> +}
>
>