Author: andy
Date: Wed Nov 13 21:44:25 2013
New Revision: 1541741

URL: http://svn.apache.org/r1541741
Log:
QueryValidator generating JSON response

Added:
    
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/
    
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/QueryValidator.java
    
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidationAction.java
    
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidationError.java
    
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidatorBaseJson.java

Added: 
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/QueryValidator.java
URL: 
http://svn.apache.org/viewvc/jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/QueryValidator.java?rev=1541741&view=auto
==============================================================================
--- 
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/QueryValidator.java
 (added)
+++ 
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/QueryValidator.java
 Wed Nov 13 21:44:25 2013
@@ -0,0 +1,149 @@
+/*
+ * 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.validation2 ;
+
+import org.apache.jena.atlas.io.IndentedLineBuffer ;
+import org.apache.jena.atlas.json.JsonBuilder ;
+import org.apache.jena.atlas.json.JsonObject ;
+
+import com.hp.hpl.jena.query.Query ;
+import com.hp.hpl.jena.query.QueryFactory ;
+import com.hp.hpl.jena.query.QueryParseException ;
+import com.hp.hpl.jena.query.Syntax ;
+import com.hp.hpl.jena.sparql.algebra.Algebra ;
+import com.hp.hpl.jena.sparql.algebra.Op ;
+import com.hp.hpl.jena.sparql.serializer.SerializationContext ;
+
+public class QueryValidator extends ValidatorBaseJson {
+    public QueryValidator() {}
+
+    @Override
+    protected String validatorName() {
+        return "SPARQL Query" ;
+    }
+
+    static final String paramQuery       = "query" ;
+    static final String paramSyntax      = "languageSyntax" ;
+    
+    static final String jInput           = "input" ;
+    
+    static final String jFormatted       = "formatted" ;
+    static final String jAlgebra         = "algebra" ;
+    static final String jAlgebraQuads    = "algebra-quads" ;
+    static final String jAlgebraOpt      = "algebra-opt" ;
+    static final String jAlgebraOptQuads = "algebra-opt-quads" ;
+
+    static final String jParseError      = "parse-error" ;
+    static final String jParseErrorLine  = "parse-error-line" ;
+    static final String jParseErrorCol   = "parse-error-column" ;
+
+    @Override
+    protected JsonObject execute(ValidationAction action) {
+        JsonBuilder obj = new JsonBuilder() ;
+        obj.startObject() ;
+
+        final String queryString = getArg(action, paramQuery) ;
+
+        String querySyntax = getArgOrNull(action, paramSyntax) ;
+        if ( querySyntax == null || querySyntax.equals("") )
+            querySyntax = "SPARQL" ;
+
+        Syntax language = Syntax.lookup(querySyntax) ;
+        if ( language == null ) {
+            errorBadRequest("Unknown syntax: " + querySyntax) ;
+            return null ;
+        }
+
+        boolean outputSPARQL = true ;
+        boolean outputAlgebra = true ;
+        boolean outputQuads = true ;
+        boolean outputOptimized = true ;
+        boolean outputOptimizedQuads = true ;
+
+        obj.key(jInput).value(queryString) ;
+
+        // Attempt to parse it.
+        Query query = null ;
+        try {
+            query = QueryFactory.create(queryString, "http://example/base/";, 
language) ;
+        } catch (QueryParseException ex) {
+            obj.key(jParseError).value(ex.getMessage()) ;
+            obj.key(jParseErrorLine).value(ex.getLine()) ;
+            obj.key(jParseErrorCol).value(ex.getColumn()) ;
+        }
+
+        if ( query != null ) {
+            
+            if ( outputSPARQL )
+                formatted(obj, query) ;
+
+            if ( outputAlgebra )
+                algebra(obj, query) ;
+
+            if ( outputQuads )
+                algebraQuads(obj, query) ;
+
+            if ( outputOptimized )
+                algebraOpt(obj, query) ;
+
+            if ( outputOptimizedQuads )
+                algebraOptQuads(obj, query) ;
+        }
+        
+        obj.finishObject() ;
+        return obj.build().getAsObject() ;
+    }
+
+    private void formatted(JsonBuilder obj, Query query) {
+        IndentedLineBuffer out = new IndentedLineBuffer() ;
+        query.serialize(out) ;
+        obj.key(jFormatted).value(out.asString()) ;
+    }
+
+    private void algebra(JsonBuilder obj, Query query) {
+        Op op = Algebra.compile(query) ;
+        obj.key(jAlgebra).value(string(query, op)) ;
+    }
+
+    private void algebraQuads(JsonBuilder obj, Query query) {
+        Op op = Algebra.compile(query) ;
+        op = Algebra.toQuadForm(op) ;
+        obj.key(jAlgebraQuads).value(string(query, op)) ;
+    }
+
+    private void algebraOpt(JsonBuilder obj, Query query) {
+        Op op = Algebra.compile(query) ;
+        op = Algebra.optimize(op) ;
+        obj.key(jAlgebraOpt).value(string(query, op)) ;
+    }
+
+    private void algebraOptQuads(JsonBuilder obj, Query query) {
+        Op op = Algebra.compile(query) ;
+        op = Algebra.toQuadForm(op) ;
+        op = Algebra.optimize(op) ;
+        obj.key(jAlgebraOptQuads).value(string(query, op)) ;
+    }
+
+    private String string(Query query, Op op) {
+        final SerializationContext sCxt = new SerializationContext(query) ;
+        IndentedLineBuffer out = new IndentedLineBuffer() ;
+        op.output(out, sCxt) ;
+        return out.asString() ;
+    }
+}

Added: 
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidationAction.java
URL: 
http://svn.apache.org/viewvc/jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidationAction.java?rev=1541741&view=auto
==============================================================================
--- 
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidationAction.java
 (added)
+++ 
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidationAction.java
 Wed Nov 13 21:44:25 2013
@@ -0,0 +1,92 @@
+/*
+ * 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.validation2;
+
+import java.util.HashMap ;
+import java.util.Map ;
+
+import javax.servlet.http.HttpServletRequest ;
+import javax.servlet.http.HttpServletResponse ;
+
+import org.apache.jena.atlas.logging.Log ;
+
+public class ValidationAction
+{
+    public final boolean verbose ;
+    public final long id ;
+    private boolean startTimeIsSet = false ;
+    private boolean finishTimeIsSet = false ;
+
+    private long startTime = -2 ;
+    private long finishTime = -2 ;
+    
+    // Outcome.
+    int statusCode = -1 ;
+    String message = null ;
+    int contentLength = -1 ;
+    String contentType = null ;
+    
+    Map <String, String> headers = new HashMap<String, String>() ;
+    public HttpServletRequest request;
+    public HttpServletResponse response ;
+    
+    public ValidationAction(long id, HttpServletRequest request, 
HttpServletResponse response, boolean verbose) {
+        this.id = id ;
+        this.request = request ;
+        this.response = response ;
+        this.verbose = false ;
+    }
+
+    /** Reduce to a size that can be kept around for sometime */
+    public void minimize() {
+        this.request = null ;
+        this.response = null ;
+    }
+
+    public void setStartTime() {
+        if ( startTimeIsSet ) 
+            Log.warn(this,  "Start time reset") ;
+        startTimeIsSet = true ;
+        this.startTime = System.nanoTime() ;
+    }
+
+    public void setFinishTime() {
+        if ( finishTimeIsSet ) 
+            Log.warn(this,  "Finish time reset") ;
+        finishTimeIsSet = true ;
+        this.finishTime = System.nanoTime() ;
+    }
+
+    public HttpServletRequest getRequest()          { return request ; }
+
+    public HttpServletResponse getResponse()        { return response ; }
+    
+    /** Return the recorded time taken in milliseconds. 
+     *  {@linkplain #setStartTime} and {@linkplain #setFinishTime}
+     *  must have been called.
+     */
+    public long getTime()
+    {
+        if ( ! startTimeIsSet ) 
+            Log.warn(this,  "Start time not set") ;
+        if ( ! finishTimeIsSet ) 
+            Log.warn(this,  "Finish time not set") ;
+        return (finishTime-startTime)/(1000*1000) ;
+    }
+}

