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 2015/08/24 10:13:26 UTC

[17/50] jena git commit: Add construct quad support to Fuseki

Add construct quad support to Fuseki

Project: http://git-wip-us.apache.org/repos/asf/jena/repo
Commit: http://git-wip-us.apache.org/repos/asf/jena/commit/0eb28d80
Tree: http://git-wip-us.apache.org/repos/asf/jena/tree/0eb28d80
Diff: http://git-wip-us.apache.org/repos/asf/jena/diff/0eb28d80

Branch: refs/heads/master
Commit: 0eb28d805e3270c9951f13cdbd55af3e8d01d0ab
Parents: e819ac3
Author: confidencesun <co...@gmail.com>
Authored: Tue Aug 11 12:05:55 2015 +0800
Committer: confidencesun <co...@gmail.com>
Committed: Tue Aug 11 12:05:55 2015 +0800

----------------------------------------------------------------------
 .../sparql/engine/http/QueryEngineHTTP.java     |  30 +-
 .../main/java/org/apache/jena/fuseki/DEF.java   |   7 +
 .../jena/fuseki/servlets/ResponseDataset.java   | 134 +++
 .../jena/fuseki/servlets/SPARQL_Query.java      | 838 ++++++++++---------
 .../java/org/apache/jena/fuseki/TestQuery.java  | 188 ++---
 5 files changed, 719 insertions(+), 478 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/0eb28d80/jena-arq/src/main/java/org/apache/jena/sparql/engine/http/QueryEngineHTTP.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/engine/http/QueryEngineHTTP.java b/jena-arq/src/main/java/org/apache/jena/sparql/engine/http/QueryEngineHTTP.java
