You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2017/08/19 17:00:40 UTC
[2/5] jena git commit: JENA-1372: fn:apply and fn:collation-key
JENA-1372: fn:apply and fn:collation-key
Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/919a8215
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/919a8215
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/919a8215
Branch: refs/heads/master
Commit: 919a8215174d1820565144c230e8fbc1d7f77cf1
Parents: 1be131e
Author: Andy Seaborne <an...@apache.org>
Authored: Thu Aug 17 21:08:54 2017 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Thu Aug 17 21:21:51 2017 +0100
----------------------------------------------------------------------
.../jena/sparql/function/FunctionBase.java | 22 ++++-
.../jena/sparql/function/StandardFunctions.java | 5 +
.../jena/sparql/function/library/FN_Apply.java | 96 ++++++++++++++++++++
.../function/library/FN_CollationKey.java | 52 +++++++++++
.../java/org/apache/jena/sparql/TC_General.java | 2 +
.../apache/jena/sparql/expr/TestFunctions2.java | 1 -
.../jena/sparql/function/library/LibTest.java | 49 ++++++++++
.../function/library/TS_LibraryFunctions.java | 31 +++++++
.../function/library/TestFnFunctions.java | 64 +++++++++++++
.../function/library/TestFunctionCollation.java | 18 +---
10 files changed, 320 insertions(+), 20 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jena/blob/919a8215/jena-arq/src/main/java/org/apache/jena/sparql/function/FunctionBase.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/function/FunctionBase.java b/jena-arq/src/main/java/org/apache/jena/sparql/function/FunctionBase.java
index c55a988..53177ff 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/function/FunctionBase.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/function/FunctionBase.java
@@ -27,7 +27,7 @@ import org.apache.jena.sparql.expr.Expr ;
import org.apache.jena.sparql.expr.ExprList ;
import org.apache.jena.sparql.expr.NodeValue ;
-/** Impleemntation root for custom function evaluation. */
+/** Implementation root for custom function evaluation. */
public abstract class FunctionBase implements Function {
@Override
@@ -36,6 +36,13 @@ public abstract class FunctionBase implements Function {
checkBuild(uri, args) ;
}
+ // Valid during execution.
+ // Only specialised uses need these values
+ // e.g. fn:apply which is a meta-function - it looks up a URI to get a function to call.
+ protected FunctionEnv functionEnv = null;
+ // Not needed so hide but keep for debugging.
+ private Binding binding = null;
+
@Override
public NodeValue exec(Binding binding, ExprList args, String uri, FunctionEnv env) {
if ( args == null )
@@ -49,8 +56,17 @@ public abstract class FunctionBase implements Function {
evalArgs.add( x );
}
- NodeValue nv = exec(evalArgs) ;
- return nv ;
+ // Cature
+ try {
+ this.functionEnv = env ;
+ this.binding = binding;
+ NodeValue nv = exec(evalArgs) ;
+ return nv ;
+ } finally {
+ this.functionEnv = null ;
+ this.binding = null;
+ }
+
}
/** Function call to a list of evaluated argument values */
http://git-wip-us.apache.org/repos/asf/jena/blob/919a8215/jena-arq/src/main/java/org/apache/jena/sparql/function/StandardFunctions.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/function/StandardFunctions.java b/jena-arq/src/main/java/org/apache/jena/sparql/function/StandardFunctions.java
index 145b1b0..e5d4337 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/function/StandardFunctions.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/function/StandardFunctions.java
@@ -232,6 +232,11 @@ public class StandardFunctions
add(registry, math+"atan2", Math_atan2.class) ;
+ // F&O 3.1
+ add(registry, xfn+"apply", FN_Apply.class);
+ add(registry, xfn+"collation-key", FN_CollationKey.class);
+
+
// And add op:'s
// 4.2.1 op:numeric-add
// 4.2.2 op:numeric-subtract
http://git-wip-us.apache.org/repos/asf/jena/blob/919a8215/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_Apply.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_Apply.java b/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_Apply.java
new file mode 100644
index 0000000..4f766fa
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_Apply.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.function.library;
+
+import java.util.List ;
+
+import org.apache.jena.atlas.lib.Cache ;
+import org.apache.jena.atlas.lib.CacheFactory ;
+import org.apache.jena.graph.Node ;
+import org.apache.jena.sparql.expr.ExprEvalException ;
+import org.apache.jena.sparql.expr.ExprList ;
+import org.apache.jena.sparql.expr.NodeValue ;
+import org.apache.jena.sparql.function.Function ;
+import org.apache.jena.sparql.function.FunctionBase ;
+import org.apache.jena.sparql.function.FunctionFactory ;
+import org.apache.jena.sparql.function.FunctionRegistry ;
+import org.apache.jena.sparql.sse.builders.ExprBuildException ;
+import org.apache.jena.sparql.util.Context ;
+
+/** XPath and XQuery Functions and Operators 3.1
+ * <p>
+ * {@code fn:apply(function, args)}
+ */
+public class FN_Apply extends FunctionBase {
+ // Assumes one object per use site.
+ private Cache<String, Function> cache1 = CacheFactory.createOneSlotCache();
+
+ @Override
+ public void checkBuild(String uri, ExprList args) {
+ if ( args.isEmpty() )
+ throw new ExprBuildException("fn:apply: no function to call (minimum number of args is one)");
+ }
+ @Override
+ public NodeValue exec(List<NodeValue> args) {
+ if ( args.isEmpty() )
+ throw new ExprBuildException("fn:apply: no function to call (minimum number of args is one)");
+ NodeValue functionId = args.get(0);
+ List<NodeValue> argExprs = args.subList(1,args.size()) ;
+ ExprList exprs = new ExprList();
+ argExprs.forEach((a)->exprs.add(a));
+ Node fnNode = functionId.asNode();
+
+ if ( fnNode.isBlank() )
+ throw new ExprBuildException("fn:apply: function id is a blank node (must be a URI)");
+ if ( fnNode.isLiteral() )
+ throw new ExprBuildException("fn:apply: function id is a literal (must be a URI)");
+ if ( fnNode.isVariable() )
+ // Should not happen ... but ...
+ throw new ExprBuildException("fn:apply: function id is an unbound variable (must be a URI)");
+ if ( fnNode.isURI() ) {
+ String functionIRI = fnNode.getURI();
+ Function function = cache1.getOrFill(functionIRI, ()->buildFunction(functionIRI));
+ if ( function instanceof FunctionBase ) {
+ // Fast track.
+ return ((FunctionBase)function).exec(argExprs);
+ }
+ function.build(functionIRI, exprs);
+ // Eval'ed arguments.
+ return function.exec(null, exprs, functionIRI, null);
+ }
+
+ throw new ExprEvalException("fn:apply: Weird function argument (arg 1): "+functionId);
+ }
+
+ private Function buildFunction(String functionIRI) {
+ FunctionRegistry registry = chooseRegistry(functionEnv.getContext()) ;
+ FunctionFactory ff = registry.get(functionIRI) ;
+ if ( ff == null )
+ return null;
+ return ff.create(functionIRI) ;
+ }
+
+ private FunctionRegistry chooseRegistry(Context context) {
+ FunctionRegistry registry = FunctionRegistry.get(context) ;
+ if ( registry == null )
+ registry = FunctionRegistry.get() ;
+ return registry ;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/919a8215/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_CollationKey.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_CollationKey.java b/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_CollationKey.java
new file mode 100644
index 0000000..6f98f25
--- /dev/null
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/function/library/FN_CollationKey.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.function.library;
+
+import java.nio.charset.StandardCharsets ;
+import java.util.Base64 ;
+import java.util.Locale ;
+
+import org.apache.jena.datatypes.xsd.XSDDatatype ;
+import org.apache.jena.sparql.expr.NodeValue ;
+import org.apache.jena.sparql.function.FunctionBase2 ;
+
+/** XPath and XQuery Functions and Operators 3.1
+ * <p>
+ * {@code fn:collation-key($key as xs:string, $collation as xs:string) as xs:base64Binary}
+ */
+public class FN_CollationKey extends FunctionBase2 {
+
+ // The function2 variant
+ // Function1 is default collation -> codepoint.
+
+ @Override
+ public NodeValue exec(NodeValue v1, NodeValue v2) {
+ //fn:collation-key($key as xs:string, $collation as xs:string) as xs:base64Binary
+ if ( ! v1.isString() ) {}
+ if ( ! v2.isString() ) {}
+ String collation = v2 == null ? "" : v2.getString().toLowerCase(Locale.ROOT);
+
+ // The irony of using the lexical form of old rdf:plainLiteral (RDF 1.1 does not
+ // need rdf:plainLiteral and rdf:plainLiteral should never appear in RDF)
+ String x = v1.getString()+"@"+v2.getString();
+ byte[] b = x.getBytes(StandardCharsets.UTF_8);
+ String s = Base64.getMimeEncoder().encodeToString(b);
+ return NodeValue.makeNode(s, XSDDatatype.XSDbase64Binary);
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/919a8215/jena-arq/src/test/java/org/apache/jena/sparql/TC_General.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/TC_General.java b/jena-arq/src/test/java/org/apache/jena/sparql/TC_General.java
index e8d46ea..e4542bc 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/TC_General.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/TC_General.java
@@ -31,6 +31,7 @@ import org.apache.jena.sparql.engine.join.TS_Join ;
import org.apache.jena.sparql.expr.E_Function ;
import org.apache.jena.sparql.expr.NodeValue ;
import org.apache.jena.sparql.expr.TS_Expr ;
+import org.apache.jena.sparql.function.library.TS_LibraryFunctions ;
import org.apache.jena.sparql.function.user.TS_UserFunctions ;
import org.apache.jena.sparql.graph.TS_Graph ;
import org.apache.jena.sparql.lang.TS_Lang ;
@@ -57,6 +58,7 @@ import org.junit.runners.Suite ;
, TS_Util.class
, TS_Expr.class
+ , TS_LibraryFunctions.class
, TS_UserFunctions.class
, TS_PFunction.class
http://git-wip-us.apache.org/repos/asf/jena/blob/919a8215/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions2.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions2.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions2.java
index bd937d5..bc5985a 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions2.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestFunctions2.java
@@ -34,7 +34,6 @@ import org.junit.Test ;
public class TestFunctions2 extends BaseTest
{
- // 3->2
// Some overlap with TestFunctions except those are direct function calls and these are via SPARQL 1.1 syntax.
// Better too many tests than too few.
http://git-wip-us.apache.org/repos/asf/jena/blob/919a8215/jena-arq/src/test/java/org/apache/jena/sparql/function/library/LibTest.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/function/library/LibTest.java b/jena-arq/src/test/java/org/apache/jena/sparql/function/library/LibTest.java
new file mode 100644
index 0000000..cfff012
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/function/library/LibTest.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.function.library;
+
+import static org.junit.Assert.assertEquals ;
+import static org.junit.Assert.assertTrue ;
+
+import org.apache.jena.graph.Node ;
+import org.apache.jena.shared.PrefixMapping ;
+import org.apache.jena.sparql.ARQConstants ;
+import org.apache.jena.sparql.expr.Expr ;
+import org.apache.jena.sparql.expr.NodeValue ;
+import org.apache.jena.sparql.function.FunctionEnvBase ;
+import org.apache.jena.sparql.util.ExprUtils ;
+import org.apache.jena.sparql.util.NodeFactoryExtra ;
+
+public class LibTest {
+ private static PrefixMapping pmap = ARQConstants.getGlobalPrefixMap() ;
+
+ static void test(String string) {
+ test(string, "true");
+ }
+
+ static void test(String string, String result) {
+ Expr expr = ExprUtils.parse(string, pmap) ;
+ NodeValue nv = expr.eval(null, new FunctionEnvBase()) ;
+ Node r = NodeFactoryExtra.parseNode(result) ;
+ NodeValue nvr = NodeValue.makeNode(r) ;
+ assertTrue("Not same value: Expected: " + nvr + " : Actual = " + nv, NodeValue.sameAs(nvr, nv)) ;
+ // test result must be lexical form exact.
+ assertEquals(r, nv.asNode()) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/919a8215/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TS_LibraryFunctions.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TS_LibraryFunctions.java b/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TS_LibraryFunctions.java
new file mode 100644
index 0000000..132b313
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TS_LibraryFunctions.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.function.library;
+
+import org.junit.runner.RunWith ;
+import org.junit.runners.Suite ;
+import org.junit.runners.Suite.SuiteClasses ;
+
+@RunWith(Suite.class)
+@SuiteClasses( {
+ // A lot of the test ate in TestFunctions and TestFunctions2.
+ TestFunctionCollation.class
+ , TestFnFunctions.class
+})
+public class TS_LibraryFunctions {}
http://git-wip-us.apache.org/repos/asf/jena/blob/919a8215/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TestFnFunctions.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TestFnFunctions.java b/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TestFnFunctions.java
new file mode 100644
index 0000000..493f501
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TestFnFunctions.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.function.library;
+
+import static org.apache.jena.sparql.function.library.LibTest.test;
+
+import org.apache.jena.sparql.expr.ExprEvalException ;
+import org.apache.jena.sparql.expr.VariableNotBoundException ;
+import org.apache.jena.sparql.sse.builders.ExprBuildException ;
+import org.apache.jena.system.JenaSystem ;
+import org.junit.Test ;
+
+public class TestFnFunctions {
+
+ static { JenaSystem.init(); }
+
+ @Test public void apply_1() {
+ test("fn:apply(math:sqrt, 9)", "3.0e0");
+ }
+
+ // Under arity
+ @Test(expected=ExprEvalException.class)
+ public void apply_2() {
+ test("fn:apply(math:sqrt)", "3.0e0");
+ }
+
+ // Over arity
+ @Test(expected=ExprEvalException.class)
+ public void apply_3() {
+ test("fn:apply(math:sqrt, 9, 10)", "3.0e0");
+ }
+
+ // Not a URI.
+ @Test(expected=ExprBuildException.class)
+ public void apply_4() {
+ test("fn:apply('bicycle', 9, 10)", "3.0e0");
+ }
+
+ @Test(expected=VariableNotBoundException.class)
+ public void apply_5() {
+ test("fn:apply(?var)", "3.0e0");
+ }
+
+ @Test
+ public void collationKey_1() {
+ test("fn:collation-key('foo', 'en') = 'Zm9vQGVu'^^xsd:base64Binary");
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/919a8215/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TestFunctionCollation.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TestFunctionCollation.java b/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TestFunctionCollation.java
index 7d69cd2..208d7fc 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TestFunctionCollation.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/function/library/TestFunctionCollation.java
@@ -20,28 +20,19 @@ package org.apache.jena.sparql.function.library;
import static org.junit.Assert.assertArrayEquals;
-import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import org.apache.jena.sparql.expr.NodeValue;
-import org.junit.Before;
import org.junit.Test;
/**
* Tests for {@link FN_Collation}.
*/
public class TestFunctionCollation {
-
- private FN_Collation function = null;
-
- @Before
- public void setUp() {
- function = new FN_Collation();
- }
-
@Test
public void testFunctionCollationExec() {
+ FN_Collation function = new FN_Collation();
NodeValue collation = NodeValue.makeString("fi");
final String[] unordered = new String[]
@@ -54,12 +45,7 @@ public class TestFunctionCollation {
for (String string : unordered) {
nodeValues.add(function.exec(collation, NodeValue.makeString(string)));
}
- nodeValues.sort(new Comparator<NodeValue>() {
- @Override
- public int compare(NodeValue o1, NodeValue o2) {
- return NodeValue.compare(o1, o2);
- }
- });
+ nodeValues.sort((NodeValue o1, NodeValue o2) -> NodeValue.compare(o1, o2) );
List<String> result = new LinkedList<>();
for (NodeValue nv : nodeValues) {
String s = nv.toString();