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 ;
+ }
+}
+