Added: 
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidationError.java
URL: 
http://svn.apache.org/viewvc/jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidationError.java?rev=1541741&view=auto
==============================================================================
--- 
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidationError.java
 (added)
+++ 
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidationError.java
 Wed Nov 13 21:44:25 2013
@@ -0,0 +1,24 @@
+/**
+ * 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.validation2;
+
+public class ValidationError {
+
+}
+

Added: 
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidatorBaseJson.java
URL: 
http://svn.apache.org/viewvc/jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidatorBaseJson.java?rev=1541741&view=auto
==============================================================================
--- 
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidatorBaseJson.java
 (added)
+++ 
jena/branches/jena-fuseki-new-ui/src/main/java/org/apache/jena/fuseki/validation2/ValidatorBaseJson.java
 Wed Nov 13 21:44:25 2013
@@ -0,0 +1,193 @@
+/*
+ * 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.validation2;
+
+import static java.lang.String.format ;
+
+import java.io.OutputStream ;
+import java.util.Enumeration ;
+
+import javax.servlet.http.HttpServletRequest ;
+import javax.servlet.http.HttpServletResponse ;
+
+import org.apache.jena.atlas.json.JSON ;
+import org.apache.jena.atlas.json.JsonObject ;
+import org.apache.jena.fuseki.Fuseki ;
+import org.apache.jena.fuseki.HttpNames ;
+import org.apache.jena.fuseki.servlets.ActionErrorException ;
+import org.apache.jena.fuseki.servlets.ServletBase ;
+import org.apache.jena.riot.WebContent ;
+import org.apache.jena.web.HttpSC ;
+import org.slf4j.Logger ;
+
+import com.hp.hpl.jena.query.ARQ ;
+import com.hp.hpl.jena.sparql.util.Context ;
+
+/** ValidationBase for JSON out */ 
+public abstract class ValidatorBaseJson extends ServletBase
+{
+    protected static Logger serviceLog = Fuseki.requestLog ;
+    public static final String respService      = "X-Service" ;
+    
+    @Override
+    public void doGet(HttpServletRequest httpRequest, HttpServletResponse 
httpResponse)
+    { execute(httpRequest, httpResponse) ; }
+
+    @Override
+    public void doPost(HttpServletRequest httpRequest, HttpServletResponse 
httpResponse)
+    { execute(httpRequest, httpResponse) ; }
+    
+    protected void execute(HttpServletRequest request, HttpServletResponse 
response) {
+        long id = allocRequestId(request, response) ;
+        ValidationAction action = new ValidationAction(id, request, response, 
false) ;
+        printRequest(action) ;
+        action.setStartTime() ;
+        
+        response = action.response ;
+        initResponse(request, response) ;
+        Context cxt = ARQ.getContext() ;
+        
+        try {
+            JsonObject obj = execute(action) ;
+            action.statusCode = HttpSC.OK_200 ;
+            action.message = "OK" ;
+            response.setCharacterEncoding(WebContent.charsetUTF8);
+            response.setContentType(WebContent.contentTypeJSON);
+            //response.setContentType(WebContent.contentTypeTextPlain);
+            action.response.setStatus(HttpSC.OK_200) ;
+            OutputStream out = response.getOutputStream() ; 
+            JSON.write(out, obj);
+        } catch (ActionErrorException ex) {
+            if ( ex.exception != null )
+                ex.exception.printStackTrace(System.err) ;
+            if ( ex.message != null )
+                responseSendError(response, ex.rc, ex.message) ;
+            else
+                responseSendError(response, ex.rc) ;
+            //(null, string, statusCode) ;
+        } catch (Throwable th) {
+            responseSendError(response, HttpSC.INTERNAL_SERVER_ERROR_500, 
"Internal Error") ;
+        }
+        action.setFinishTime() ;
+        printResponse(action) ;
+    }
+    
+    private void initResponse(HttpServletRequest request, HttpServletResponse 
response)
+    {
+        setCommonHeaders(response) ;
+        String method = request.getMethod() ;
+        // All GET and HEAD operations are sensitive to conneg so ...
+        if ( HttpNames.METHOD_GET.equalsIgnoreCase(method) || 
HttpNames.METHOD_HEAD.equalsIgnoreCase(method) )
+            setVaryHeader(response) ;
+    }
+    
+    private void printRequest(ValidationAction action)
+    {
+        String url = wholeRequestURL(action.request) ;
+        String method = action.request.getMethod() ;
+
+        log.info(format("[%d] %s %s", action.id, method, url)) ;
+        if ( action.verbose ) {
+            Enumeration<String> en = action.request.getHeaderNames() ;
+            for (; en.hasMoreElements();) {
+                String h = en.nextElement() ;
+                Enumeration<String> vals = action.request.getHeaders(h) ;
+                if (!vals.hasMoreElements())
+                    log.info(format("[%d]   ", action.id, h)) ;
+                else {
+                    for (; vals.hasMoreElements();)
+                        log.info(format("[%d]   %-20s %s", action.id, h, 
vals.nextElement())) ;
+                }
+            }
+        }
+    }
+    
+    private void printResponse(ValidationAction action)
+    {
+        long time = action.getTime() ;
+        
+        HttpServletResponse response = action.response ;
+        if ( action.verbose )
+        {
+//            if ( action.contentType != null )
+//                log.info(format("[%d]   %-20s %s", action.id, 
HttpNames.hContentType, action.contentType)) ;
+//            if ( action.contentLength != -1 )
+//                log.info(format("[%d]   %-20s %d", action.id, 
HttpNames.hContentLengh, action.contentLength)) ;
+//            for ( Map.Entry<String, String> e: action.headers.entrySet() )
+//                log.info(format("[%d]   %-20s %s", action.id, e.getKey(), 
e.getValue())) ;
+        }
+
+        String timeStr = fmtMillis(time) ;
+
+        if ( action.message == null )
+            log.info(String.format("[%d] %d %s (%s) ", action.id, 
action.statusCode, HttpSC.getMessage(action.statusCode), timeStr)) ;
+        else
+            log.info(String.format("[%d] %d %s (%s) ", action.id, 
action.statusCode, action.message, timeStr)) ;
+    }
+    
+    private static String fmtMillis(long time)
+    {
+        // Millis only? seconds only?
+        if ( time < 1000 )
+            return String.format("%,d ms", time) ;
+        return String.format("%,.3f s", time/1000.0) ;
+    }
+    
+    protected abstract JsonObject execute(ValidationAction action) ;
+    
+    protected abstract String validatorName() ;
+
+    protected void setHeaders(HttpServletResponse httpResponse)
+    {
+        httpResponse.setCharacterEncoding(WebContent.charsetUTF8) ;
+        httpResponse.setContentType(WebContent.contentTypeJSON) ;
+        httpResponse.setHeader(respService, "Jena Fuseki Validator / 
"+validatorName()+": http://jena.apache.org/";) ;
+    }
+
+    protected static String getArg(ValidationAction action, String paramName) {
+        String arg = getArgOrNull(action, paramName) ;
+        if ( arg == null ) {
+            error(HttpSC.BAD_REQUEST_400, "No parameter given: " + paramName) ;
+            return null ;
+        }
+        return arg ;
+    }
+
+    protected static String getArgOrNull(ValidationAction action, String 
paramName) {
+        String[] args = getArgs(action, paramName) ;
+
+        if ( args == null || args.length == 0 )
+            return null ;
+
+        if ( args.length > 1 ) {
+            error(HttpSC.BAD_REQUEST_400, "Too many ("+args.length+") 
parameter values: "+paramName) ;
+            return null ;
+        }
+        
+        return args[0] ;
+    }
+    
+    protected static String[] getArgs(ValidationAction action, String 
paramName) {
+        String[] args = action.request.getParameterValues(paramName) ;
+        if ( args == null || args.length == 0 )
+            return null ;
+        return args ;
+    }
+}    
+


Reply via email to