index a35fffc..cab831f 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/engine/http/QueryEngineHTTP.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/engine/http/QueryEngineHTTP.java
@@ -394,7 +394,7 @@ public class QueryEngineHTTP implements QueryExecution {
     
     @Override
     public Iterator<Quad> execConstructQuads(){
-    	return null;
+    	return execQuads();
     }
     
     @Override
@@ -469,6 +469,32 @@ public class QueryEngineHTTP implements QueryExecution {
 
         return RiotReader.createIteratorTriples(in, lang, null);
     }
+    
+    private Iterator<Quad> execQuads() {
+        checkNotClosed() ;
+        HttpQuery httpQuery = makeHttpQuery();
+        httpQuery.setAccept(WebContent.defaultDatasetAcceptHeader);
+        InputStream in = httpQuery.exec();
+        
+        // Don't assume the endpoint actually gives back the content type we
+        // asked for
+        String actualContentType = httpQuery.getContentType();
+
+        // If the server fails to return a Content-Type then we will assume
+        // the server returned the type we asked for
+        if (actualContentType == null || actualContentType.equals("")) {
+            actualContentType = WebContent.defaultDatasetAcceptHeader;
+        }
+
+        // Try to select language appropriately here based on the model content
+        // type
+        Lang lang = RDFLanguages.contentTypeToLang(actualContentType);
+        if (!RDFLanguages.isQuads(lang))
+            throw new QueryException("Endpoint returned Content Type: " + actualContentType
+                    + " which is not a valid RDF Dataset syntax");
+
+        return RiotReader.createIteratorQuads(in, lang, null);
+    }
 
     @Override
     public boolean execAsk() {
@@ -817,4 +843,4 @@ public class QueryEngineHTTP implements QueryExecution {
         if ( v < 1 )
             sBuff.append(";q=").append(v) ;
     } 
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/jena/blob/0eb28d80/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/DEF.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/DEF.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/DEF.java
index b419cc6..953b724 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/DEF.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/DEF.java
@@ -31,6 +31,13 @@ public class DEF
     
     public static final AcceptList jsonOffer          = AcceptList.create(contentTypeJSON) ;
 
+    public static final AcceptList pureRdfOffer       = AcceptList.create(contentTypeTurtle, 
+                                                                          contentTypeTurtleAlt1,
+                                                                          contentTypeTurtleAlt2,
+                                                                          contentTypeNTriples,
+                                                                          contentTypeRDFXML
+                                                                          ) ;
+    
     public static final AcceptList rdfOffer           = AcceptList.create(contentTypeTurtle, 
                                                                           contentTypeTurtleAlt1,
                                                                           contentTypeTurtleAlt2,

http://git-wip-us.apache.org/repos/asf/jena/blob/0eb28d80/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseDataset.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseDataset.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseDataset.java
new file mode 100644
index 0000000..91d615d
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseDataset.java
@@ -0,0 +1,134 @@
+/*
+ * 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 org.apache.jena.riot.WebContent.charsetUTF8;
+import static org.apache.jena.riot.WebContent.contentTypeJSONLD;
+import static org.apache.jena.riot.WebContent.contentTypeNTriples;
+import static org.apache.jena.riot.WebContent.contentTypeRDFJSON;
+import static org.apache.jena.riot.WebContent.contentTypeRDFXML;
+import static org.apache.jena.riot.WebContent.contentTypeTurtle;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.jena.atlas.web.MediaType;
+import org.apache.jena.fuseki.DEF;
+import org.apache.jena.fuseki.Fuseki;
+import org.apache.jena.fuseki.conneg.ConNeg;
+import org.apache.jena.fuseki.conneg.WebLib;
+import org.apache.jena.query.Dataset;
+import org.apache.jena.riot.Lang;
+import org.apache.jena.riot.RDFDataMgr;
+import org.apache.jena.riot.RDFLanguages;
+import org.apache.jena.riot.WebContent;
+import org.apache.jena.web.HttpSC;
+
+public class ResponseDataset
+{
+    // Short names for "output="
+    private static final String contentOutputTriG          = "trig" ;
+    private static final String contentOutputNQuads        = "n-quads" ;
+
+
+    public static Map<String,String> shortNamesModel = new HashMap<String, String>() ;
+    static {
+
+        // Some short names.  keys are lowercase.
+        
+        ResponseOps.put(shortNamesModel, contentOutputNQuads,  WebContent.contentTypeNQuads) ;
+        ResponseOps.put(shortNamesModel, contentOutputTriG,     WebContent.contentTypeTriG) ;
+    }
+
+    public static void doResponseDataset(HttpAction action, Dataset dataset) 
+    {
+        HttpServletRequest request = action.request ;
+        HttpServletResponse response = action.response ;
+        
+        String mimeType = null ;        // Header request type 
+
+        // TODO Use MediaType throughout.
+        MediaType i = ConNeg.chooseContentType(request, DEF.quadsOffer, DEF.acceptNQuads) ;
+        if ( i != null )
+            mimeType = i.getContentType() ;
+
+        String outputField = ResponseOps.paramOutput(request, shortNamesModel) ;
+        if ( outputField != null )
+            mimeType = outputField ;
+
+        String writerMimeType = mimeType ;
+
+        if ( mimeType == null )
+        {
+            Fuseki.actionLog.warn("Can't find MIME type for response") ;
+            String x = WebLib.getAccept(request) ;
+            String msg ;
+            if ( x == null )
+                msg = "No Accept: header" ;
+            else
+                msg = "Accept: "+x+" : Not understood" ;
+            ServletOps.error(HttpSC.NOT_ACCEPTABLE_406, msg) ;
+        }
+
+        String contentType = mimeType ;
+        String charset =     charsetUTF8 ;
+
+        String forceAccept = ResponseOps.paramForceAccept(request) ;
+        if ( forceAccept != null )
+        {
+            contentType = forceAccept ;
+            charset = charsetUTF8 ;
+        }
+
+        Lang lang = RDFLanguages.contentTypeToLang(contentType) ;
+        if ( lang == null )
+            ServletOps.errorBadRequest("Can't determine output content type: "+contentType) ;
+        
+//        if ( rdfw instanceof RDFXMLWriterI )
+//            rdfw.setProperty("showXmlDeclaration", "true") ;
+
+    //        // Write locally to check it's possible.
+    //        // Time/space tradeoff.
+    //        try {
+    //            OutputStream out = new NullOutputStream() ;
+    //            RDFDataMgr.write(out, model, lang) ;
+    //            IO.flush(out) ;
+    //        } catch (JenaException ex)
+    //        {
+    //            SPARQL_ServletBase.errorOccurred(ex) ;
+    //        }
+
+        try {
+            ResponseResultSet.setHttpResponse(action, contentType, charset) ; 
+            response.setStatus(HttpSC.OK_200) ;
+            ServletOutputStream out = response.getOutputStream() ;
+            RDFDataMgr.write(out, dataset, lang) ;
+            out.flush() ;
+        }
+        catch (Exception ex) { 
+            action.log.info("Exception while writing the response model: "+ex.getMessage(), ex) ;
+            ServletOps.errorOccurred("Exception while writing the response model: "+ex.getMessage(), ex) ;
+        }
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/0eb28d80/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 ba4a61a..bed63da 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
@@ -16,385 +16,463 @@
  * limitations under the License.
  */
 
-package org.apache.jena.fuseki.servlets ;
-
-import static java.lang.String.format ;
-import static org.apache.jena.fuseki.server.CounterName.QueryTimeouts ;
-import static org.apache.jena.riot.WebContent.ctHTMLForm ;
-import static org.apache.jena.riot.WebContent.ctSPARQLQuery ;
-import static org.apache.jena.riot.WebContent.isHtmlForm ;
-import static org.apache.jena.riot.WebContent.matchContentType ;
-import static org.apache.jena.riot.web.HttpNames.paramAccept ;
-import static org.apache.jena.riot.web.HttpNames.paramCallback ;
-import static org.apache.jena.riot.web.HttpNames.paramDefaultGraphURI ;
-import static org.apache.jena.riot.web.HttpNames.paramForceAccept ;
-import static org.apache.jena.riot.web.HttpNames.paramNamedGraphURI ;
-import static org.apache.jena.riot.web.HttpNames.paramOutput1 ;
-import static org.apache.jena.riot.web.HttpNames.paramOutput2 ;
-import static org.apache.jena.riot.web.HttpNames.paramQuery ;
-import static org.apache.jena.riot.web.HttpNames.paramQueryRef ;
-import static org.apache.jena.riot.web.HttpNames.paramStyleSheet ;
-import static org.apache.jena.riot.web.HttpNames.paramTimeout ;
-
-import java.io.IOException ;
-import java.io.InputStream ;
-import java.util.* ;
-
-import javax.servlet.http.HttpServletRequest ;
-import javax.servlet.http.HttpServletResponse ;
-
-import org.apache.jena.atlas.io.IO ;
-import org.apache.jena.atlas.io.IndentedLineBuffer ;
-import org.apache.jena.atlas.web.ContentType ;
-import org.apache.jena.fuseki.Fuseki ;
-import org.apache.jena.fuseki.FusekiException ;
-import org.apache.jena.fuseki.FusekiLib ;
-import org.apache.jena.query.* ;
-import org.apache.jena.rdf.model.Model ;
-import org.apache.jena.riot.web.HttpNames ;
-import org.apache.jena.riot.web.HttpOp ;
-import org.apache.jena.sparql.core.Prologue ;
-import org.apache.jena.sparql.resultset.SPARQLResult ;
-import org.apache.jena.web.HttpSC ;
-
-/** Handle SPARQL Query requests overt eh SPARQL Protocol. 
- * Subclasses provide this algorithm with the actual dataset to query, whether
- * a dataset hosted by this server ({@link SPARQL_QueryDataset}) or 
- * speciifed in the protocol request ({@link SPARQL_QueryGeneral}).   
- */ 
-public abstract class SPARQL_Query extends SPARQL_Protocol
-{
-    private static final String QueryParseBase = Fuseki.BaseParserSPARQL ;
-    
-    public SPARQL_Query() {
-        super() ;
-    }
-
-    // Choose REST verbs to support.
-
-    @Override
-    protected void doPost(HttpServletRequest request, HttpServletResponse response) {
-        doCommon(request, response) ;
-    }
-
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
-        doCommon(request, response) ;
-    }
-
-    // HEAD
-
-    @Override
-    protected void doOptions(HttpServletRequest request, HttpServletResponse response) {
-        setCommonHeadersForOptions(response) ;
-        response.setHeader(HttpNames.hAllow, "GET,OPTIONS,POST") ;
-        response.setHeader(HttpNames.hContentLengh, "0") ;
-    }
-
-    @Override
-    protected final void perform(HttpAction action) {
-        // GET
-        if ( action.request.getMethod().equals(HttpNames.METHOD_GET) ) {
-            executeWithParameter(action) ;
-            return ;
-        }
-
-        ContentType ct = FusekiLib.getContentType(action) ;
-
-        // POST application/x-www-form-url
-        // POST ?query= and no Content-Type
-        if ( ct == null || isHtmlForm(ct) ) {
-            // validation checked that if no Content-type, then its a POST with ?query=
-            executeWithParameter(action) ;
-            return ;
-        }
-
-        // POST application/sparql-query
-        if ( matchContentType(ct, ctSPARQLQuery) ) {
-            executeBody(action) ;
-            return ;
-        }
-
-        ServletOps.error(HttpSC.UNSUPPORTED_MEDIA_TYPE_415, "Bad content type: " + ct.getContentType()) ;
-    }
-
-    // All the params we support
-
-    protected static List<String> allParams = Arrays.asList(paramQuery, paramDefaultGraphURI, paramNamedGraphURI,
-                                                            paramQueryRef, paramStyleSheet, paramAccept, paramOutput1,
-                                                            paramOutput2, paramCallback, paramForceAccept, paramTimeout) ;
-
-    /**
-     * Validate the request, checking HTTP method and HTTP Parameters.
-     * @param action HTTP Action
-     */
-    @Override
-    protected void validate(HttpAction action) {
-        String method = action.request.getMethod().toUpperCase(Locale.ROOT) ;
-
-        if ( !HttpNames.METHOD_POST.equals(method) && !HttpNames.METHOD_GET.equals(method) )
-            ServletOps.errorMethodNotAllowed("Not a GET or POST request") ;
-
-        if ( HttpNames.METHOD_GET.equals(method) && action.request.getQueryString() == null ) {
-            ServletOps.warning(action, "Service Description / SPARQL Query / " + action.request.getRequestURI()) ;
-            ServletOps.errorNotFound("Service Description: " + action.request.getRequestURI()) ;
-        }
-
-        // Use of the dataset describing parameters is check later.
-        try {
-            validateParams(action, allParams) ;
-            validateRequest(action) ;
-        } catch (ActionErrorException ex) {
-            throw ex ;
-        }
-        // Query not yet parsed.
-    }
-
-    /**
-     * Validate the request after checking HTTP method and HTTP Parameters.
-     * @param action HTTP Action
-     */
-    protected abstract void validateRequest(HttpAction action) ;
-
-    /**
-     * Helper method for validating request.
-     * @param request HTTP request
-     * @param params parameters in a collection of Strings
-     */
-    protected void validateParams(HttpAction action, Collection<String> params) {
-        HttpServletRequest request = action.request ;
-        ContentType ct = FusekiLib.getContentType(request) ;
-        boolean mustHaveQueryParam = true ;
-        if ( ct != null ) {
-            String incoming = ct.getContentType() ;
-
-            if ( matchContentType(ctSPARQLQuery, ct) ) {
-                mustHaveQueryParam = false ;
-                // Drop through.
-            } else if ( matchContentType(ctHTMLForm, ct)) {
-                // Nothing specific to do
-            } 
-            else
-                ServletOps.error(HttpSC.UNSUPPORTED_MEDIA_TYPE_415, "Unsupported: " + incoming) ;
-        }
-
-        // GET/POST of a form at this point.
-
-        if ( mustHaveQueryParam ) {
-            int N = countParamOccurences(request, paramQuery) ;
-
-            if ( N == 0 )
-                ServletOps.errorBadRequest("SPARQL Query: No 'query=' parameter") ;
-            if ( N > 1 )
-                ServletOps.errorBadRequest("SPARQL Query: Multiple 'query=' parameters") ;
-
-            // application/sparql-query does not use a query param.
-            String queryStr = request.getParameter(HttpNames.paramQuery) ;
-
-            if ( queryStr == null )
-                ServletOps.errorBadRequest("SPARQL Query: No query specified (no 'query=' found)") ;
-            if ( queryStr.isEmpty() )
-                ServletOps.errorBadRequest("SPARQL Query: Empty query string") ;
-        }
-
-        if ( params != null ) {
-            Enumeration<String> en = request.getParameterNames() ;
-            for (; en.hasMoreElements();) {
-                String name = en.nextElement() ;
-                if ( !params.contains(name) )
-                    ServletOps.warning(action, "SPARQL Query: Unrecognize request parameter (ignored): " + name) ;
-            }
-        }
-    }
-
-    private void executeWithParameter(HttpAction action) {
-        String queryString = action.request.getParameter(paramQuery) ;
-        execute(queryString, action) ;
-    }
-
-    private void executeBody(HttpAction action) {
-        String queryString = null ;
-        try {
-            InputStream input = action.request.getInputStream() ;
-            queryString = IO.readWholeFileAsUTF8(input) ;
-        } catch (IOException ex) {
-            ServletOps.errorOccurred(ex) ;
-        }
-        execute(queryString, action) ;
-    }
-
-    private void execute(String queryString, HttpAction action) {
-        String queryStringLog = ServletOps.formatForLog(queryString) ;
-        if ( action.verbose )
-            action.log.info(format("[%d] Query = \n%s", action.id, queryString)) ;
-        else
-            action.log.info(format("[%d] Query = %s", action.id, queryStringLog)) ;
-
-        Query query = null ;
-        try {
-            // NB syntax is ARQ (a superset of SPARQL)
-            query = QueryFactory.create(queryString, QueryParseBase, Syntax.syntaxARQ) ;
-            queryStringLog = formatForLog(query) ;
-            validateQuery(action, query) ;
-        } catch (ActionErrorException ex) {
-            throw ex ;
-        } catch (QueryParseException ex) {
-            ServletOps.errorBadRequest("Parse error: \n" + queryString + "\n\r" + messageForQueryException(ex)) ;
-        }
-        // Should not happen.
-        catch (QueryException ex) {
-            ServletOps.errorBadRequest("Error: \n" + queryString + "\n\r" + ex.getMessage()) ;
-        }
-
-        // Assumes finished whole thing by end of sendResult.
-        try {
-            action.beginRead() ;
-            Dataset dataset = decideDataset(action, query, queryStringLog) ;
-            try ( QueryExecution qExec = createQueryExecution(query, dataset) ; ) {
-                SPARQLResult result = executeQuery(action, qExec, query, queryStringLog) ;
-                // Deals with exceptions itself.
-                sendResults(action, result, query.getPrologue()) ;
-            }
-        } 
-        catch (QueryParseException ex) {
-            // Late stage static error (e.g. bad fixed Lucene query string). 
-            ServletOps.errorBadRequest("Query parse error: \n" + queryString + "\n\r" + messageForQueryException(ex)) ;
-        }
-        catch (QueryCancelledException ex) {
-            // Additional counter information.
-            incCounter(action.getEndpoint().getCounters(), QueryTimeouts) ;
-            throw ex ;
-        } finally { action.endRead() ; }
-    }
-
-    /**
-     * Check the query - if unacceptable, throw ActionErrorException or call
-     * super.error
-     * @param action HTTP Action
-     * @param query  SPARQL Query
-     */
-    protected abstract void validateQuery(HttpAction action, Query query) ;
-
-    /** Create the {@link QueryExecution} for this operation.
-     * @param query
-     * @param dataset
-     * @return QueryExecution
-     */
-    protected QueryExecution createQueryExecution(Query query, Dataset dataset) {
-        return QueryExecutionFactory.create(query, dataset) ;
-    }
-
-    /** Perform the {@link QueryExecution} once.
-     * @param action
-     * @param queryExecution
-     * @param query
-     * @param queryStringLog Informational string created from the initial query. 
-     * @return
-     */
-    protected SPARQLResult executeQuery(HttpAction action, QueryExecution queryExecution, Query query, String queryStringLog) {
-        setAnyTimeouts(queryExecution, action) ;
-
-        if ( query.isSelectType() ) {
-            ResultSet rs = queryExecution.execSelect() ;
-
-            // Force some query execution now.
-            //
-            // If the timeout-first-row goes off, the output stream has not
-            // been started so the HTTP error code is sent.
-
-            rs.hasNext() ;
-
-            // If we wanted perfect query time cancellation, we could consume
-            // the result now
-            // to see if the timeout-end-of-query goes off.
-
-            // rs = ResultSetFactory.copyResults(rs) ;
-
-            action.log.info(format("[%d] exec/select", action.id)) ;
-            return new SPARQLResult(rs) ;
-        }
-
-        if ( query.isConstructType() ) {
-            Model model = queryExecution.execConstruct() ;
-            action.log.info(format("[%d] exec/construct", action.id)) ;
-            return new SPARQLResult(model) ;
-        }
-
-        if ( query.isDescribeType() ) {
-            Model model = queryExecution.execDescribe() ;
-            action.log.info(format("[%d] exec/describe", action.id)) ;
-            return new SPARQLResult(model) ;
-        }
-
-        if ( query.isAskType() ) {
-            boolean b = queryExecution.execAsk() ;
-            action.log.info(format("[%d] exec/ask", action.id)) ;
-            return new SPARQLResult(b) ;
-        }
-
-        ServletOps.errorBadRequest("Unknown query type - " + queryStringLog) ;
-        return null ;
-    }
-
-    private void setAnyTimeouts(QueryExecution qexec, HttpAction action) {
-//        if ( !(action.getDataService().allowTimeoutOverride) )
-//            return ;
-
-        long desiredTimeout = Long.MAX_VALUE ;
-        String timeoutHeader = action.request.getHeader("Timeout") ;
-        String timeoutParameter = action.request.getParameter("timeout") ;
-        if ( timeoutHeader != null ) {
-            try {
-                desiredTimeout = (int)(Float.parseFloat(timeoutHeader) * 1000) ;
-            } catch (NumberFormatException e) {
-                throw new FusekiException("Timeout header must be a number", e) ;
-            }
-        } else if ( timeoutParameter != null ) {
-            try {
-                desiredTimeout = (int)(Float.parseFloat(timeoutParameter) * 1000) ;
-            } catch (NumberFormatException e) {
-                throw new FusekiException("timeout parameter must be a number", e) ;
-            }
-        }
-
-//        desiredTimeout = Math.min(action.getDataService().maximumTimeoutOverride, desiredTimeout) ;
-        if ( desiredTimeout != Long.MAX_VALUE )
-            qexec.setTimeout(desiredTimeout) ;
-    }
-
-    /** Choose the dataset for this SPARQL Query request. 
-     * @param action
-     * @param query  Query - this may be modified to remove a DatasetDescription.
-     * @param queryStringLog 
-     * @return {@link Dataset}
-     */
-    protected abstract Dataset decideDataset(HttpAction action, Query query, String queryStringLog) ;
-
-    /** Ship the results to the remote caller.
-     * @param action
-     * @param result
-     * @param qPrologue
-     */
-    protected void sendResults(HttpAction action, SPARQLResult result, Prologue qPrologue) {
-        if ( result.isResultSet() )
-            ResponseResultSet.doResponseResultSet(action, result.getResultSet(), qPrologue) ;
-        else if ( result.isGraph() )
-            ResponseModel.doResponseModel(action, result.getModel()) ;
-        else if ( result.isBoolean() )
-            ResponseResultSet.doResponseResultSet(action, result.getBooleanResult()) ;
-        else
-            ServletOps.errorOccurred("Unknown or invalid result type") ;
-    }
-
-    private String formatForLog(Query query) {
-        IndentedLineBuffer out = new IndentedLineBuffer() ;
-        out.setFlatMode(true) ;
-        query.serialize(out) ;
-        return out.asString() ;
-    }
-
-    private String getRemoteString(String queryURI) {
-        return HttpOp.execHttpGetString(queryURI) ;
-    }
+package org.apache.jena.fuseki.servlets;
+
+import static java.lang.String.format;
+import static org.apache.jena.fuseki.server.CounterName.QueryTimeouts;
+import static org.apache.jena.riot.WebContent.ctHTMLForm;
+import static org.apache.jena.riot.WebContent.ctSPARQLQuery;
+import static org.apache.jena.riot.WebContent.isHtmlForm;
+import static org.apache.jena.riot.WebContent.matchContentType;
+import static org.apache.jena.riot.web.HttpNames.paramAccept;
+import static org.apache.jena.riot.web.HttpNames.paramCallback;
+import static org.apache.jena.riot.web.HttpNames.paramDefaultGraphURI;
+import static org.apache.jena.riot.web.HttpNames.paramForceAccept;
+import static org.apache.jena.riot.web.HttpNames.paramNamedGraphURI;
+import static org.apache.jena.riot.web.HttpNames.paramOutput1;
+import static org.apache.jena.riot.web.HttpNames.paramOutput2;
+import static org.apache.jena.riot.web.HttpNames.paramQuery;
+import static org.apache.jena.riot.web.HttpNames.paramQueryRef;
+import static org.apache.jena.riot.web.HttpNames.paramStyleSheet;
+import static org.apache.jena.riot.web.HttpNames.paramTimeout;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Locale;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.jena.atlas.io.IO;
+import org.apache.jena.atlas.io.IndentedLineBuffer;
+import org.apache.jena.atlas.web.AcceptList;
+import org.apache.jena.atlas.web.ContentType;
+import org.apache.jena.atlas.web.MediaType;
+import org.apache.jena.fuseki.DEF;
+import org.apache.jena.fuseki.Fuseki;
+import org.apache.jena.fuseki.FusekiException;
+import org.apache.jena.fuseki.FusekiLib;
+import org.apache.jena.fuseki.conneg.WebLib;
+import org.apache.jena.query.Dataset;
+import org.apache.jena.query.Query;
+import org.apache.jena.query.QueryCancelledException;
+import org.apache.jena.query.QueryException;
+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.ResultSet;
+import org.apache.jena.query.Syntax;
+import org.apache.jena.rdf.model.Model;
+import org.apache.jena.riot.web.HttpNames;
+import org.apache.jena.riot.web.HttpOp;
+import org.apache.jena.sparql.core.Prologue;
+import org.apache.jena.sparql.resultset.SPARQLResult;
+import org.apache.jena.web.HttpSC;
+
+/**
+ * Handle SPARQL Query requests overt eh SPARQL Protocol. Subclasses provide
+ * this algorithm with the actual dataset to query, whether a dataset hosted by
+ * this server ({@link SPARQL_QueryDataset}) or speciifed in the protocol
+ * request ({@link SPARQL_QueryGeneral}).
+ */
+public abstract class SPARQL_Query extends SPARQL_Protocol {
+	private static final String QueryParseBase = Fuseki.BaseParserSPARQL;
+
+	public SPARQL_Query() {
+		super();
+	}
+
+	// Choose REST verbs to support.
+
+	@Override
+	protected void doPost(HttpServletRequest request,
+			HttpServletResponse response) {
+		doCommon(request, response);
+	}
+
+	@Override
+	protected void doGet(HttpServletRequest request,
+			HttpServletResponse response) {
+		doCommon(request, response);
+	}
+
+	// HEAD
+
+	@Override
+	protected void doOptions(HttpServletRequest request,
+			HttpServletResponse response) {
+		setCommonHeadersForOptions(response);
+		response.setHeader(HttpNames.hAllow, "GET,OPTIONS,POST");
+		response.setHeader(HttpNames.hContentLengh, "0");
+	}
+
+	@Override
+	protected final void perform(HttpAction action) {
+		// GET
+		if (action.request.getMethod().equals(HttpNames.METHOD_GET)) {
+			executeWithParameter(action);
+			return;
+		}
+
+		ContentType ct = FusekiLib.getContentType(action);
+
+		// POST application/x-www-form-url
+		// POST ?query= and no Content-Type
+		if (ct == null || isHtmlForm(ct)) {
+			// validation checked that if no Content-type, then its a POST with
+			// ?query=
+			executeWithParameter(action);
+			return;
+		}
+
+		// POST application/sparql-query
+		if (matchContentType(ct, ctSPARQLQuery)) {
+			executeBody(action);
+			return;
+		}
+
+		ServletOps.error(HttpSC.UNSUPPORTED_MEDIA_TYPE_415,
+				"Bad content type: " + ct.getContentType());
+	}
+
+	// All the params we support
+
+	protected static List<String> allParams = Arrays.asList(paramQuery,
+			paramDefaultGraphURI, paramNamedGraphURI, paramQueryRef,
+			paramStyleSheet, paramAccept, paramOutput1, paramOutput2,
+			paramCallback, paramForceAccept, paramTimeout);
+
+	/**
+	 * Validate the request, checking HTTP method and HTTP Parameters.
+	 * 
+	 * @param action
+	 *            HTTP Action
+	 */
+	@Override
+	protected void validate(HttpAction action) {
+		String method = action.request.getMethod().toUpperCase(Locale.ROOT);
+
+		if (!HttpNames.METHOD_POST.equals(method)
+				&& !HttpNames.METHOD_GET.equals(method))
+			ServletOps.errorMethodNotAllowed("Not a GET or POST request");
+
+		if (HttpNames.METHOD_GET.equals(method)
+				&& action.request.getQueryString() == null) {
+			ServletOps.warning(action, "Service Description / SPARQL Query / "
+					+ action.request.getRequestURI());
+			ServletOps.errorNotFound("Service Description: "
+					+ action.request.getRequestURI());
+		}
+
+		// Use of the dataset describing parameters is check later.
+		try {
+			validateParams(action, allParams);
+			validateRequest(action);
+		} catch (ActionErrorException ex) {
+			throw ex;
+		}
+		// Query not yet parsed.
+	}
+
+	/**
+	 * Validate the request after checking HTTP method and HTTP Parameters.
+	 * 
+	 * @param action
+	 *            HTTP Action
+	 */
+	protected abstract void validateRequest(HttpAction action);
+
+	/**
+	 * Helper method for validating request.
+	 * 
+	 * @param request
+	 *            HTTP request
+	 * @param params
+	 *            parameters in a collection of Strings
+	 */
+	protected void validateParams(HttpAction action, Collection<String> params) {
+		HttpServletRequest request = action.request;
+		ContentType ct = FusekiLib.getContentType(request);
+		boolean mustHaveQueryParam = true;
+		if (ct != null) {
+			String incoming = ct.getContentType();
+
+			if (matchContentType(ctSPARQLQuery, ct)) {
+				mustHaveQueryParam = false;
+				// Drop through.
+			} else if (matchContentType(ctHTMLForm, ct)) {
+				// Nothing specific to do
+			} else
+				ServletOps.error(HttpSC.UNSUPPORTED_MEDIA_TYPE_415,
+						"Unsupported: " + incoming);
+		}
+
+		// GET/POST of a form at this point.
+
+		if (mustHaveQueryParam) {
+			int N = countParamOccurences(request, paramQuery);
+
+			if (N == 0)
+				ServletOps
+						.errorBadRequest("SPARQL Query: No 'query=' parameter");
+			if (N > 1)
+				ServletOps
+						.errorBadRequest("SPARQL Query: Multiple 'query=' parameters");
+
+			// application/sparql-query does not use a query param.
+			String queryStr = request.getParameter(HttpNames.paramQuery);
+
+			if (queryStr == null)
+				ServletOps
+						.errorBadRequest("SPARQL Query: No query specified (no 'query=' found)");
+			if (queryStr.isEmpty())
+				ServletOps.errorBadRequest("SPARQL Query: Empty query string");
+		}
+
+		if (params != null) {
+			Enumeration<String> en = request.getParameterNames();
+			for (; en.hasMoreElements();) {
+				String name = en.nextElement();
+				if (!params.contains(name))
+					ServletOps.warning(action,
+							"SPARQL Query: Unrecognize request parameter (ignored): "
+									+ name);
+			}
+		}
+	}
+
+	private void executeWithParameter(HttpAction action) {
+		String queryString = action.request.getParameter(paramQuery);
+		execute(queryString, action);
+	}
+
+	private void executeBody(HttpAction action) {
+		String queryString = null;
+		try {
+			InputStream input = action.request.getInputStream();
+			queryString = IO.readWholeFileAsUTF8(input);
+		} catch (IOException ex) {
+			ServletOps.errorOccurred(ex);
+		}
+		execute(queryString, action);
+	}
+
+	private void execute(String queryString, HttpAction action) {
+		String queryStringLog = ServletOps.formatForLog(queryString);
+		if (action.verbose)
+			action.log
+					.info(format("[%d] Query = \n%s", action.id, queryString));
+		else
+			action.log
+					.info(format("[%d] Query = %s", action.id, queryStringLog));
+
+		Query query = null;
+		try {
+			// NB syntax is ARQ (a superset of SPARQL)
+			query = QueryFactory.create(queryString, QueryParseBase,
+					Syntax.syntaxARQ);
+			queryStringLog = formatForLog(query);
+			validateQuery(action, query);
+		} catch (ActionErrorException ex) {
+			throw ex;
+		} catch (QueryParseException ex) {
+			ServletOps.errorBadRequest("Parse error: \n" + queryString + "\n\r"
+					+ messageForQueryException(ex));
+		}
+		// Should not happen.
+		catch (QueryException ex) {
+			ServletOps.errorBadRequest("Error: \n" + queryString + "\n\r"
+					+ ex.getMessage());
+		}
+
+		// Assumes finished whole thing by end of sendResult.
+		try {
+			action.beginRead();
+			Dataset dataset = decideDataset(action, query, queryStringLog);
+			try (QueryExecution qExec = createQueryExecution(query, dataset);) {
+				SPARQLResult result = executeQuery(action, qExec, query,
+						queryStringLog);
+				// Deals with exceptions itself.
+				sendResults(action, result, query.getPrologue());
+			}
+		} catch (QueryParseException ex) {
+			// Late stage static error (e.g. bad fixed Lucene query string).
+			ServletOps.errorBadRequest("Query parse error: \n" + queryString
+					+ "\n\r" + messageForQueryException(ex));
+		} catch (QueryCancelledException ex) {
+			// Additional counter information.
+			incCounter(action.getEndpoint().getCounters(), QueryTimeouts);
+			throw ex;
+		} finally {
+			action.endRead();
+		}
+	}
+
+	/**
+	 * Check the query - if unacceptable, throw ActionErrorException or call
+	 * super.error
+	 * 
+	 * @param action
+	 *            HTTP Action
+	 * @param query
+	 *            SPARQL Query
+	 */
+	protected abstract void validateQuery(HttpAction action, Query query);
+
+	/**
+	 * Create the {@link QueryExecution} for this operation.
+	 * 
+	 * @param query
+	 * @param dataset
+	 * @return QueryExecution
+	 */
+	protected QueryExecution createQueryExecution(Query query, Dataset dataset) {
+		return QueryExecutionFactory.create(query, dataset);
+	}
+
+	/**
+	 * Perform the {@link QueryExecution} once.
+	 * 
+	 * @param action
+	 * @param queryExecution
+	 * @param query
+	 * @param queryStringLog
+	 *            Informational string created from the initial query.
+	 * @return
+	 */
+	protected SPARQLResult executeQuery(HttpAction action,
+			QueryExecution queryExecution, Query query, String queryStringLog) {
+		setAnyTimeouts(queryExecution, action);
+
+		if (query.isSelectType()) {
+			ResultSet rs = queryExecution.execSelect();
+
+			// Force some query execution now.
+			//
+			// If the timeout-first-row goes off, the output stream has not
+			// been started so the HTTP error code is sent.
+
+			rs.hasNext();
+
+			// If we wanted perfect query time cancellation, we could consume
+			// the result now
+			// to see if the timeout-end-of-query goes off.
+
+			// rs = ResultSetFactory.copyResults(rs) ;
+
+			action.log.info(format("[%d] exec/select", action.id));
+			return new SPARQLResult(rs);
+		}
+
+		if (query.isConstructType()) {
+
+			MediaType rdfMediaType = AcceptList.match( DEF.pureRdfOffer, new AcceptList( WebLib.getAccept(action.getRequest())));
+			
+			if ( ! rdfMediaType.getType().equals("*") ) {
+				Model model = queryExecution.execConstruct();
+				action.log.info(format("[%d] exec/construct/model", action.id));
+				return new SPARQLResult(model);
+			} else  {
+				Dataset dataset = queryExecution.execConstructDataset();
+				action.log
+						.info(format("[%d] exec/construct/dataset", action.id));
+				return new SPARQLResult(dataset);
+			}
+		}
+
+		if (query.isDescribeType()) {
+			Model model = queryExecution.execDescribe();
+			action.log.info(format("[%d] exec/describe", action.id));
+			return new SPARQLResult(model);
+		}
+
+		if (query.isAskType()) {
+			boolean b = queryExecution.execAsk();
+			action.log.info(format("[%d] exec/ask", action.id));
+			return new SPARQLResult(b);
+		}
+
+		ServletOps.errorBadRequest("Unknown query type - " + queryStringLog);
+		return null;
+	}
+
+	private void setAnyTimeouts(QueryExecution qexec, HttpAction action) {
+		// if ( !(action.getDataService().allowTimeoutOverride) )
+		// return ;
+
+		long desiredTimeout = Long.MAX_VALUE;
+		String timeoutHeader = action.request.getHeader("Timeout");
+		String timeoutParameter = action.request.getParameter("timeout");
+		if (timeoutHeader != null) {
+			try {
+				desiredTimeout = (int) (Float.parseFloat(timeoutHeader) * 1000);
+			} catch (NumberFormatException e) {
+				throw new FusekiException("Timeout header must be a number", e);
+			}
+		} else if (timeoutParameter != null) {
+			try {
+				desiredTimeout = (int) (Float.parseFloat(timeoutParameter) * 1000);
+			} catch (NumberFormatException e) {
+				throw new FusekiException("timeout parameter must be a number",
+						e);
+			}
+		}
+
+		// desiredTimeout =
+		// Math.min(action.getDataService().maximumTimeoutOverride,
+		// desiredTimeout) ;
+		if (desiredTimeout != Long.MAX_VALUE)
+			qexec.setTimeout(desiredTimeout);
+	}
+
+	/**
+	 * Choose the dataset for this SPARQL Query request.
+	 * 
+	 * @param action
+	 * @param query
+	 * @param queryStringLog
+	 * @return {@link Dataset}
+	 */
+	protected abstract Dataset decideDataset(HttpAction action, Query query,
+			String queryStringLog);
+
+	/**
+	 * Ship the results to the remote caller.
+	 * 
+	 * @param action
+	 * @param result
+	 * @param qPrologue
+	 */
+	protected void sendResults(HttpAction action, SPARQLResult result,
+			Prologue qPrologue) {
+		if (result.isResultSet())
+			ResponseResultSet.doResponseResultSet(action,
+					result.getResultSet(), qPrologue);
+		else if (result.isGraph()) {
+			ResponseModel.doResponseModel(action, result.getModel());
+		} else if (result.isBoolean())
+			ResponseResultSet.doResponseResultSet(action,
+					result.getBooleanResult());
+		else if (result.isDataset()) {
+			ResponseDataset.doResponseDataset(action, result.getDataset());
+		} else
+			ServletOps.errorOccurred("Unknown or invalid result type");
+	}
+
+	private String formatForLog(Query query) {
+		IndentedLineBuffer out = new IndentedLineBuffer();
+		out.setFlatMode(true);
+		query.serialize(out);
+		return out.asString();
+	}
+
+	private String getRemoteString(String queryURI) {
+		return HttpOp.execHttpGetString(queryURI);
+	}
 
 }

http://git-wip-us.apache.org/repos/asf/jena/blob/0eb28d80/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 2f4d73a..911d105 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
@@ -16,140 +16,136 @@
  * limitations under the License.
  */
 
-package org.apache.jena.fuseki ;
+package org.apache.jena.fuseki;
 
-import static org.apache.jena.fuseki.ServerTest.gn1 ;
-import static org.apache.jena.fuseki.ServerTest.gn2 ;
-import static org.apache.jena.fuseki.ServerTest.model1 ;
-import static org.apache.jena.fuseki.ServerTest.model2 ;
-import static org.apache.jena.fuseki.ServerTest.serviceQuery ;
-import static org.apache.jena.fuseki.ServerTest.serviceREST ;
+import static org.apache.jena.fuseki.ServerTest.gn1;
+import static org.apache.jena.fuseki.ServerTest.model1;
+import static org.apache.jena.fuseki.ServerTest.model2;
+import static org.apache.jena.fuseki.ServerTest.serviceQuery;
+import static org.apache.jena.fuseki.ServerTest.serviceREST;
 
-import java.io.IOException ;
-import java.net.HttpURLConnection ;
-import java.net.URL ;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Iterator;
 
-import org.apache.jena.atlas.junit.BaseTest ;
-import org.apache.jena.graph.Node ;
-import org.apache.jena.query.* ;
-import org.apache.jena.sparql.core.Var ;
-import org.apache.jena.sparql.engine.binding.Binding ;
-import org.apache.jena.sparql.resultset.ResultSetCompare ;
-import org.apache.jena.sparql.sse.Item ;
-import org.apache.jena.sparql.sse.SSE ;
-import org.apache.jena.sparql.sse.builders.BuilderResultSet ;
-import org.apache.jena.sparql.util.Convert ;
-import org.junit.AfterClass ;
-import org.junit.Assert ;
-import org.junit.BeforeClass ;
-import org.junit.Test ;
+import org.apache.jena.atlas.junit.BaseTest;
+import org.apache.jena.graph.Triple;
+import org.apache.jena.query.DatasetAccessor;
+import org.apache.jena.query.DatasetAccessorFactory;
+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.ResultSet;
+import org.apache.jena.query.ResultSetFormatter;
+import org.apache.jena.query.Syntax;
+import org.apache.jena.sparql.core.Quad;
+import org.apache.jena.sparql.core.Var;
+import org.apache.jena.sparql.engine.binding.Binding;
+import org.apache.jena.sparql.resultset.ResultSetCompare;
+import org.apache.jena.sparql.sse.Item;
+import org.apache.jena.sparql.sse.SSE;
+import org.apache.jena.sparql.sse.builders.BuilderResultSet;
+import org.apache.jena.sparql.util.Convert;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
 
-public class TestQuery extends BaseTest {
-    protected static ResultSet rs1 = null ;
+public class TestQuery extends BaseTest 
+{
+    protected static ResultSet rs1 = null ; 
     static {
         Item item = SSE.parseItem("(resultset (?s ?p ?o) (row (?s <x>)(?p <p>)(?o 1)))") ;
         rs1 = BuilderResultSet.build(item) ;
     }
-
-    @BeforeClass
-    public static void beforeClass() {
+    
+    @BeforeClass public static void beforeClass()
+    {
         ServerTest.allocServer() ;
         ServerTest.resetServer() ;
         DatasetAccessor du = DatasetAccessorFactory.createHTTP(serviceREST) ;
         du.putModel(model1) ;
         du.putModel(gn1, model2) ;
     }
-
-    @AfterClass
-    public static void afterClass() {
+    
+    @AfterClass public static void afterClass()
+    {
         DatasetAccessor du = DatasetAccessorFactory.createHTTP(serviceREST) ;
         du.deleteDefault() ;
         ServerTest.freeServer() ;
     }
-
-    @Test
-    public void query_01() {
+    
+    @Test public void query_01()
+    {
         execQuery("SELECT * {?s ?p ?o}", 1) ;
     }
-
-    @Test
-    public void query_recursive_01() {
-        String query = "SELECT * WHERE { SERVICE <" + serviceQuery + "> { ?s ?p ?o . BIND(?o AS ?x) } }" ;
-        try (QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery, query)) {
-            ResultSet rs = qExec.execSelect() ;
-            Var x = Var.alloc("x") ;
+    
+    @Test public void query_recursive_01()
+    {
+        String query = "SELECT * WHERE { SERVICE <" + serviceQuery + "> { ?s ?p ?o . BIND(?o AS ?x) } }";
+        try ( QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery, query) ) {
+            ResultSet rs = qExec.execSelect();
+            Var x = Var.alloc("x");
             while (rs.hasNext()) {
-                Binding b = rs.nextBinding() ;
-                Assert.assertNotNull(b.get(x)) ;
+                Binding b = rs.nextBinding();
+                Assert.assertNotNull(b.get(x));
             }
         }
     }
-
-    @Test
-    public void query_with_params_01() {
-        String query = "ASK { }" ;
-        try (QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery + "?output=json", query)) {
-            boolean result = qExec.execAsk() ;
-            Assert.assertTrue(result) ;
+    
+    @Test public void query_with_params_01()
+    {
+        String query = "ASK { }";
+        try ( QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery + "?output=json", query) ) {
+            boolean result = qExec.execAsk();
+            Assert.assertTrue(result);
         }
     }
+    
+    @Test public void query_construct_quad_01()
+    {
+        String queryString = " CONSTRUCT { GRAPH <http://eg/g> {?s ?p ?oq} } WHERE {?s ?p ?oq}" ;
+        Query query = QueryFactory.create(queryString, Syntax.syntaxARQ);
+               
+        try ( QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery, query) ) {
+            Iterator<Quad> result = qExec.execConstructQuads();
+            Assert.assertTrue(result.hasNext());
+            Assert.assertEquals( "http://eg/g", result.next().getGraph().getURI());
 
-    @Test
-    public void request_id_header_01() throws IOException {
-        String qs = Convert.encWWWForm("ASK{}") ;
-        URL u = new URL(serviceQuery + "?query=" + qs) ;
-        HttpURLConnection conn = (HttpURLConnection)u.openConnection() ;
-        Assert.assertTrue(conn.getHeaderField("Fuseki-Request-ID") != null) ;
-    }
-
-    @Test
-    public void query_dynamic_dataset_01() {
-        DatasetAccessor du = DatasetAccessorFactory.createHTTP(serviceREST) ;
-        du.putModel(model1);
-        du.putModel(gn1, model2);
-        {
-            String query = "SELECT * { ?s ?p ?o }" ;
-            try (QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery + "?output=json", query)) {
-                ResultSet rs = qExec.execSelect() ;
-                Node o = rs.next().getLiteral("o").asNode() ;
-                Node n = SSE.parseNode("1") ;
-                assertEquals(n, o) ;
-            }
-        }
-        {
-
-            String query = "SELECT * FROM <" + gn1 + "> { ?s ?p ?o }" ;
-            try (QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery + "?output=json", query)) {
-                ResultSet rs = qExec.execSelect() ;
-                Node o = rs.next().getLiteral("o").asNode() ;
-                Node n = SSE.parseNode("2") ;
-                assertEquals(n, o) ;
-            }
         }
     }
     
-    @Test
-    public void query_dynamic_dataset_02() {
-        DatasetAccessor du = DatasetAccessorFactory.createHTTP(serviceREST) ;
-        du.putModel(model1);
-        du.putModel(gn1, model1);
-        du.putModel(gn2, model2);
-        String query = "SELECT * FROM <"+gn1+"> FROM <"+gn2+"> { ?s ?p ?o }" ;
-        try (QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery + "?output=json", query)) {
-            ResultSet rs = qExec.execSelect() ;
-            int n = ResultSetFormatter.consume(rs) ;
-            assertEquals(2, n) ;
+    @Test public void query_construct_01()
+    {
+        String query = " CONSTRUCT {?s ?p ?o} WHERE {?s ?p ?o}" ;
+        try ( QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery, query) ) {
+            Iterator<Triple> result = qExec.execConstructTriples();
+            Assert.assertTrue(result.hasNext());
         }
     }
+    
 
-    private void execQuery(String queryString, int exceptedRowCount) {
+    
+    @Test public void request_id_header_01() throws IOException
+    {
+        String qs = Convert.encWWWForm("ASK{}") ;
+        URL u = new URL(serviceQuery+"?query="+qs);
+        HttpURLConnection conn = (HttpURLConnection) u.openConnection();
+        Assert.assertTrue(conn.getHeaderField("Fuseki-Request-ID") != null);
+    }
+
+    private void execQuery(String queryString, int exceptedRowCount)
+    {
         QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery, queryString) ;
         ResultSet rs = qExec.execSelect() ;
         int x = ResultSetFormatter.consume(rs) ;
         assertEquals(exceptedRowCount, x) ;
     }
-
-    private void execQuery(String queryString, ResultSet expectedResultSet) {
+    
+    private void execQuery(String queryString, ResultSet expectedResultSet)
+    {
         QueryExecution qExec = QueryExecutionFactory.sparqlService(serviceQuery, queryString) ;
         ResultSet rs = qExec.execSelect() ;
         boolean b = ResultSetCompare.equalsByTerm(rs, expectedResultSet) ;