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/01/05 18:34:22 UTC
[43/51] [abbrv] [partial] jena git commit: Maven modules for Fuseki2
http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads.java
new file mode 100644
index 0000000..578447e
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads.java
@@ -0,0 +1,68 @@
+/**
+ * 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 ;
+
+
+/**
+ * Servlet for operations directly on a dataset - REST(ish) behaviour on the
+ * dataset URI.
+ */
+
+public abstract class REST_Quads extends SPARQL_GSP {
+ // Not supported: GSP direct naming.
+
+ public REST_Quads() {
+ super() ;
+ }
+
+ @Override
+ protected void validate(HttpAction action) {
+ // Check in the operations itself.
+ }
+
+ @Override
+ protected void doOptions(HttpAction action) {
+ ServletOps.errorMethodNotAllowed("OPTIONS") ;
+ }
+
+ @Override
+ protected void doHead(HttpAction action) {
+ ServletOps.errorMethodNotAllowed("HEAD") ;
+ }
+
+ @Override
+ protected void doPost(HttpAction action) {
+ ServletOps.errorMethodNotAllowed("POST") ;
+ }
+
+ @Override
+ protected void doPut(HttpAction action) {
+ ServletOps.errorMethodNotAllowed("PUT") ;
+ }
+
+ @Override
+ protected void doDelete(HttpAction action) {
+ ServletOps.errorMethodNotAllowed("DELETE") ;
+ }
+
+ @Override
+ protected void doPatch(HttpAction action) {
+ ServletOps.errorMethodNotAllowed("PATCH") ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_R.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_R.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_R.java
new file mode 100644
index 0000000..ca25b06
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_R.java
@@ -0,0 +1,99 @@
+/**
+ * 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 javax.servlet.ServletOutputStream ;
+
+import org.apache.jena.atlas.web.MediaType ;
+import org.apache.jena.atlas.web.TypedOutputStream ;
+import org.apache.jena.riot.web.HttpNames ;
+import org.apache.jena.riot.* ;
+
+import com.hp.hpl.jena.sparql.core.DatasetGraph ;
+
+/**
+ * Servlet for operations directly on a dataset - REST(ish) behaviour on the
+ * dataset URI.
+ */
+
+public class REST_Quads_R extends REST_Quads {
+ public REST_Quads_R() {
+ super() ;
+ }
+
+ @Override
+ protected void validate(HttpAction action) { }
+
+ @Override
+ protected void doGet(HttpAction action) {
+ MediaType mediaType = ActionLib.contentNegotationQuads(action) ;
+ ServletOutputStream output ;
+ try {
+ output = action.response.getOutputStream() ;
+ } catch (IOException ex) {
+ ServletOps.errorOccurred(ex) ;
+ output = null ;
+ }
+
+ TypedOutputStream out = new TypedOutputStream(output, mediaType) ;
+ Lang lang = RDFLanguages.contentTypeToLang(mediaType.getContentType()) ;
+ if ( lang == null )
+ lang = RDFLanguages.TRIG ;
+
+ if ( action.verbose )
+ action.log.info(format("[%d] Get: Content-Type=%s, Charset=%s => %s", action.id,
+ mediaType.getContentType(), mediaType.getCharset(), lang.getName())) ;
+ if ( !RDFLanguages.isQuads(lang) )
+ ServletOps.errorBadRequest("Not a quads format: " + mediaType) ;
+
+ action.beginRead() ;
+ try {
+ DatasetGraph dsg = action.getActiveDSG() ;
+ action.response.setHeader("Content-type", lang.getContentType().toHeaderString());
+ RDFFormat fmt =
+ ( lang == Lang.RDFXML ) ? RDFFormat.RDFXML_PLAIN : RDFWriterRegistry.defaultSerialization(lang) ;
+ RDFDataMgr.write(out, dsg, fmt) ;
+ ServletOps.success(action) ;
+ } finally {
+ action.endRead() ;
+ }
+ }
+
+ @Override
+ protected void doOptions(HttpAction action) {
+ action.response.setHeader(HttpNames.hAllow, "GET, HEAD, OPTIONS") ;
+ action.response.setHeader(HttpNames.hContentLengh, "0") ;
+ ServletOps.success(action) ;
+ }
+
+ @Override
+ protected void doHead(HttpAction action) {
+ action.beginRead() ;
+ try {
+ MediaType mediaType = ActionLib.contentNegotationQuads(action) ;
+ ServletOps.success(action) ;
+ } finally {
+ action.endRead() ;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_RW.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_RW.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_RW.java
new file mode 100644
index 0000000..dfc87ab
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_RW.java
@@ -0,0 +1,136 @@
+/**
+ * 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 org.apache.jena.fuseki.FusekiLib ;
+import org.apache.jena.riot.RiotException ;
+import org.apache.jena.riot.system.StreamRDF ;
+import org.apache.jena.riot.system.StreamRDFLib ;
+
+import com.hp.hpl.jena.sparql.core.DatasetGraph ;
+import com.hp.hpl.jena.sparql.core.DatasetGraphFactory ;
+
+/**
+ * Servlet for operations directly on a dataset - REST(ish) behaviour on the
+ * dataset URI.
+ */
+
+public class REST_Quads_RW extends REST_Quads_R {
+
+ public REST_Quads_RW() {
+ super() ;
+ }
+
+ @Override
+ protected void validate(HttpAction action) { }
+
+ @Override
+ protected void doPost(HttpAction action) {
+ if ( !action.getDataService().allowUpdate() )
+ ServletOps.errorMethodNotAllowed("POST") ;
+
+ if ( action.isTransactional() )
+ doPutPostTxn(action, false) ;
+ else
+ doPutPostNonTxn(action, false) ;
+ }
+
+ @Override
+ protected void doPut(HttpAction action) {
+ if ( !action.getDataService().allowUpdate() )
+ ServletOps.errorMethodNotAllowed("POST") ;
+
+ if ( action.isTransactional() )
+ doPutPostTxn(action, true) ;
+ else
+ doPutPostNonTxn(action, true) ;
+ }
+
+ // These are very similar to SPARQL_REST_RW.addDataIntoTxn/nonTxn
+ // Maybe can be usually DRYed.
+
+ @Override
+ protected void doDelete(HttpAction action) {
+ ServletOps.errorMethodNotAllowed("DELETE") ;
+ }
+
+ @Override
+ protected void doPatch(HttpAction action) {
+ ServletOps.errorMethodNotAllowed("PATCH") ;
+ }
+
+ private void doPutPostTxn(HttpAction action, boolean clearFirst) {
+ UploadDetails details = null ;
+ action.beginWrite() ;
+ try {
+ DatasetGraph dsg = action.getActiveDSG() ;
+ if ( clearFirst )
+ dsg.clear() ;
+ StreamRDF dest = StreamRDFLib.dataset(dsg) ;
+ details = Upload.incomingData(action, dest) ;
+ action.commit() ;
+ ServletOps.success(action) ;
+ } catch (RiotException ex) {
+ // Parse error
+ action.abort() ;
+ ServletOps.errorBadRequest(ex.getMessage()) ;
+ } catch (Exception ex) {
+ // Something else went wrong. Backout.
+ action.abort() ;
+ ServletOps.errorOccurred(ex.getMessage()) ;
+ } finally {
+ action.endWrite() ;
+ }
+ ServletOps.uploadResponse(action, details) ;
+ }
+
+ private void doPutPostNonTxn(HttpAction action, boolean clearFirst) {
+ DatasetGraph dsgTmp = DatasetGraphFactory.createMem() ;
+ StreamRDF dest = StreamRDFLib.dataset(dsgTmp) ;
+
+ UploadDetails details ;
+ try {
+ details = Upload.incomingData(action, dest) ;
+ } catch (RiotException ex) {
+ ServletOps.errorBadRequest(ex.getMessage()) ;
+ return ;
+ }
+ // Now insert into dataset
+ action.beginWrite() ;
+ try {
+ DatasetGraph dsg = action.getActiveDSG() ;
+ if ( clearFirst )
+ dsg.clear() ;
+ FusekiLib.addDataInto(dsgTmp, dsg) ;
+ action.commit() ;
+ ServletOps.success(action) ;
+ } catch (Exception ex) {
+ // We're in the non-transactional branch, this probably will not
+ // work
+ // but it might and there is no harm safely trying.
+ try {
+ action.abort() ;
+ } catch (Exception ex2) {}
+ ServletOps.errorOccurred(ex.getMessage()) ;
+ } finally {
+ action.endWrite() ;
+ }
+ ServletOps.uploadResponse(action, details) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseCallback.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseCallback.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseCallback.java
new file mode 100644
index 0000000..1a78627
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseCallback.java
@@ -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.servlets ;
+
+public interface ResponseCallback
+{
+ public void callback(boolean successfulOperation) ;
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseModel.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseModel.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseModel.java
new file mode 100644
index 0000000..65eb1e5
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseModel.java
@@ -0,0 +1,136 @@
+/*
+ * 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 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.riot.Lang ;
+import org.apache.jena.riot.RDFDataMgr ;
+import org.apache.jena.riot.RDFLanguages ;
+import static org.apache.jena.riot.WebContent.* ;
+import org.apache.jena.web.HttpSC ;
+
+import com.hp.hpl.jena.rdf.model.Model ;
+
+public class ResponseModel
+{
+ // Short names for "output="
+ private static final String contentOutputJSONLD = "json-ld" ;
+ private static final String contentOutputJSONRDF = "json-rdf" ;
+ private static final String contentOutputJSON = "json" ;
+ private static final String contentOutputXML = "xml" ;
+ private static final String contentOutputText = "text" ;
+ private static final String contentOutputTTL = "ttl" ;
+ private static final String contentOutputNT = "nt" ;
+
+ public static Map<String,String> shortNamesModel = new HashMap<String, String>() ;
+ static {
+
+ // Some short names. keys are lowercase.
+ ResponseOps.put(shortNamesModel, contentOutputJSONLD, contentTypeJSONLD) ;
+ ResponseOps.put(shortNamesModel, contentOutputJSONRDF, contentTypeRDFJSON) ;
+ ResponseOps.put(shortNamesModel, contentOutputJSON, contentTypeJSONLD) ;
+ ResponseOps.put(shortNamesModel, contentOutputXML, contentTypeRDFXML) ;
+ ResponseOps.put(shortNamesModel, contentOutputText, contentTypeTurtle) ;
+ ResponseOps.put(shortNamesModel, contentOutputTTL, contentTypeTurtle) ;
+ ResponseOps.put(shortNamesModel, contentOutputNT, contentTypeNTriples) ;
+ }
+
+ public static void doResponseModel(HttpAction action, Model model)
+ {
+ HttpServletRequest request = action.request ;
+ HttpServletResponse response = action.response ;
+
+ String mimeType = null ; // Header request type
+
+ // TODO Use MediaType throughout.
+ MediaType i = ConNeg.chooseContentType(request, DEF.rdfOffer, DEF.acceptRDFXML) ;
+ 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, model, 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/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseOps.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseOps.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseOps.java
new file mode 100644
index 0000000..8a3a1c9
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseOps.java
@@ -0,0 +1,94 @@
+/*
+ * 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 java.io.IOException ;
+import java.util.Locale ;
+import java.util.Map ;
+
+import javax.servlet.http.HttpServletRequest ;
+
+import org.apache.jena.riot.web.HttpNames ;
+
+public class ResponseOps
+{
+ // Helpers
+ public static void put(Map<String, String> map, String key, String value)
+ {
+ map.put(key.toLowerCase(Locale.ROOT), value) ;
+ }
+
+ public static boolean isEOFexception(IOException ioEx)
+ {
+ if ( ioEx.getClass().getName().equals("org.mortbay.jetty.EofException eofEx") )
+ return true ;
+ if ( ioEx instanceof java.io.EOFException )
+ return true ;
+ return false ;
+ }
+
+ public static String paramForceAccept(HttpServletRequest request)
+ {
+ String x = fetchParam(request, HttpNames.paramForceAccept) ;
+ return x ;
+ }
+
+ public static String paramStylesheet(HttpServletRequest request)
+ { return fetchParam(request, HttpNames.paramStyleSheet) ; }
+
+ public static String paramOutput(HttpServletRequest request, Map<String,String> map)
+ {
+ // Two names.
+ String x = fetchParam(request, HttpNames.paramOutput1) ;
+ if ( x == null )
+ x = fetchParam(request, HttpNames.paramOutput2) ;
+ return expandShortName(x, map) ;
+ }
+
+ public static String expandShortName(String str, Map<String,String> map)
+ {
+ if ( str == null )
+ return null ;
+ // Force keys to lower case. See put() above.
+ String key = str.toLowerCase(Locale.ROOT) ;
+ String str2 = map.get(key) ;
+ if ( str2 == null )
+ return str ;
+ return str2 ;
+ }
+
+ public static String paramCallback(HttpServletRequest request)
+ {
+ return fetchParam(request, HttpNames.paramCallback) ;
+ }
+
+ public static String fetchParam(HttpServletRequest request, String parameterName)
+ {
+ String value = request.getParameter(parameterName) ;
+ if ( value != null )
+ {
+ value = value.trim() ;
+ if ( value.length() == 0 )
+ value = null ;
+ }
+ return value ;
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java
new file mode 100644
index 0000000..f87e56b
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java
@@ -0,0 +1,322 @@
+/*
+ * 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 static org.apache.jena.atlas.lib.Lib.equal ;
+import static org.apache.jena.riot.WebContent.charsetUTF8 ;
+import static org.apache.jena.riot.WebContent.contentTypeRDFXML ;
+import static org.apache.jena.riot.WebContent.contentTypeResultsJSON ;
+import static org.apache.jena.riot.WebContent.contentTypeResultsThrift ;
+import static org.apache.jena.riot.WebContent.contentTypeResultsXML ;
+import static org.apache.jena.riot.WebContent.contentTypeTextCSV ;
+import static org.apache.jena.riot.WebContent.contentTypeTextPlain ;
+import static org.apache.jena.riot.WebContent.contentTypeTextTSV ;
+import static org.apache.jena.riot.WebContent.contentTypeXML ;
+
+import java.io.IOException ;
+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.io.IO ;
+import org.apache.jena.atlas.web.AcceptList ;
+import org.apache.jena.atlas.web.MediaType ;
+import org.apache.jena.fuseki.DEF ;
+import org.apache.jena.fuseki.FusekiException ;
+import org.apache.jena.fuseki.conneg.ConNeg ;
+import org.apache.jena.riot.ResultSetMgr ;
+import org.apache.jena.riot.WebContent ;
+import org.apache.jena.riot.resultset.ResultSetLang ;
+import org.apache.jena.web.HttpSC ;
+import org.slf4j.Logger ;
+import org.slf4j.LoggerFactory ;
+
+import com.hp.hpl.jena.query.QueryCancelledException ;
+import com.hp.hpl.jena.query.ResultSet ;
+import com.hp.hpl.jena.query.ResultSetFormatter ;
+import com.hp.hpl.jena.sparql.core.Prologue ;
+
+/** This is the content negotiation for each kind of SPARQL query result */
+public class ResponseResultSet
+{
+ private static Logger xlog = LoggerFactory.getLogger(ResponseResultSet.class) ;
+
+ // Short names for "output="
+ private static final String contentOutputJSON = "json" ;
+ private static final String contentOutputXML = "xml" ;
+ private static final String contentOutputSPARQL = "sparql" ;
+ private static final String contentOutputText = "text" ;
+ private static final String contentOutputCSV = "csv" ;
+ private static final String contentOutputTSV = "tsv" ;
+ private static final String contentOutputThrift = "thrift" ;
+
+ public static Map<String,String> shortNamesResultSet = new HashMap<>() ;
+ static {
+ // Some short names. keys are lowercase.
+ ResponseOps.put(shortNamesResultSet, contentOutputJSON, contentTypeResultsJSON) ;
+ ResponseOps.put(shortNamesResultSet, contentOutputSPARQL, contentTypeResultsXML) ;
+ ResponseOps.put(shortNamesResultSet, contentOutputXML, contentTypeResultsXML) ;
+ ResponseOps.put(shortNamesResultSet, contentOutputText, contentTypeTextPlain) ;
+ ResponseOps.put(shortNamesResultSet, contentOutputCSV, contentTypeTextCSV) ;
+ ResponseOps.put(shortNamesResultSet, contentOutputTSV, contentTypeTextTSV) ;
+ ResponseOps.put(shortNamesResultSet, contentOutputThrift, contentTypeResultsThrift) ;
+ }
+
+ interface OutputContent { void output(ServletOutputStream out) ; }
+
+ public static void doResponseResultSet(HttpAction action, Boolean booleanResult)
+ {
+ doResponseResultSet$(action, null, booleanResult, null, DEF.rsOfferBoolean) ;
+ }
+
+ public static void doResponseResultSet(HttpAction action, ResultSet resultSet, Prologue qPrologue)
+ {
+ doResponseResultSet$(action, resultSet, null, qPrologue, DEF.rsOfferTable) ;
+ }
+
+ // If we refactor the conneg into a single function, we can split boolean and result set handling.
+
+ // One or the other argument must be null
+ private static void doResponseResultSet$(HttpAction action,
+ ResultSet resultSet, Boolean booleanResult,
+ Prologue qPrologue,
+ AcceptList contentTypeOffer)
+ {
+ HttpServletRequest request = action.request ;
+ HttpServletResponse response = action.response ;
+ long id = action.id ;
+
+ if ( resultSet == null && booleanResult == null )
+ {
+ xlog.warn("doResponseResult: Both result set and boolean result are null") ;
+ throw new FusekiException("Both result set and boolean result are null") ;
+ }
+
+ if ( resultSet != null && booleanResult != null )
+ {
+ xlog.warn("doResponseResult: Both result set and boolean result are set") ;
+ throw new FusekiException("Both result set and boolean result are set") ;
+ }
+
+ String mimeType = null ;
+ MediaType i = ConNeg.chooseContentType(request, contentTypeOffer, DEF.acceptRSXML) ;
+ if ( i != null )
+ mimeType = i.getContentType() ;
+
+ // Override content type
+ // Does &output= override?
+ // Requested output type by the web form or &output= in the request.
+ String outputField = ResponseOps.paramOutput(request, shortNamesResultSet) ; // Expands short names
+ if ( outputField != null )
+ mimeType = outputField ;
+
+ String serializationType = mimeType ; // Choose the serializer based on this.
+ String contentType = mimeType ; // Set the HTTP respose header to this.
+
+ // Stylesheet - change to application/xml.
+ final String stylesheetURL = ResponseOps.paramStylesheet(request) ;
+ if ( stylesheetURL != null && equal(serializationType,contentTypeResultsXML) )
+ contentType = contentTypeXML ;
+
+ // Force to text/plain?
+ String forceAccept = ResponseOps.paramForceAccept(request) ;
+ if ( forceAccept != null )
+ contentType = contentTypeTextPlain ;
+
+ // Better : dispatch on MediaType
+ if ( equal(serializationType, contentTypeResultsXML) )
+ sparqlXMLOutput(action, contentType, resultSet, stylesheetURL, booleanResult) ;
+ else if ( equal(serializationType, contentTypeResultsJSON) )
+ jsonOutput(action, contentType, resultSet, booleanResult) ;
+ else if ( equal(serializationType, contentTypeTextPlain) )
+ textOutput(action, contentType, resultSet, qPrologue, booleanResult) ;
+ else if ( equal(serializationType, contentTypeTextCSV) )
+ csvOutput(action, contentType, resultSet, booleanResult) ;
+ else if (equal(serializationType, contentTypeTextTSV) )
+ tsvOutput(action, contentType, resultSet, booleanResult) ;
+ else if (equal(serializationType, WebContent.contentTypeResultsThrift) )
+ thriftOutput(action, contentType, resultSet, booleanResult) ;
+ else
+ ServletOps.errorBadRequest("Can't determine output serialization: "+serializationType) ;
+ }
+
+
+ public static void setHttpResponse(HttpAction action,
+// HttpServletRequest httpRequest,
+// HttpServletResponse httpResponse,
+ String contentType, String charset)
+ {
+ // ---- Set up HTTP Response
+ // Stop caching (not that ?queryString URLs are cached anyway)
+ if ( true )
+ ServletOps.setNoCache(action) ;
+ // See: http://www.w3.org/International/O-HTTP-charset.html
+ if ( contentType != null )
+ {
+ if ( charset != null && ! isXML(contentType) )
+ contentType = contentType+"; charset="+charset ;
+ action.log.trace("Content-Type for response: "+contentType) ;
+ action.response.setContentType(contentType) ;
+ }
+ }
+
+ private static boolean isXML(String contentType)
+ {
+ return contentType.equals(contentTypeRDFXML)
+ || contentType.equals(contentTypeResultsXML)
+ || contentType.equals(contentTypeXML) ;
+ }
+
+ private static void sparqlXMLOutput(HttpAction action, String contentType, final ResultSet resultSet, final String stylesheetURL, final Boolean booleanResult)
+ {
+ OutputContent proc =
+ new OutputContent(){
+ @Override
+ public void output(ServletOutputStream out)
+ {
+ if ( resultSet != null )
+ ResultSetFormatter.outputAsXML(out, resultSet, stylesheetURL) ;
+ if ( booleanResult != null )
+ ResultSetFormatter.outputAsXML(out, booleanResult.booleanValue(), stylesheetURL) ;
+ }} ;
+ output(action, contentType, null, proc) ;
+ }
+
+ private static void jsonOutput(HttpAction action, String contentType, final ResultSet resultSet, final Boolean booleanResult)
+ {
+ OutputContent proc = new OutputContent(){
+ @Override
+ public void output(ServletOutputStream out)
+ {
+ if ( resultSet != null )
+ ResultSetFormatter.outputAsJSON(out, resultSet) ;
+ if ( booleanResult != null )
+ ResultSetFormatter.outputAsJSON(out, booleanResult.booleanValue()) ;
+ }
+ } ;
+
+ try {
+ String callback = ResponseOps.paramCallback(action.request) ;
+ ServletOutputStream out = action.response.getOutputStream() ;
+
+ if ( callback != null )
+ {
+ callback = callback.replace("\r", "") ;
+ callback = callback.replace("\n", "") ;
+ out.print(callback) ;
+ out.println("(") ;
+ }
+
+ output(action, contentType, charsetUTF8, proc) ;
+
+ if ( callback != null )
+ out.println(")") ;
+ } catch (IOException ex) { IO.exception(ex) ; }
+ }
+
+ private static void textOutput(HttpAction action, String contentType, final ResultSet resultSet, final Prologue qPrologue, final Boolean booleanResult)
+ {
+ // Text is not streaming.
+ OutputContent proc = new OutputContent(){
+ @Override
+ public void output(ServletOutputStream out)
+ {
+ if ( resultSet != null )
+ ResultSetFormatter.out(out, resultSet, qPrologue) ;
+ if ( booleanResult != null )
+ ResultSetFormatter.out(out, booleanResult.booleanValue()) ;
+ }
+ };
+
+ output(action, contentType, charsetUTF8, proc) ;
+ }
+
+ private static void csvOutput(HttpAction action, String contentType, final ResultSet resultSet, final Boolean booleanResult) {
+ OutputContent proc = new OutputContent(){
+ @Override
+ public void output(ServletOutputStream out)
+ {
+ if ( resultSet != null )
+ ResultSetFormatter.outputAsCSV(out, resultSet) ;
+ if ( booleanResult != null )
+ ResultSetFormatter.outputAsCSV(out, booleanResult.booleanValue()) ;
+ }
+ } ;
+ output(action, contentType, charsetUTF8, proc) ;
+ }
+
+ private static void tsvOutput(HttpAction action, String contentType, final ResultSet resultSet, final Boolean booleanResult) {
+ OutputContent proc = new OutputContent(){
+ @Override
+ public void output(ServletOutputStream out)
+ {
+ if ( resultSet != null )
+ ResultSetFormatter.outputAsTSV(out, resultSet) ;
+ if ( booleanResult != null )
+ ResultSetFormatter.outputAsTSV(out, booleanResult.booleanValue()) ;
+ }
+ } ;
+ output(action, contentType, charsetUTF8, proc) ;
+ }
+
+ private static void thriftOutput(HttpAction action, String contentType, final ResultSet resultSet, final Boolean booleanResult) {
+ OutputContent proc = new OutputContent(){
+ @Override
+ public void output(ServletOutputStream out)
+ {
+ if ( resultSet != null )
+ ResultSetMgr.write(out, resultSet, ResultSetLang.SPARQLResultSetThrift) ;
+ if ( booleanResult != null )
+ xlog.error("Can't write boolen result in thrift") ;
+ }
+ } ;
+ output(action, contentType, WebContent.charsetUTF8, proc) ;
+ }
+
+ private static void output(HttpAction action, String contentType, String charset, OutputContent proc)
+ {
+ try {
+ setHttpResponse(action, 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.
+ action.log.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.
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP.java
new file mode 100644
index 0000000..3f6a3b4
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP.java
@@ -0,0 +1,214 @@
+/*
+ * 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 java.util.Enumeration ;
+
+import javax.servlet.http.HttpServletRequest ;
+
+import org.apache.jena.riot.web.HttpNames ;
+import org.apache.jena.riot.system.IRIResolver ;
+
+import com.hp.hpl.jena.graph.Graph ;
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.graph.NodeFactory ;
+import com.hp.hpl.jena.sparql.core.DatasetGraph ;
+
+public abstract class SPARQL_GSP extends ActionREST
+{
+ protected final static Target determineTarget(HttpAction action) {
+ // Delayed until inside a transaction.
+ if ( action.getActiveDSG() == null )
+ ServletOps.errorOccurred("Internal error : No action graph (not in a transaction?)") ;
+
+ boolean dftGraph = getOneOnly(action.request, HttpNames.paramGraphDefault) != null ;
+ String uri = getOneOnly(action.request, HttpNames.paramGraph) ;
+
+ if ( !dftGraph && uri == null ) {
+ ServletOps.errorBadRequest("Neither default graph nor named graph specified; no direct name") ;
+
+ // Direct naming or error.
+ uri = action.request.getRequestURL().toString() ;
+ if ( action.request.getRequestURI().equals(action.getDatasetName()) )
+ // No name
+ ServletOps.errorBadRequest("Neither default graph nor named graph specified; no direct name") ;
+ }
+
+ String dsTarget = action.getDatasetName() ;
+
+ if ( dftGraph )
+ return Target.createDefault(action.getActiveDSG()) ;
+
+ // Named graph
+ if ( uri.equals(HttpNames.valueDefault ) )
+ // But "named" default
+ return Target.createDefault(action.getActiveDSG()) ;
+
+ // Strictly, a bit naughty on the URI resolution. But more sensible.
+ // Base is dataset.
+
+ // XXX Remove any service.
+
+ String base = action.request.getRequestURL().toString() ; //wholeRequestURL(request) ;
+ // Make sure it ends in "/", ie. dataset as container.
+ if ( action.request.getQueryString() != null && ! base.endsWith("/") )
+ base = base + "/" ;
+
+ String absUri = IRIResolver.resolveString(uri, base) ;
+ Node gn = NodeFactory.createURI(absUri) ;
+ return Target.createNamed(action.getActiveDSG(), absUri, gn) ;
+ }
+
+ // struct for target
+ protected static final class Target
+ {
+ final boolean isDefault ;
+ final DatasetGraph dsg ;
+ private Graph _graph ;
+ final String name ;
+ final Node graphName ;
+
+ static Target createNamed(DatasetGraph dsg, String name, Node graphName) {
+ return new Target(false, dsg, name, graphName) ;
+ }
+
+ static Target createDefault(DatasetGraph dsg) {
+ return new Target(true, dsg, null, null) ;
+ }
+
+ /** Create a new Target which is like the original but aimed at a different DatasetGraph */
+ static Target retarget(Target target, DatasetGraph dsg) {
+ Target target2 = new Target(target, dsg) ;
+ target2._graph = null ;
+ return target2 ;
+ }
+
+ private Target(boolean isDefault, DatasetGraph dsg, String name, Node graphName) {
+ this.isDefault = isDefault ;
+ this.dsg = dsg ;
+ this._graph = null ;
+ this.name = name ;
+ this.graphName = graphName ;
+
+ if ( isDefault )
+ {
+ if ( name != null || graphName != null )
+ throw new IllegalArgumentException("Inconsistent: default and a graph name/node") ;
+ }
+ else
+ {
+ if ( name == null || graphName == null )
+ throw new IllegalArgumentException("Inconsistent: not default and/or no graph name/node") ;
+ }
+ }
+
+ private Target(Target other, DatasetGraph dsg) {
+ this.isDefault = other.isDefault ;
+ this.dsg = dsg ; //other.dsg ;
+ this._graph = other._graph ;
+ this.name = other.name ;
+ this.graphName = other.graphName ;
+ }
+
+ /** Get a graph for the action - this may create a graph in the dataset - this is not a test for graph existence */
+ public Graph graph() {
+ if ( ! isGraphSet() )
+ {
+ if ( isDefault )
+ _graph = dsg.getDefaultGraph() ;
+ else
+ _graph = dsg.getGraph(graphName) ;
+ }
+ return _graph ;
+ }
+
+ public boolean exists()
+ {
+ if ( isDefault ) return true ;
+ return dsg.containsGraph(graphName) ;
+ }
+
+ public boolean isGraphSet()
+ {
+ return _graph != null ;
+ }
+
+ @Override
+// protected static ErrorHandler errorHandler = ErrorHandlerFactory.errorHandlerStd(log) ;
+
+ public String toString()
+ {
+ if ( isDefault ) return "default" ;
+ return name ;
+ }
+ }
+
+ public SPARQL_GSP()
+ { super() ; }
+
+ @Override
+ protected void validate(HttpAction action)
+ {
+ HttpServletRequest request = action.request ;
+ if ( request.getQueryString() == null ) {
+ //errorBadRequest("No query string") ;
+ return ;
+ }
+
+ String g = request.getParameter(HttpNames.paramGraph) ;
+ String d = request.getParameter(HttpNames.paramGraphDefault) ;
+
+ if ( g != null && d !=null )
+ ServletOps.errorBadRequest("Both ?default and ?graph in the query string of the request") ;
+
+ if ( g == null && d == null )
+ ServletOps.errorBadRequest("Neither ?default nor ?graph in the query string of the request") ;
+
+ int x1 = SPARQL_Protocol.countParamOccurences(request, HttpNames.paramGraph) ;
+ int x2 = SPARQL_Protocol.countParamOccurences(request, HttpNames.paramGraphDefault) ;
+
+ if ( x1 > 1 )
+ ServletOps.errorBadRequest("Multiple ?default in the query string of the request") ;
+ if ( x2 > 1 )
+ ServletOps.errorBadRequest("Multiple ?graph in the query string of the request") ;
+
+ Enumeration<String> en = request.getParameterNames() ;
+ for ( ; en.hasMoreElements() ; )
+ {
+ String h = en.nextElement() ;
+ if ( ! HttpNames.paramGraph.equals(h) && ! HttpNames.paramGraphDefault.equals(h) )
+ ServletOps.errorBadRequest("Unknown parameter '"+h+"'") ;
+ // one of ?default and &graph
+ if ( request.getParameterValues(h).length != 1 )
+ ServletOps.errorBadRequest("Multiple parameters '"+h+"'") ;
+ }
+ }
+
+ protected static String getOneOnly(HttpServletRequest request, String name)
+ {
+ String[] values = request.getParameterValues(name) ;
+ if ( values == null )
+ return null ;
+ if ( values.length == 0 )
+ return null ;
+ if ( values.length > 1 )
+ ServletOps.errorBadRequest("Multiple occurrences of '"+name+"'") ;
+ return values[0] ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_R.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_R.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_R.java
new file mode 100644
index 0000000..a706e57
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_R.java
@@ -0,0 +1,123 @@
+/*
+ * 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 javax.servlet.ServletOutputStream ;
+
+import org.apache.jena.atlas.web.MediaType ;
+import org.apache.jena.atlas.web.TypedOutputStream ;
+import org.apache.jena.riot.web.HttpNames ;
+import org.apache.jena.riot.* ;
+
+import com.hp.hpl.jena.graph.Graph ;
+
+/** Only the READ operations */
+public class SPARQL_GSP_R extends SPARQL_GSP
+{
+ public SPARQL_GSP_R()
+ { super() ; }
+
+ @Override
+ protected String mapRequestToDataset(HttpAction action) { return ActionLib.mapRequestToDatasetLongest$(action.request.getRequestURI()) ; }
+
+ @Override
+ protected void doGet(HttpAction action) {
+ // Assume success - do the set up before grabbing the lock.
+ // Sets content type.
+ MediaType mediaType = ActionLib.contentNegotationRDF(action) ;
+
+ ServletOutputStream output ;
+ try { output = action.response.getOutputStream() ; }
+ catch (IOException ex) { ServletOps.errorOccurred(ex) ; output = null ; }
+
+ TypedOutputStream out = new TypedOutputStream(output, mediaType) ;
+ Lang lang = RDFLanguages.contentTypeToLang(mediaType.getContentType()) ;
+
+ if ( action.verbose )
+ action.log.info(format("[%d] Get: Content-Type=%s, Charset=%s => %s",
+ action.id, mediaType.getContentType(), mediaType.getCharset(), lang.getName())) ;
+
+ action.beginRead() ;
+ setCommonHeaders(action.response) ;
+ try {
+ Target target = determineTarget(action) ;
+ if ( action.log.isDebugEnabled() )
+ action.log.debug("GET->"+target) ;
+ boolean exists = target.exists() ;
+ if ( ! exists )
+ ServletOps.errorNotFound("No such graph: <"+target.name+">") ;
+ // If we want to set the Content-Length, we need to buffer.
+ //response.setContentLength(??) ;
+ String ct = lang.getContentType().toHeaderString() ;
+ action.response.setContentType(ct) ;
+ Graph g = target.graph() ;
+ //Special case RDF/XML to be the plain (faster, less readable) form
+ RDFFormat fmt =
+ ( lang == Lang.RDFXML ) ? RDFFormat.RDFXML_PLAIN : RDFWriterRegistry.defaultSerialization(lang) ;
+ RDFDataMgr.write(out, g, fmt) ;
+ ServletOps.success(action) ;
+ } finally { action.endRead() ; }
+ }
+
+ @Override
+ protected void doOptions(HttpAction action) {
+ setCommonHeadersForOptions(action.response) ;
+ action.response.setHeader(HttpNames.hAllow, "GET,HEAD,OPTIONS") ;
+ action.response.setHeader(HttpNames.hContentLengh, "0") ;
+ ServletOps.success(action) ;
+ }
+
+ @Override
+ protected void doHead(HttpAction action) {
+ action.beginRead() ;
+ setCommonHeaders(action.response) ;
+ try {
+ Target target = determineTarget(action) ;
+ if ( action.log.isDebugEnabled() )
+ action.log.debug("HEAD->"+target) ;
+ if ( ! target.exists() )
+ {
+ ServletOps.successNotFound(action) ;
+ return ;
+ }
+ MediaType mediaType = ActionLib.contentNegotationRDF(action) ;
+ ServletOps.success(action) ;
+ } finally { action.endRead() ; }
+ }
+
+ @Override
+ protected void doPost(HttpAction action)
+ { ServletOps.errorMethodNotAllowed("POST") ; }
+
+ @Override
+ protected void doDelete(HttpAction action)
+ { ServletOps.errorMethodNotAllowed("DELETE") ; }
+
+ @Override
+ protected void doPut(HttpAction action)
+ { ServletOps.errorMethodNotAllowed("PUT") ; }
+
+ @Override
+ protected void doPatch(HttpAction action)
+ { ServletOps.errorMethodNotAllowed("PATCH") ; }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_RW.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_RW.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_RW.java
new file mode 100644
index 0000000..d3c3179
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_RW.java
@@ -0,0 +1,208 @@
+/*
+ * 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.ctMultipartMixed ;
+import static org.apache.jena.riot.WebContent.matchContentType ;
+
+import java.util.Map ;
+import java.util.Map.Entry ;
+
+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.FusekiLib ;
+import org.apache.jena.fuseki.conneg.ConNeg ;
+import org.apache.jena.fuseki.servlets.UploadDetails.PreState ;
+import org.apache.jena.riot.RiotException ;
+import org.apache.jena.riot.system.StreamRDF ;
+import org.apache.jena.riot.system.StreamRDFLib ;
+import org.apache.jena.riot.web.HttpNames ;
+import org.apache.jena.web.HttpSC ;
+
+import com.hp.hpl.jena.graph.Graph ;
+import com.hp.hpl.jena.sparql.graph.GraphFactory ;
+
+/** The WRITE operations added to the READ operations */
+public class SPARQL_GSP_RW extends SPARQL_GSP_R
+{
+ public SPARQL_GSP_RW()
+ { super() ; }
+
+ @Override
+ protected void doOptions(HttpAction action) {
+ setCommonHeadersForOptions(action.response) ;
+ action.response.setHeader(HttpNames.hAllow, "GET,HEAD,OPTIONS,PUT,DELETE,POST");
+ action.response.setHeader(HttpNames.hContentLengh, "0") ;
+ ServletOps.success(action) ;
+ }
+
+ @Override
+ protected void doDelete(HttpAction action) {
+ action.beginWrite() ;
+ try {
+ Target target = determineTarget(action) ;
+ if ( action.log.isDebugEnabled() )
+ action.log.debug("DELETE->"+target) ;
+ boolean existedBefore = target.exists() ;
+ if ( ! existedBefore)
+ {
+ // commit, not abort, because locking "transactions" don't support abort.
+ action.commit() ;
+ ServletOps.errorNotFound("No such graph: "+target.name) ;
+ }
+ deleteGraph(action) ;
+ action.commit() ;
+ }
+ finally { action.endWrite() ; }
+ ServletOps.successNoContent(action) ;
+ }
+
+ @Override
+ protected void doPut(HttpAction action) { doPutPost(action, true) ; }
+
+ @Override
+ protected void doPost(HttpAction action) { doPutPost(action, false) ; }
+
+ private void doPutPost(HttpAction action, boolean overwrite) {
+ ContentType ct = FusekiLib.getContentType(action) ;
+ if ( ct == null )
+ ServletOps.errorBadRequest("No Content-Type:") ;
+
+ if ( matchContentType(ctMultipartMixed, ct) ) {
+ ServletOps.error(HttpSC.UNSUPPORTED_MEDIA_TYPE_415, "multipart/mixed not supported") ;
+ }
+
+ UploadDetails details ;
+ if ( action.isTransactional() )
+ details = addDataIntoTxn(action, overwrite) ;
+ else
+ details = addDataIntoNonTxn(action, overwrite) ;
+
+ MediaType mt = ConNeg.chooseCharset(action.request, DEF.jsonOffer, DEF.acceptJSON) ;
+
+ if ( mt == null ) {
+ // No return body.
+ if ( details.getExistedBefore().equals(PreState.ABSENT) )
+ ServletOps.successCreated(action) ;
+ else
+ ServletOps.successNoContent(action) ;
+ return ;
+ }
+ ServletOps.uploadResponse(action, details) ;
+ }
+
+ /** Directly add data in a transaction.
+ * Assumes recovery from parse errors by transaction abort.
+ * Return whether the target existed before.
+ * @param action
+ * @param cleanDest Whether to remove data first (true = PUT, false = POST)
+ * @return whether the target existed beforehand
+ */
+ protected static UploadDetails addDataIntoTxn(HttpAction action, boolean overwrite) {
+ action.beginWrite();
+ Target target = determineTarget(action) ;
+ boolean existedBefore = false ;
+ try {
+ if ( action.log.isDebugEnabled() )
+ action.log.debug(" ->"+target) ;
+ existedBefore = target.exists() ;
+ Graph g = target.graph() ;
+ if ( overwrite && existedBefore )
+ clearGraph(target) ;
+ StreamRDF sink = StreamRDFLib.graph(g) ;
+ UploadDetails upload = Upload.incomingData(action, sink);
+ upload.setExistedBefore(existedBefore) ;
+ action.commit() ;
+ return upload ;
+ } catch (RiotException ex) {
+ // Parse error
+ action.abort() ;
+ ServletOps.errorBadRequest(ex.getMessage()) ;
+ return null ;
+ } catch (Exception ex) {
+ // Something else went wrong. Backout.
+ action.abort() ;
+ ServletOps.errorOccurred(ex.getMessage()) ;
+ return null ;
+ } finally {
+ action.endWrite() ;
+ }
+ }
+
+ /** Add data where the destination does not support full transactions.
+ * In particular, with no abort, and actions probably going to the real storage
+ * parse errors can lead to partial updates. Instead, parse to a temporary
+ * graph, then insert that data.
+ * @param action
+ * @param cleanDest Whether to remove data first (true = PUT, false = POST)
+ * @return whether the target existed beforehand.
+ */
+
+ protected static UploadDetails addDataIntoNonTxn(HttpAction action, boolean overwrite) {
+ Graph graphTmp = GraphFactory.createGraphMem() ;
+ StreamRDF dest = StreamRDFLib.graph(graphTmp) ;
+
+ UploadDetails details ;
+ try { details = Upload.incomingData(action, dest); }
+ catch (RiotException ex) {
+ ServletOps.errorBadRequest(ex.getMessage()) ;
+ return null ;
+ }
+ // Now insert into dataset
+ action.beginWrite() ;
+ Target target = determineTarget(action) ;
+ boolean existedBefore = false ;
+ try {
+ if ( action.log.isDebugEnabled() )
+ action.log.debug(" ->"+target) ;
+ existedBefore = target.exists() ;
+ if ( overwrite && existedBefore )
+ clearGraph(target) ;
+ FusekiLib.addDataInto(graphTmp, target.dsg, target.graphName) ;
+ details.setExistedBefore(existedBefore) ;
+ action.commit() ;
+ return details ;
+ } catch (Exception ex) {
+ // We parsed into a temporary graph so an exception at this point
+ // is not because of a parse error.
+ // We're in the non-transactional branch, this probably will not work
+ // but it might and there is no harm safely trying.
+ try { action.abort() ; } catch (Exception ex2) {}
+ ServletOps.errorOccurred(ex.getMessage()) ;
+ return null ;
+ } finally { action.endWrite() ; }
+ }
+
+ protected static void deleteGraph(HttpAction action) {
+ Target target = determineTarget(action) ;
+ if ( target.isDefault )
+ target.graph().clear() ;
+ else
+ action.getActiveDSG().removeGraph(target.graphName) ;
+ }
+
+ protected static void clearGraph(Target target) {
+ Graph g = target.graph() ;
+ g.clear() ;
+ Map<String, String> pm = g.getPrefixMapping().getNsPrefixMap() ;
+ for ( Entry<String, String> e : pm.entrySet() )
+ g.getPrefixMapping().removeNsPrefix(e.getKey()) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Protocol.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Protocol.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Protocol.java
new file mode 100644
index 0000000..87d234e
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Protocol.java
@@ -0,0 +1,101 @@
+/**
+ * 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.web.HttpNames.paramDefaultGraphURI ;
+import static org.apache.jena.riot.web.HttpNames.paramNamedGraphURI ;
+
+import java.util.Arrays ;
+import java.util.Collections ;
+import java.util.List ;
+
+import javax.servlet.http.HttpServletRequest ;
+
+import org.apache.jena.atlas.iterator.Filter ;
+import org.apache.jena.atlas.iterator.Iter ;
+import org.apache.jena.atlas.lib.Lib ;
+
+import com.hp.hpl.jena.query.Query ;
+import com.hp.hpl.jena.query.QueryParseException ;
+import com.hp.hpl.jena.sparql.core.DatasetDescription ;
+
+/** Support for the SPARQL protocol (SPARQL Query, SPARQL Update)
+ */
+public abstract class SPARQL_Protocol extends ActionSPARQL
+{
+ protected SPARQL_Protocol() { super() ; }
+
+ protected static String messageForQPE(QueryParseException ex)
+ {
+ if ( ex.getMessage() != null )
+ return ex.getMessage() ;
+ if ( ex.getCause() != null )
+ return Lib.classShortName(ex.getCause().getClass()) ;
+ return null ;
+ }
+
+ protected static DatasetDescription getDatasetDescription(HttpAction action)
+ {
+ List<String> graphURLs = toStrList(action.request.getParameterValues(paramDefaultGraphURI)) ;
+ List<String> namedGraphs = toStrList(action.request.getParameterValues(paramNamedGraphURI)) ;
+
+ graphURLs = removeEmptyValues(graphURLs) ;
+ namedGraphs = removeEmptyValues(namedGraphs) ;
+
+ if ( graphURLs.size() == 0 && namedGraphs.size() == 0 )
+ return null ;
+ return DatasetDescription.create(graphURLs, namedGraphs) ;
+ }
+
+ protected static DatasetDescription getDatasetDescription(Query query)
+ {
+ return DatasetDescription.create(query) ;
+ }
+
+ private static List<String> toStrList(String[] array)
+ {
+ if ( array == null )
+ return Collections.emptyList() ;
+ return Arrays.asList(array) ;
+ }
+
+ private static List<String> removeEmptyValues(List<String> list)
+ {
+ return Iter.iter(list).filter(acceptNonEmpty).toList() ;
+ }
+
+ private static Filter<String> acceptNonEmpty = new Filter<String>(){
+ @Override
+ public boolean accept(String item)
+ {
+ return item != null && item.length() != 0 ;
+ }
+ } ;
+
+ protected static int countParamOccurences(HttpServletRequest request, String param)
+ {
+ String[] x = request.getParameterValues(param) ;
+ if ( x == null )
+ return 0 ;
+ return x.length ;
+ }
+
+
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/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
new file mode 100644
index 0000000..6ab3f71
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
@@ -0,0 +1,393 @@
+/*
+ * 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 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.riot.web.HttpNames ;
+import org.apache.jena.riot.web.HttpOp ;
+import org.apache.jena.web.HttpSC ;
+
+import com.hp.hpl.jena.query.* ;
+import com.hp.hpl.jena.rdf.model.Model ;
+import com.hp.hpl.jena.sparql.core.Prologue ;
+import com.hp.hpl.jena.sparql.resultset.SPARQLResult ;
+
+/** 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) ;
+ String incoming = ct.getContentType() ;
+
+ // POST application/x-www-form-url
+ if ( isHtmlForm(ct) ) {
+ executeWithParameter(action) ;
+ return ;
+ }
+
+ // POST application/sparql-query
+ if ( matchContentType(ct, ctSPARQLQuery) ) {
+ executeBody(action) ;
+ return ;
+ }
+
+ ServletOps.error(HttpSC.UNSUPPORTED_MEDIA_TYPE_415, "Bad content type: " + incoming) ;
+ }
+
+ // 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 ;
+ } else if ( matchContentType(ctHTMLForm, ct))
+ {}
+ 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" + messageForQPE(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 (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
+ * @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) ;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/470ee4d7/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_QueryDataset.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_QueryDataset.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_QueryDataset.java
new file mode 100644
index 0000000..9e9df36
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_QueryDataset.java
@@ -0,0 +1,60 @@
+/*
+ * 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 com.hp.hpl.jena.query.Dataset ;
+import com.hp.hpl.jena.query.DatasetFactory ;
+import com.hp.hpl.jena.query.Query ;
+import com.hp.hpl.jena.sparql.core.DatasetDescription ;
+import com.hp.hpl.jena.sparql.core.DatasetGraph ;
+import com.hp.hpl.jena.sparql.core.DynamicDatasets ;
+
+public class SPARQL_QueryDataset extends SPARQL_Query
+{
+ public SPARQL_QueryDataset(boolean verbose) { super() ; }
+
+ public SPARQL_QueryDataset()
+ { this(false) ; }
+
+ @Override
+ protected void validateRequest(HttpAction action)
+ { }
+
+ @Override
+ protected void validateQuery(HttpAction action, Query query)
+ { }
+
+ @Override
+ protected Dataset decideDataset(HttpAction action, Query query, String queryStringLog)
+ {
+ DatasetGraph dsg = action.getActiveDSG() ;
+
+ // query.getDatasetDescription() ;
+
+ // Protocol.
+ DatasetDescription dsDesc = getDatasetDescription(action) ;
+ if (dsDesc != null )
+ {
+ //errorBadRequest("SPARQL Query: Dataset description in the protocol request") ;
+ dsg = DynamicDatasets.dynamicDataset(dsDesc, dsg, false) ;
+ }
+
+ return DatasetFactory.create(dsg) ;
+ }
+}