jena-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ki...@apache.org
Subject [1/5] jena git commit: JENA-632: Generate JSON from SPARQL directly
Date Fri, 27 Apr 2018 11:08:12 GMT
Repository: jena
Updated Branches:
  refs/heads/master e5cbf13e3 -> 4bf5e3c0a


http://git-wip-us.apache.org/repos/asf/jena/blob/4bf5e3c0/jena-arq/src/main/java/org/apache/jena/sparql/lib/RDFTerm2Json.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/lib/RDFTerm2Json.java b/jena-arq/src/main/java/org/apache/jena/sparql/lib/RDFTerm2Json.java
index 5f0184c..bcf1fd1 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/lib/RDFTerm2Json.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/lib/RDFTerm2Json.java
@@ -64,7 +64,7 @@ public class RDFTerm2Json {
             return new JsonString(node.getURI());
         if ( node.isBlank() ) {
             Node node2 = RiotLib.blankNodeToIri(node);
-            return new JsonString(node.getURI());
+            return new JsonString(node2.getURI());
         }
         if ( node.isVariable() ) 
             return new JsonString("?"+node.getName());

http://git-wip-us.apache.org/repos/asf/jena/blob/4bf5e3c0/jena-arq/src/main/java/org/apache/jena/sparql/resultset/SPARQLResult.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/resultset/SPARQLResult.java b/jena-arq/src/main/java/org/apache/jena/sparql/resultset/SPARQLResult.java
index 77c7ae2..2633d8d 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/resultset/SPARQLResult.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/resultset/SPARQLResult.java
@@ -18,6 +18,9 @@
 
 package org.apache.jena.sparql.resultset;
 
+import java.util.Iterator;
+
+import org.apache.jena.atlas.json.JsonObject;
 import org.apache.jena.query.Dataset;
 import org.apache.jena.query.ResultSet;
 import org.apache.jena.rdf.model.Model;
@@ -34,6 +37,7 @@ public class SPARQLResult {
     private Boolean   booleanResult = null;
     private Model     model         = null;
     private Dataset   dataset       = null;
+    private Iterator<JsonObject> jsonItems = null;
 
     // Delayed choice of result type.
     protected SPARQLResult() {}
@@ -54,6 +58,10 @@ public class SPARQLResult {
         set(dataset);
     }
 
+    public SPARQLResult(Iterator<JsonObject> jsonItems) {
+        set(jsonItems); 
+    }
+
     public boolean isResultSet() {
         if ( !hasBeenSet )
             throw new ResultSetException("Not set");
@@ -83,6 +91,13 @@ public class SPARQLResult {
         return booleanResult != null;
     }
 
+    public boolean isJson()
+    {
+        if ( !hasBeenSet )
+            throw new ResultSetException("Not set");
+        return jsonItems != null;
+    }
+
     public ResultSet getResultSet() {
         if ( !hasBeenSet )
             throw new ResultSetException("Not set");
@@ -115,6 +130,15 @@ public class SPARQLResult {
         return dataset;
     }
 
+    public Iterator<JsonObject> getJsonItems()
+    {
+        if ( !hasBeenSet )
+            throw new ResultSetException("Not set");
+        if ( !isJson() )
+            throw new ResultSetException("Not a JSON result");
+        return jsonItems;
+    }
+
     public boolean isHasBeenSet() {
         return hasBeenSet;
     }
@@ -142,4 +166,10 @@ public class SPARQLResult {
         booleanResult = r;
         hasBeenSet = true;
     }
+
+    protected void set(Iterator<JsonObject> jsonItems) {
+        this.jsonItems = jsonItems; 
+        hasBeenSet = true;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/jena/blob/4bf5e3c0/jena-arq/src/main/java/org/apache/jena/sparql/serializer/QuerySerializer.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/serializer/QuerySerializer.java
b/jena-arq/src/main/java/org/apache/jena/sparql/serializer/QuerySerializer.java
index e77e5e3..4429b82 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/serializer/QuerySerializer.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/serializer/QuerySerializer.java
@@ -20,6 +20,7 @@ package org.apache.jena.sparql.serializer;
 
 import java.io.OutputStream ;
 import java.util.List ;
+import java.util.Map;
 
 import org.apache.jena.atlas.io.IndentedWriter ;
 import org.apache.jena.graph.Node ;
@@ -45,6 +46,7 @@ public class QuerySerializer implements QueryVisitor
     protected FormatterElement fmtElement ;
     protected FmtExprSPARQL fmtExpr ;
     protected IndentedWriter out = null ;
+    protected Prologue prologue = null ;
 
     QuerySerializer(OutputStream        _out,
                     FormatterElement    formatterElement, 
@@ -75,6 +77,7 @@ public class QuerySerializer implements QueryVisitor
     @Override
     public void visitPrologue(Prologue prologue)
     { 
+        this.prologue = prologue ;
         int row1 = out.getRow() ;
         PrologueSerializer.output(out, prologue) ;
         int row2 = out.getRow() ;
@@ -142,7 +145,30 @@ public class QuerySerializer implements QueryVisitor
         out.print("ASK") ;
         out.newline() ;
     }
-    
+
+    @Override
+    public void visitJsonResultForm(Query query) {
+        out.println("JSON {");
+        out.incIndent(BLOCK_INDENT);
+        out.incIndent(BLOCK_INDENT);
+        boolean first = true;
+        for (Map.Entry<String, Node> entry : query.getJsonMapping().entrySet()) {
+            String field = entry.getKey();
+            Node value = entry.getValue();
+            if ( ! first )
+                out.println(" ,");
+            first = false;
+            out.print('"'); out.print(field); out.print('"');
+            out.print(" : ");
+            out.pad(15);
+            out.print(FmtUtils.stringForNode(value, prologue));
+        }
+        out.decIndent(BLOCK_INDENT);
+        out.decIndent(BLOCK_INDENT);
+        out.print(" }");
+        out.newline();
+    }
+
     @Override
     public void visitDatasetDecl(Query query)
     {

http://git-wip-us.apache.org/repos/asf/jena/blob/4bf5e3c0/jena-arq/src/main/java/org/apache/jena/sparql/syntax/syntaxtransform/QueryTransformOps.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/syntax/syntaxtransform/QueryTransformOps.java
b/jena-arq/src/main/java/org/apache/jena/sparql/syntax/syntaxtransform/QueryTransformOps.java
index 8c7b712..c7d05b4 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/syntax/syntaxtransform/QueryTransformOps.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/syntax/syntaxtransform/QueryTransformOps.java
@@ -218,6 +218,11 @@ public class QueryTransformOps {
         }
 
         @Override
+        public void visitJsonResultForm(Query query) {
+            newQuery.setQueryJsonType();
+        }
+
+        @Override
         public void visitDatasetDecl(Query query) {
         }
 

http://git-wip-us.apache.org/repos/asf/jena/blob/4bf5e3c0/jena-arq/src/test/java/org/apache/jena/query/TS_ResultSetFormatter.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/query/TS_ResultSetFormatter.java b/jena-arq/src/test/java/org/apache/jena/query/TS_ResultSetFormatter.java
new file mode 100644
index 0000000..44947fb
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/query/TS_ResultSetFormatter.java
@@ -0,0 +1,30 @@
+/**
+ * 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.query;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses( {
+    TestResultSetFormatter.class
+})
+public class TS_ResultSetFormatter {
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/4bf5e3c0/jena-arq/src/test/java/org/apache/jena/query/TestResultSetFormatter.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/query/TestResultSetFormatter.java b/jena-arq/src/test/java/org/apache/jena/query/TestResultSetFormatter.java
new file mode 100644
index 0000000..0d9519a
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/query/TestResultSetFormatter.java
@@ -0,0 +1,84 @@
+/**
+ * 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.query;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.jena.datatypes.xsd.XSDDatatype;
+import org.apache.jena.rdf.model.AnonId;
+import org.apache.jena.rdf.model.Model;
+import org.apache.jena.rdf.model.ModelFactory;
+import org.apache.jena.rdf.model.Property;
+import org.apache.jena.rdf.model.RDFNode;
+import org.apache.jena.rdf.model.Resource;
+import org.apache.jena.rdf.model.ResourceFactory;
+import org.apache.jena.sparql.engine.JsonIterator;
+import org.junit.Test;
+
+/**
+ * Tests for the {@link ResultSetFormatter}.
+ */
+public class TestResultSetFormatter {
+
+    @Test
+    public void testIterator() throws IOException {
+        Model model = ModelFactory.createDefaultModel();
+        {
+            Resource r = model.createResource(AnonId.create("first"));
+            Property p = model.getProperty("");
+            RDFNode node = ResourceFactory.createTypedLiteral("123", XSDDatatype.XSDdecimal);
+            model.add(r, p, node);
+            r = model.createResource(AnonId.create("second"));
+            p = model.getProperty("");
+            node = ResourceFactory.createTypedLiteral("abc", XSDDatatype.XSDstring);
+            model.add(r, p, node);
+            r = model.createResource(AnonId.create("third"));
+            p = model.getProperty("");
+            node = ResourceFactory.createLangLiteral("def", "en");
+            model.add(r, p, node);
+            r = model.createResource(AnonId.create("fourth"));
+            p = model.getProperty("");
+            node = ResourceFactory.createTypedLiteral("true", XSDDatatype.XSDboolean);
+            model.add(r, p, node);
+        }
+        Query query = QueryFactory.create("JSON { \"s\": ?s , \"p\": ?p , \"o\" : ?o } "
+                + "WHERE { ?s ?p ?o }", Syntax.syntaxARQ);
+        try ( QueryExecution qexec = QueryExecutionFactory.create(query, model) ) {
+            JsonIterator execJsonItems = (JsonIterator) qexec.execJsonItems();
+            try (final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+                ResultSetFormatter.output(baos, execJsonItems);
+                String output = baos.toString(Charset.forName("UTF-8"));
+                assertTrue(output.contains("\"_:first\""));
+                assertTrue(output.contains("\"_:second\""));
+                assertTrue(output.contains("\"_:third\""));
+                assertTrue(output.contains("\"_:fourth\""));
+                assertFalse(output.contains("\"true\""));
+                assertTrue(output.contains("true"));
+                assertTrue(output.contains("123"));
+                assertFalse(output.contains("\"123\""));
+                assertTrue(output.contains("\"abc\""));
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/4bf5e3c0/jena-arq/src/test/java/org/apache/jena/sparql/api/TestAPI.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/api/TestAPI.java b/jena-arq/src/test/java/org/apache/jena/sparql/api/TestAPI.java
index 74c27a8..7942a5e 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/api/TestAPI.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/api/TestAPI.java
@@ -22,12 +22,35 @@ import java.util.Iterator;
 import java.util.Set ;
 
 import org.apache.jena.atlas.iterator.Iter ;
+import org.apache.jena.atlas.json.JsonArray;
+import org.apache.jena.atlas.json.JsonObject;
 import org.apache.jena.atlas.junit.BaseTest;
+import org.apache.jena.datatypes.xsd.XSDDatatype;
 import org.apache.jena.graph.Graph ;
 import org.apache.jena.graph.Node ;
 import org.apache.jena.graph.Triple;
-import org.apache.jena.query.* ;
-import org.apache.jena.rdf.model.* ;
+import org.apache.jena.query.Dataset;
+import org.apache.jena.query.DatasetFactory;
+import org.apache.jena.query.Query;
+import org.apache.jena.query.QueryExecution;
+import org.apache.jena.query.QueryExecutionFactory;
+import org.apache.jena.query.QueryFactory;
+import org.apache.jena.query.QueryParseException;
+import org.apache.jena.query.QuerySolution;
+import org.apache.jena.query.QuerySolutionMap;
+import org.apache.jena.query.ResultSet;
+import org.apache.jena.query.ResultSetCloseable;
+import org.apache.jena.query.ResultSetFactory;
+import org.apache.jena.query.ResultSetFormatter;
+import org.apache.jena.query.Syntax;
+import org.apache.jena.rdf.model.AnonId;
+import org.apache.jena.rdf.model.Model;
+import org.apache.jena.rdf.model.ModelFactory;
+import org.apache.jena.rdf.model.Property;
+import org.apache.jena.rdf.model.RDFNode;
+import org.apache.jena.rdf.model.Resource;
+import org.apache.jena.rdf.model.ResourceFactory;
+import org.apache.jena.rdf.model.Statement;
 import org.apache.jena.sparql.core.DatasetGraph;
 import org.apache.jena.sparql.core.DatasetGraphFactory;
 import org.apache.jena.sparql.core.Quad;
@@ -553,9 +576,9 @@ public class TestAPI extends BaseTest
     @Test public void testARQConstructQuad_ShortForm_bad() {
         String queryString = "CONSTRUCT WHERE { GRAPH ?g {?s ?p ?o. FILTER isIRI(?o)}  }";
         try {
-        	QueryFactory.create(queryString, Syntax.syntaxARQ);
+            QueryFactory.create(queryString, Syntax.syntaxARQ);
         }catch (QueryParseException e){
-        	return;
+            return;
         }
         fail("Short form of construct quad MUST be simple graph patterns!");
     }
@@ -601,4 +624,60 @@ public class TestAPI extends BaseTest
             qExec.close();
         }
     }
+
+    /**
+     * Test that a JSON query returns an array with the correct size, given a pre-populated
model.
+     */
+    @Test public void testExecJson() {
+        // JENA-632
+        Query query = QueryFactory.create("JSON { \"s\": ?s , \"p\": ?p , \"o\" : ?o } "
+                + "WHERE { ?s ?p ?o }", Syntax.syntaxARQ);
+        
+        try ( QueryExecution qexec = QueryExecutionFactory.create(query, m) ) {
+            JsonArray jsonArray = qexec.execJson();
+            assertNotNull( jsonArray );
+            assertEquals(3, jsonArray.size());
+        }
+    }
+
+    /**
+     * Test that a JSON query returns an array with the correct data values, given a pre-populated
+     * model.
+     */
+    @Test public void testExecJsonItems() {
+        // JENA-632
+        Model model = ModelFactory.createDefaultModel();
+        {
+            Resource r = model.createResource(AnonId.create("first"));
+            Property p = model.getProperty("");
+            RDFNode node = ResourceFactory.createTypedLiteral("123", XSDDatatype.XSDdecimal);
+            model.add(r, p, node);
+            r = model.createResource(AnonId.create("second"));
+            p = model.getProperty("");
+            node = ResourceFactory.createTypedLiteral("abc", XSDDatatype.XSDstring);
+            model.add(r, p, node);
+            r = model.createResource(AnonId.create("third"));
+            p = model.getProperty("");
+            node = ResourceFactory.createLangLiteral("def", "en");
+            model.add(r, p, node);
+        }
+        Query query = QueryFactory.create("JSON { \"s\": ?s , \"p\": ?p , \"o\" : ?o } "
+                + "WHERE { ?s ?p ?o }", Syntax.syntaxARQ);
+        try ( QueryExecution qexec = QueryExecutionFactory.create(query, model) ) {
+            Iterator<JsonObject> execJsonItems = qexec.execJsonItems();
+            int size = 0;
+            while(execJsonItems.hasNext()) {
+                JsonObject next = execJsonItems.next();
+                if (next.get("s").toString().contains("first")) {
+                    assertEquals(123, next.get("o").getAsNumber().value().intValue());
+                } else if (next.get("s").toString().contains("second")) {
+                    assertEquals("abc", next.get("o").getAsString().value());
+                } else if (next.get("s").toString().contains("third")) {
+                    assertEquals("def", next.get("o").getAsString().value());
+                }
+                size++;
+            }
+            assertEquals(3, size);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/jena/blob/4bf5e3c0/jena-arq/src/test/java/org/apache/jena/sparql/engine/TS_Engine.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/TS_Engine.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/TS_Engine.java
index d7b386c..c1ff26f 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/engine/TS_Engine.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/TS_Engine.java
@@ -34,6 +34,8 @@ import org.junit.runners.Suite ;
       , TestService.class
       , TestQueryEngineHTTP.class
       , TestQueryEngineMultiThreaded.class
+      , TestJsonIterator.class
+      , TestJsonEval.class
 })
 
 public class TS_Engine {}

http://git-wip-us.apache.org/repos/asf/jena/blob/4bf5e3c0/jena-arq/src/test/java/org/apache/jena/sparql/engine/TestJsonEval.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/TestJsonEval.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/TestJsonEval.java
new file mode 100644
index 0000000..47c8548
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/TestJsonEval.java
@@ -0,0 +1,77 @@
+/*
+ * 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.engine;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.jena.atlas.json.JSON;
+import org.apache.jena.atlas.json.JsonValue;
+import org.apache.jena.query.*;
+import org.apache.jena.sparql.core.DatasetGraph;
+import org.apache.jena.sparql.core.DatasetGraphZero;
+import org.junit.Test;
+
+public class TestJsonEval {
+
+    @Test public void json_eval_01() {
+        test("JSON { 'x' : ?x } WHERE { VALUES ?x { 'X' } }",
+             "[ { 'x' : 'X' } ]"); 
+    }
+
+    @Test public void json_eval_02() {
+        test("JSON { 'x' : ?x } WHERE { VALUES ?x { 'X' 'Y' } }",
+             "[ { 'x' : 'X' } , {'x' : 'Y' }]"); 
+    }
+
+    @Test public void json_eval_03() {
+        test("JSON { 's' : 'FOO' } WHERE { }",
+             "[ { 's' : 'FOO' } ]"); 
+    }
+
+    @Test public void json_eval_04() {
+        test("JSON { 'F' : 'string' } WHERE { }",
+             "[ { 'F' : 'string' } ]"); 
+    }
+
+    @Test public void json_eval_05() {
+        test("JSON { 'x' : 123 } WHERE { }",
+             "[ { 'x' : 123 }]"); 
+    }
+
+    @Test public void json_eval_06() {
+        test("JSON { 'x' : 123.5 } WHERE { }",
+             "[ { 'x' : 123.5 }]"); 
+    }
+
+    @Test public void json_eval_07() {
+        test("JSON { 'x' : -10 } WHERE { }",
+             "[ { 'x' : -10 }]"); 
+    }
+
+    private void test(String queryString, String jsonExpected) {
+        Query query = QueryFactory.create(queryString, Syntax.syntaxARQ);
+        DatasetGraph dsg = new DatasetGraphZero();
+        Dataset ds = DatasetFactory.wrap(dsg);
+        try ( QueryExecution qExec = QueryExecutionFactory.create(query, ds) ) {
+            JsonValue jvGot = qExec.execJson() ;
+            JsonValue jvExpected = JSON.parseAny(jsonExpected) ;
+            assertEquals(jvExpected, jvGot);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/4bf5e3c0/jena-arq/src/test/java/org/apache/jena/sparql/engine/TestJsonIterator.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/engine/TestJsonIterator.java b/jena-arq/src/test/java/org/apache/jena/sparql/engine/TestJsonIterator.java
new file mode 100644
index 0000000..82a733b
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/engine/TestJsonIterator.java
@@ -0,0 +1,86 @@
+/**
+ * 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.engine;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.NoSuchElementException;
+
+import org.apache.jena.datatypes.xsd.XSDDatatype;
+import org.apache.jena.query.Query;
+import org.apache.jena.query.QueryExecution;
+import org.apache.jena.query.QueryExecutionFactory;
+import org.apache.jena.query.QueryFactory;
+import org.apache.jena.query.Syntax;
+import org.apache.jena.rdf.model.AnonId;
+import org.apache.jena.rdf.model.Model;
+import org.apache.jena.rdf.model.ModelFactory;
+import org.apache.jena.rdf.model.Property;
+import org.apache.jena.rdf.model.RDFNode;
+import org.apache.jena.rdf.model.Resource;
+import org.apache.jena.rdf.model.ResourceFactory;
+import org.junit.Test;
+
+/**
+ * Tests for {@link JsonIterator}.
+ */
+public class TestJsonIterator {
+
+    @Test
+    public void testIterator() {
+        Model model = ModelFactory.createDefaultModel();
+        {
+            Resource r = model.createResource(AnonId.create("first"));
+            Property p = model.getProperty("");
+            RDFNode node = ResourceFactory.createTypedLiteral("123", XSDDatatype.XSDdecimal);
+            model.add(r, p, node);
+            r = model.createResource(AnonId.create("second"));
+            p = model.getProperty("");
+            node = ResourceFactory.createTypedLiteral("abc", XSDDatatype.XSDstring);
+            model.add(r, p, node);
+            r = model.createResource(AnonId.create("third"));
+            p = model.getProperty("");
+            node = ResourceFactory.createLangLiteral("def", "en");
+            model.add(r, p, node);
+        }
+        Query query = QueryFactory.create("JSON { \"s\": ?s , \"p\": ?p , \"o\" : ?o } "
+                + "WHERE { ?s ?p ?o }", Syntax.syntaxARQ);
+        try ( QueryExecution qexec = QueryExecutionFactory.create(query, model) ) {
+            JsonIterator execJsonItems = (JsonIterator) qexec.execJsonItems();
+            assertTrue(execJsonItems.hasNext());
+            assertNotNull(execJsonItems.next());
+        }
+    }
+
+    @Test(expected = NoSuchElementException.class)
+    public void testInitialStates() {
+        JsonIterator iterator = new JsonIterator(null, Collections.emptyList());
+        assertFalse(iterator.hasNext());
+        iterator.next();
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemoveNotImplemented() {
+        JsonIterator iterator = new JsonIterator(null, Collections.emptyList());
+        iterator.remove();
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/4bf5e3c0/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseJson.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseJson.java
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseJson.java
new file mode 100644
index 0000000..c0be5db
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseJson.java
@@ -0,0 +1,150 @@
+/*
+ * 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.fuseki.servlets;
+
+import static java.lang.String.format;
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.jena.atlas.json.JsonObject;
+import org.apache.jena.fuseki.FusekiException;
+import org.apache.jena.fuseki.servlets.ResponseResultSet.OutputContent;
+import org.apache.jena.query.QueryCancelledException;
+import org.apache.jena.query.ResultSetFormatter;
+import org.apache.jena.riot.WebContent;
+import org.apache.jena.web.HttpSC;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Responsible for handling JSON response output.
+ */
+public class ResponseJson 
+{
+
+    // Loggers
+    private static Logger xlog = LoggerFactory.getLogger(ResponseJson.class) ;
+
+    /**
+     * Outputs a JSON query result
+     *
+     * @param action HTTP action
+     * @param jsonItem a ResultSetJsonStream instance
+     */
+    public static void doResponseJson(HttpAction action, Iterator<JsonObject> jsonItem)
+    {
+        if ( jsonItem == null)
+        {
+            xlog.warn("doResponseJson: Result set is null") ; 
+            throw new FusekiException("Result set is null") ;
+        }
+
+        jsonOutput(action, jsonItem) ;
+    }
+
+    private static void jsonOutput(HttpAction action, final Iterator<JsonObject> jsonItems)
+    {
+        OutputContent proc = new OutputContent()
+        {
+            @Override
+            public void output(ServletOutputStream out)
+            {
+                if (jsonItems != null)
+                    ResultSetFormatter.output(out, jsonItems) ;
+            }
+        } ;
+
+        try
+        {
+            String callback = ResponseOps.paramCallback(action.request) ;
+            ServletOutputStream out = action.response.getOutputStream() ;
+
+            if ( callback != null )
+            {
+                callback = StringUtils.replaceChars(callback, "\r", "") ;
+                callback = StringUtils.replaceChars(callback, "\n", "") ;
+                out.print(callback) ;
+                out.println("(") ;
+            }
+
+            output(action, "application/json", WebContent.charsetUTF8, proc) ;
+
+            if ( callback != null )
+                out.println(")") ;
+        } catch (IOException ex) { ServletOps.errorOccurred(ex) ; }
+    }
+
+    private static void output(HttpAction action, String contentType, String charset, OutputContent
proc) 
+    {
+        try
+        {
+            setHttpResponse(action.request, action.response, contentType, charset) ; 
+            action.response.setStatus(HttpSC.OK_200) ;
+            ServletOutputStream out = action.response.getOutputStream() ;
+            try
+            {
+                proc.output(out) ;
+                out.flush() ;
+            }
+            catch (QueryCancelledException ex)
+            {
+                // Bother.  Status code 200 already sent.
+                xlog.info(format("[%d] Query Cancelled - results truncated (but 200 already
sent)", action.id)) ;
+                out.println() ;
+                out.println("##  Query cancelled due to timeout during execution   ##") ;
+                out.println("##  ****          Incomplete results           ****   ##") ;
+                out.flush() ;
+                // No point raising an exception - 200 was sent already.  
+                //errorOccurred(ex) ;
+            }
+        // Includes client gone.
+        } catch (IOException ex) 
+        { ServletOps.errorOccurred(ex) ; }
+        // Do not call httpResponse.flushBuffer(); here - Jetty closes the stream if it is
a gzip stream
+        // then the JSON callback closing details can't be added. 
+    }
+
+    public static void setHttpResponse(HttpServletRequest httpRequest,
+            HttpServletResponse httpResponse,
+            String contentType, String charset) 
+    {
+        // ---- Set up HTTP Response
+        // Stop caching (not that ?queryString URLs are cached anyway)
+        if ( true )
+        {
+            httpResponse.setHeader("Cache-Control", "no-cache") ;
+            httpResponse.setHeader("Pragma", "no-cache") ;
+        }
+        // See: http://www.w3.org/International/O-HTTP-charset.html
+        if ( contentType != null )
+        {
+            if ( charset != null )
+                contentType = contentType+"; charset="+charset ;
+            xlog.trace("Content-Type for response: "+contentType) ;
+            httpResponse.setContentType(contentType) ;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/4bf5e3c0/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
index 278b904..d88a51c 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
@@ -45,6 +45,7 @@ import javax.servlet.http.HttpServletResponse ;
 
 import org.apache.jena.atlas.io.IO ;
 import org.apache.jena.atlas.io.IndentedLineBuffer ;
+import org.apache.jena.atlas.json.JsonObject;
 import org.apache.jena.atlas.web.ContentType ;
 import org.apache.jena.fuseki.Fuseki ;
 import org.apache.jena.fuseki.FusekiException ;
@@ -345,6 +346,14 @@ public abstract class SPARQL_Query extends SPARQL_Protocol
             return new SPARQLResult(b) ;
         }
 
+        if ( query.isJsonType() )
+        {
+            Iterator<JsonObject> jsonIterator = queryExecution.execJsonItems();
+            //JsonArray jsonArray = queryExecution.execJson();
+            action.log.info(format("[%d] exec/json", action.id));
+            return new SPARQLResult(jsonIterator);
+        }
+
         ServletOps.errorBadRequest("Unknown query type - " + queryStringLog) ;
         return null ;
     }
@@ -399,6 +408,8 @@ public abstract class SPARQL_Query extends SPARQL_Protocol
             ResponseDataset.doResponseModel(action, result.getModel());
         else if ( result.isBoolean() )
             ResponseResultSet.doResponseResultSet(action, result.getBooleanResult()) ;
+        else if ( result.isJson() )
+            ResponseJson.doResponseJson(action, result.getJsonItems()) ;
         else
             ServletOps.errorOccurred("Unknown or invalid result type") ;
     }

http://git-wip-us.apache.org/repos/asf/jena/blob/4bf5e3c0/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestQuery.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestQuery.java
b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestQuery.java
index 624c56e..a06bc35 100644
--- a/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestQuery.java
+++ b/jena-fuseki2/jena-fuseki-core/src/test/java/org/apache/jena/fuseki/TestQuery.java
@@ -24,12 +24,18 @@ import static org.apache.jena.fuseki.ServerTest.* ;
 import static org.apache.jena.fuseki.ServerTest.model1 ;
 import static org.apache.jena.fuseki.ServerTest.model2 ;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
 import java.io.IOException ;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.net.HttpURLConnection ;
 import java.net.URL ;
 import java.util.Iterator ;
 
 import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.jena.atlas.json.JsonArray;
+import org.apache.jena.atlas.lib.NotImplemented;
 import org.apache.jena.atlas.web.AcceptList ;
 import org.apache.jena.atlas.web.MediaType;
 import org.apache.jena.graph.Node ;
@@ -264,6 +270,44 @@ public class TestQuery extends AbstractFusekiTest {
         }
     }
 
+    @Test(expected = NotImplemented.class)
+    public void query_json_01() throws IOException {
+        Query query = QueryFactory.create("JSON { \"s\": ?s , \"p\": ?p , \"o\" : ?o } "
+                + "WHERE { ?s ?p ?o }", Syntax.syntaxARQ);
+        query.toString();
+        try ( QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery(),
query) ) {
+            JsonArray result = qExec.execJson();
+            assertEquals(1, result.size());
+        }
+    }
+
+    @Test
+    public void query_json_02() throws IOException {
+        String qs = Convert.encWWWForm("JSON { \"s\": ?s , \"p\": ?p , \"o\" : ?o } "
+                + "WHERE { ?s ?p ?o }") ;
+        URL u = new URL(serviceQuery() + "?query=" + qs) ;
+        HttpURLConnection conn = (HttpURLConnection)u.openConnection() ;
+        String result = null;
+        StringBuffer sb = new StringBuffer();
+        InputStream is = null;
+        try {
+            is = new BufferedInputStream(conn.getInputStream());
+            BufferedReader br = new BufferedReader(new InputStreamReader(is));
+            String inputLine = "";
+            while ((inputLine = br.readLine()) != null) {
+                sb.append(inputLine);
+            }
+            result = sb.toString();
+        }
+        finally {
+            if (is != null) {
+                is.close(); 
+            }   
+        }
+        Assert.assertNotNull(result);
+        Assert.assertTrue(result.contains("http://example/x"));
+    }
+
     private static void execQuery(String queryString, int exceptedRowCount) {
         try ( QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery(),
queryString) ) {
             ResultSet rs = qExec.execSelect() ;


Mime
View raw message