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/03/05 16:36:43 UTC
[04/23] jena git commit: Rename folder jena-fuseki to jena-fuseki1
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/ServiceMXBean.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/ServiceMXBean.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/ServiceMXBean.java
new file mode 100644
index 0000000..11c7330
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/ServiceMXBean.java
@@ -0,0 +1,32 @@
+/**
+ * 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.server;
+
+public interface ServiceMXBean
+{
+ String getName() ;
+
+ long getRequests() ;
+ long getRequestsGood() ;
+ long getRequestsBad() ;
+
+// void enable() ;
+// void disable() ;
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/ServiceRef.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/ServiceRef.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/ServiceRef.java
new file mode 100644
index 0000000..6236050
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/ServiceRef.java
@@ -0,0 +1,63 @@
+/**
+ * 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.server;
+
+import java.util.ArrayList ;
+import java.util.List ;
+
+/** Configuration of an individual service */
+public class ServiceRef implements ServiceMXBean, Counters
+{
+ public final String name ;
+
+ // Service-level counters.
+ private final CounterSet counters = new CounterSet() ;
+ @Override
+ public CounterSet getCounters() { return counters ; }
+
+ /** Endpoints (as absolute path URLs) */
+ public List<String> endpoints = new ArrayList<String>() ;
+
+ // Attach counters to services or datasets
+ // Can we have a counter of the same name on different services?
+ // Cost : number of maps.
+ // +ve: Multiple services with the same name counter
+
+ public ServiceRef(String serviceName) {
+ this.name = serviceName ;
+ }
+
+ public boolean isActive() { return endpoints.isEmpty() ; }
+
+ @Override
+ public String getName() { return name ; }
+
+ @Override public long getRequests() {
+ return counters.value(CounterName.Requests) ;
+ }
+ @Override
+ public long getRequestsGood() {
+ return counters.value(CounterName.RequestsGood) ;
+ }
+ @Override
+ public long getRequestsBad() {
+ return counters.value(CounterName.RequestsBad) ;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ActionErrorException.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ActionErrorException.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ActionErrorException.java
new file mode 100644
index 0000000..6c5ebe9
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ActionErrorException.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+class ActionErrorException extends RuntimeException
+{
+ final Throwable exception ;
+ final String message ;
+ final int rc ;
+ ActionErrorException(Throwable ex, String message, int rc)
+ {
+ this.exception = ex ;
+ this.message = message ;
+ this.rc = rc ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ConcurrencyPolicyMRSW.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ConcurrencyPolicyMRSW.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ConcurrencyPolicyMRSW.java
new file mode 100644
index 0000000..259453d
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ConcurrencyPolicyMRSW.java
@@ -0,0 +1,113 @@
+/*
+ * 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.ConcurrentModificationException ;
+import java.util.concurrent.atomic.AtomicLong ;
+
+import org.apache.jena.fuseki.Fuseki ;
+import org.slf4j.Logger ;
+
+public final class ConcurrencyPolicyMRSW
+{
+ static private Logger log = Fuseki.requestLog ; //org.slf4j.LoggerFactory.getLogger(ConcurrencyPolicyMRSW.class) ;
+ static private final boolean logging = false ; //log.isDebugEnabled() ;
+
+ // This is a simplified version of ConcurrencyPolicyMRSW from TDB.
+ private final AtomicLong readCounter = new AtomicLong(0) ;
+ private final AtomicLong writeCounter = new AtomicLong(0) ;
+ static private final AtomicLong policyCounter = new AtomicLong(0) ;
+
+ public ConcurrencyPolicyMRSW()
+ { policyCounter.incrementAndGet() ; }
+
+ // Loggin -inside the operation.
+
+ //@Override
+ public void startRead()
+ {
+ readCounter.getAndIncrement() ;
+ log() ;
+ checkConcurrency() ;
+ }
+
+ //@Override
+ public void finishRead()
+ {
+ log() ;
+ readCounter.decrementAndGet() ;
+ checkConcurrency() ;
+ }
+
+ //@Override
+ public void startUpdate()
+ {
+ writeCounter.getAndIncrement() ;
+ log() ;
+ checkConcurrency() ;
+ }
+
+ //@Override
+ public void finishUpdate()
+ {
+ log() ;
+ writeCounter.decrementAndGet() ;
+ checkConcurrency() ;
+ }
+
+ private synchronized void checkConcurrency()
+ {
+ long R = readCounter.get() ;
+ long W = writeCounter.get() ;
+ long id = policyCounter.get();
+ if ( R > 0 && W > 0 )
+ policyError(id, R, W) ;
+ if ( W > 1 )
+ policyError(id, R, W) ;
+ }
+
+ private void log()
+ {
+ if ( ! logging )
+ return ;
+ long R , W , id ;
+ synchronized(this)
+ {
+ R = readCounter.get() ;
+ W = writeCounter.get() ;
+ id = policyCounter.get();
+ }
+ log.info(format(id, R, W)) ;
+ }
+
+ private static void policyError(long id, long R, long W)
+ {
+ policyError(format(id, R, W)) ;
+ }
+
+ private static void policyError(String message)
+ {
+ throw new ConcurrentModificationException(message) ;
+ }
+
+ private static String format(long id, long R, long W)
+ {
+ return String.format("(lock=%d) Reader = %d, Writer = %d", id, R, W) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/DumpServlet.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/DumpServlet.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/DumpServlet.java
new file mode 100644
index 0000000..7ece249
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/DumpServlet.java
@@ -0,0 +1,313 @@
+/*
+ * 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.
+ */
+
+/** A servlet that dumps its request
+ */
+
+// Could be neater - much, much neater!
+package org.apache.jena.fuseki.servlets;
+
+import java.io.BufferedReader ;
+import java.io.IOException ;
+import java.io.PrintWriter ;
+import java.io.StringWriter ;
+import java.util.Date ;
+import java.util.Enumeration ;
+import java.util.Locale ;
+import java.util.Properties ;
+
+import javax.servlet.ServletContext ;
+import javax.servlet.http.Cookie ;
+import javax.servlet.http.HttpServlet ;
+import javax.servlet.http.HttpServletRequest ;
+import javax.servlet.http.HttpServletResponse ;
+
+public class DumpServlet extends HttpServlet
+{
+ private static final long serialVersionUID = 99L; // Serilizable.
+
+
+ public DumpServlet()
+ {
+
+ }
+
+ @Override
+ public void init()
+ {
+ return ;
+ }
+
+ @Override
+ public void doGet(HttpServletRequest req, HttpServletResponse resp)
+ {
+ try {
+ PrintWriter out = resp.getWriter() ;
+ resp.setContentType("text/html");
+
+ String now = new Date().toString() ;
+
+ // HEAD
+ out.println("<html>") ;
+ out.println("<head>") ;
+ out.println("<Title>Dump @ "+now+"</Title>") ;
+ // Reduce the desire to cache it.
+ out.println("<meta CONTENT=now HTTP-EQUIV=expires>") ;
+ out.println("</head>") ;
+
+ // BODY
+ out.println("<body>") ;
+ out.println("<pre>") ;
+
+ out.println("Dump : "+now);
+ out.println() ;
+ out.println("==== Request");
+ out.println() ;
+ out.print(dumpRequest(req)) ;
+ out.println() ;
+
+ out.println(">>>> Body");
+ out.println() ;
+ printBody(out, req) ;
+ out.println("<<<< Body");
+
+ out.println("==== ServletContext");
+ out.println() ;
+ out.print(dumpServletContext());
+ out.println() ;
+
+ out.println("==== Environment");
+ out.println() ;
+ out.print(dumpEnvironment());
+ out.println() ;
+
+ out.println("</pre>") ;
+
+ out.println("</body>") ;
+ out.println("</html>") ;
+ out.flush() ;
+ } catch (IOException e)
+ { }
+ }
+
+ // This resets the input stream
+
+ static public String dumpRequest(HttpServletRequest req)
+ {
+ StringWriter sw = new StringWriter() ;
+ try( PrintWriter pw = new PrintWriter(sw) ) {
+ // Standard environment
+ pw.println("Method: "+req.getMethod());
+ pw.println("getContentLength: "+Integer.toString(req.getContentLength()));
+ pw.println("getContentType: "+req.getContentType());
+ pw.println("getRequestURI: "+req.getRequestURI());
+ pw.println("getRequestURL: "+req.getRequestURL());
+ pw.println("getContextPath: "+req.getContextPath());
+ pw.println("getServletPath: "+req.getServletPath());
+ pw.println("getPathInfo: "+req.getPathInfo());
+ pw.println("getPathTranslated: "+req.getPathTranslated());
+ pw.println("getQueryString: "+req.getQueryString());
+ pw.println("getProtocol: "+req.getProtocol());
+ pw.println("getScheme: "+req.getScheme());
+ pw.println("getServerName: "+req.getServerName());
+ pw.println("getServerPort: "+req.getServerPort());
+ pw.println("getRemoteUser: "+req.getRemoteUser());
+ pw.println("getRemoteAddr: "+req.getRemoteAddr());
+ pw.println("getRemoteHost: "+req.getRemoteHost());
+ pw.println("getRequestedSessionId: "+req.getRequestedSessionId());
+ {
+ Cookie c[] = req.getCookies() ;
+ if ( c == null )
+ pw.println("getCookies: <none>");
+ else
+ {
+ for ( Cookie aC : c )
+ {
+ pw.println( "Cookie: " + aC.getName() );
+ pw.println( " value: " + aC.getValue() );
+ pw.println( " version: " + aC.getVersion() );
+ pw.println( " comment: " + aC.getComment() );
+ pw.println( " domain: " + aC.getDomain() );
+ pw.println( " maxAge: " + aC.getMaxAge() );
+ pw.println( " path: " + aC.getPath() );
+ pw.println( " secure: " + aC.getSecure() );
+ pw.println();
+ }
+ }
+ }
+
+ {
+ // To do: create a string for the output so can send to console and return it.
+ Enumeration<String> en = req.getHeaderNames() ;
+
+ for ( ; en.hasMoreElements() ; )
+ {
+ String name = en.nextElement() ;
+ String value = req.getHeader(name) ;
+ pw.println("Head: "+name + " = " + value) ;
+ }
+ }
+
+ Enumeration<String> en2 = req.getAttributeNames() ;
+ if ( en2.hasMoreElements() )
+ pw.println();
+ for ( ; en2.hasMoreElements() ; )
+ {
+ String name = en2.nextElement() ;
+ String value = req.getAttribute(name).toString() ;
+ pw.println("Attr: "+name + " = " + value) ;
+ }
+
+ // Note that doing this on a form causes the forms content (body) to be read
+ // and parsed as form variables.
+// en = req.getParameterNames() ;
+// if ( en.hasMoreElements() )
+// pw.println();
+// for ( ; en.hasMoreElements() ; )
+// {
+// String name = (String)en.nextElement() ;
+// String value = req.getParameter(name) ;
+// pw.println("Param: "+name + " = " + value) ;
+// }
+
+
+
+// MultiMap<String, String> map = WebLib.parseQueryString(req) ;
+// for ( String name : map.keys() )
+// for ( String value : map.get(name) )
+// pw.println("Param: "+name + " = " + value) ;
+
+ Enumeration<Locale> en = req.getLocales() ;
+ if ( en.hasMoreElements() )
+ pw.println();
+ for ( ; en.hasMoreElements() ; )
+ {
+ String name = en.nextElement().toString() ;
+ pw.println("Locale: "+name) ;
+ }
+
+ pw.println() ;
+ pw.flush();
+ //printBody(pw, req) ;
+ return sw.toString() ;
+ }
+
+ }
+
+ static void printBody(PrintWriter pw, HttpServletRequest req) throws IOException
+ {
+ BufferedReader in = req.getReader() ;
+ if ( req.getContentLength() > 0 )
+ // Need +2 because last line may not have a CR/LF on it.
+ in.mark(req.getContentLength()+2) ;
+ else
+ // This is a dump - try to do something that works, even if inefficient.
+ in.mark(100*1024) ;
+
+ while(true)
+ {
+ String x = in.readLine() ;
+ if ( x == null )
+ break ;
+ x = x.replaceAll("&", "&") ;
+ x = x.replaceAll("<", "<") ;
+ x = x.replaceAll(">", ">") ;
+ pw.println(x) ;
+ }
+ try { in.reset() ;} catch (IOException e) { System.out.println("DumpServlet: Reset of content failed: "+e) ; }
+ }
+
+ /**
+ * <code>dumpEnvironment</code>
+ * @return String that is the HTML of the System properties as name/value pairs.
+ * The values are with single quotes independent of whether or not the value has
+ * single quotes in it.
+ */
+ static public String dumpEnvironment()
+ {
+ Properties properties = System.getProperties();
+
+ StringWriter sw = new StringWriter() ;
+ try(PrintWriter pw = new PrintWriter(sw) ) {
+ Enumeration<Object> en = properties.keys();
+ while(en.hasMoreElements())
+ {
+ String key = en.nextElement().toString();
+ pw.println(key+": '"+properties.getProperty(key)+"'");
+ }
+ pw.println() ;
+ pw.flush() ;
+ return sw.toString() ;
+ }
+ }
+
+ public String dumpServletContext()
+ {
+ StringWriter sw = new StringWriter() ;
+ try(PrintWriter pw = new PrintWriter(sw)) {
+
+ ServletContext sc = getServletContext();
+ pw.println("majorVersion: '"+sc.getMajorVersion()+"'");
+ pw.println("minorVersion: '"+sc.getMinorVersion()+"'");
+ pw.println("contextName: '"+sc.getServletContextName()+"'");
+ pw.println("servletInfo: '"+getServletInfo()+"'");
+ pw.println("serverInfo: '"+sc.getServerInfo()+"'");
+
+ {
+ Enumeration<String> en = sc.getInitParameterNames();
+ if (en != null) {
+ pw.println("initParameters: ");
+ while(en.hasMoreElements())
+ {
+ String key = en.nextElement();
+ pw.println(key+": '"+sc.getInitParameter(key)+"'");
+ }
+ }
+ }
+
+ {
+ Enumeration<String> en = sc.getAttributeNames();
+ if (en != null) {
+ pw.println("attributes: ");
+ while(en.hasMoreElements())
+ {
+ String key = en.nextElement();
+ pw.println(key+": '"+sc.getAttribute(key)+"'");
+ }
+ }
+ }
+ pw.println() ;
+ pw.close() ;
+ }
+ return sw.toString() ;
+ }
+
+
+ @Override
+ public void doPost(HttpServletRequest req, HttpServletResponse resp)
+ {
+ doGet(req, resp) ;
+ }
+
+
+ @Override
+ public String getServletInfo()
+ {
+ return "Dump";
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java
new file mode 100644
index 0000000..39663dd
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java
@@ -0,0 +1,290 @@
+/*
+ * 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 com.hp.hpl.jena.query.ReadWrite.READ ;
+import static com.hp.hpl.jena.query.ReadWrite.WRITE ;
+
+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 ;
+import org.apache.jena.atlas.web.MediaType ;
+import org.apache.jena.fuseki.DEF ;
+import org.apache.jena.fuseki.conneg.ConNeg ;
+import org.apache.jena.fuseki.server.DatasetRef ;
+import org.apache.jena.fuseki.server.ServiceRef ;
+
+import com.hp.hpl.jena.query.ReadWrite ;
+import com.hp.hpl.jena.sparql.SystemARQ ;
+import com.hp.hpl.jena.sparql.core.DatasetGraph ;
+import com.hp.hpl.jena.sparql.core.DatasetGraphWithLock ;
+import com.hp.hpl.jena.sparql.core.DatasetGraphWrapper ;
+import com.hp.hpl.jena.sparql.core.Transactional ;
+
+/**
+ * HTTP action that represents the user request lifecycle. Its state is handled in the
+ * {@link SPARQL_ServletBase#executeLifecycle(HttpAction)} method.
+ */
+public class HttpAction
+{
+ public final long id ;
+ public final boolean verbose ;
+
+ // Phase two items - set and valida after the datasetRef is known.
+ private DatasetGraph dsg ; // The data
+ public DatasetRef dsRef ;
+ public ServiceRef srvRef ;
+
+ private Transactional transactional ;
+ private boolean isTransactional;
+ private DatasetGraph activeDSG ; // Set when inside begin/end.
+ private ReadWrite activeMode ; // Set when inside begin/end.
+
+ private boolean startTimeIsSet = false ;
+ private boolean finishTimeIsSet = false ;
+
+ private long startTime = -2 ;
+ private long finishTime = -2 ;
+
+ // Incoming
+ //public final
+
+ // Outcome.
+ int statusCode = -1 ;
+ String message = null ;
+ int contentLength = -1 ;
+ String contentType = null ;
+
+ // Cleared to archive:
+ Map <String, String> headers = new HashMap<String, String>() ;
+ public HttpServletRequest request;
+ public HttpServletResponseTracker response ;
+
+ /**
+ * Creates a new HTTP Action, using the HTTP request and response, and a given ID.
+ *
+ * @param id given ID
+ * @param request HTTP request
+ * @param response HTTP response
+ * @param verbose verbose flag
+ */
+ public HttpAction(long id, HttpServletRequest request, HttpServletResponse response, boolean verbose) {
+ this.id = id ;
+ this.request = request ;
+ this.response = new HttpServletResponseTracker(this, response) ;
+ // Should this be set when setDataset is called from the dataset context?
+ // Currently server-wide, e.g. from the command line.
+ this.verbose = verbose ;
+ }
+
+ /**
+ * <p>Sets the action dataset. Setting a {@link DatasetRef} will replace any existing DatasetRef, as well as
+ * as the {@link DatasetGraph} of the current HTTP Action.</p>
+ *
+ * <p>Once it has updated its members, the HTTP Action will change its transactional state and
+ * {@link Transactional} instance according to its base dataset graph.</p>
+ *
+ * @param desc {@link DatasetRef}
+ * @see Transactional
+ * @see DatasetGraphWrapper
+ */
+ public void setDataset(DatasetRef desc) {
+ this.dsRef = desc ;
+ this.dsg = desc.dataset ;
+ DatasetGraph basedsg = unwrap(dsg) ;
+
+ if ( isTransactional(basedsg) && isTransactional(dsg) ) {
+ // Use transactional if it looks safe - abort is necessary.
+ transactional = (Transactional)dsg ;
+ isTransactional = true ;
+ } else {
+ // Unsure if safe
+ transactional = new DatasetGraphWithLock(dsg) ;
+ // No real abort.
+ isTransactional = false ;
+ }
+ }
+
+ /**
+ * Returns <code>true</code> iff the given {@link DatasetGraph} is an instance of {@link Transactional},
+ * <code>false otherwise</code>.
+ *
+ * @param dsg a {@link DatasetGraph}
+ * @return <code>true</code> iff the given {@link DatasetGraph} is an instance of {@link Transactional},
+ * <code>false otherwise</code>
+ */
+ private static boolean isTransactional(DatasetGraph dsg) {
+ return (dsg instanceof Transactional) ;
+ }
+
+ /**
+ * A {@link DatasetGraph} may contain other <strong>wrapped DatasetGraph's</strong>. This method will return
+ * the first instance (including the argument to this method) that <strong>is not</strong> an instance of
+ * {@link DatasetGraphWrapper}.
+ *
+ * @param dsg a {@link DatasetGraph}
+ * @return the first found {@link DatasetGraph} that is not an instance of {@link DatasetGraphWrapper}
+ */
+ private static DatasetGraph unwrap(DatasetGraph dsg) {
+ while (dsg instanceof DatasetGraphWrapper) {
+ dsg = ((DatasetGraphWrapper)dsg).getWrapped() ;
+ }
+ return dsg ;
+ }
+
+ /**
+ * Sets the {@link ServiceRef}.
+ *
+ * @param srvRef a {@link ServiceRef}
+ */
+ public void setService(ServiceRef srvRef) {
+ this.srvRef = srvRef ;
+ }
+
+ /**
+ * Returns whether or not the underlying DatasetGraph is fully transactional (supports rollback).
+ * @return <code>true</code> if the underlying DatasetGraph is fully transactional (supports rollback),
+ * <code>false</code> otherwise.
+ */
+ public boolean isTransactional() {
+ return isTransactional ;
+ }
+
+ public void beginRead() {
+ activeMode = READ ;
+ transactional.begin(READ) ;
+ activeDSG = dsg ;
+ dsRef.startTxn(READ) ;
+ }
+
+ public void endRead() {
+ dsRef.finishTxn(READ) ;
+ activeMode = null ;
+ transactional.end() ;
+ activeDSG = null ;
+ }
+
+ public void beginWrite() {
+ transactional.begin(WRITE) ;
+ activeMode = WRITE ;
+ activeDSG = dsg ;
+ dsRef.startTxn(WRITE) ;
+ }
+
+ public void commit() {
+ transactional.commit() ;
+ activeDSG = null ;
+ }
+
+ public void abort() {
+ try { transactional.abort() ; }
+ catch (Exception ex) {
+ // Some datasets claim to be transactional but
+ // don't provide a real abort. We tried to avoid
+ // them earlier but even if they sneek through,
+ // we try to continue server operation.
+ Log.warn(this, "Exception during abort (operation attempts to continue): "+ex.getMessage()) ;
+ }
+ activeDSG = null ;
+ }
+
+ public void endWrite() {
+ dsRef.finishTxn(WRITE) ;
+ activeMode = null ;
+
+ if ( transactional.isInTransaction() ) {
+ Log.warn(this, "Transaction still active in endWriter - no commit or abort seen (forced abort)") ;
+ try {
+ transactional.abort() ;
+ } catch (RuntimeException ex) {
+ Log.warn(this, "Exception in forced abort (trying to continue)", ex) ;
+ }
+ }
+ transactional.end() ;
+ activeDSG = null ;
+ }
+
+ public final DatasetGraph getActiveDSG() {
+ return activeDSG ;
+ }
+
+ public final DatasetRef getDatasetRef() {
+ return dsRef ;
+ }
+
+ /** 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 HttpServletResponseTracker 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) ;
+ }
+
+ public void sync() {
+ SystemARQ.sync(dsg) ;
+ }
+
+ public static MediaType contentNegotationRDF(HttpAction action) {
+ MediaType mt = ConNeg.chooseContentType(action.request, DEF.rdfOffer, DEF.acceptRDFXML) ;
+ if ( mt == null )
+ return null ;
+ if ( mt.getContentType() != null )
+ action.response.setContentType(mt.getContentType()) ;
+ if ( mt.getCharset() != null )
+ action.response.setCharacterEncoding(mt.getCharset()) ;
+ return mt ;
+ }
+
+ public static MediaType contentNegotationQuads(HttpAction action) {
+ return ConNeg.chooseContentType(action.request, DEF.quadsOffer, DEF.acceptNQuads) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/HttpServletResponseTracker.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/HttpServletResponseTracker.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/HttpServletResponseTracker.java
new file mode 100644
index 0000000..c39e728
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/HttpServletResponseTracker.java
@@ -0,0 +1,140 @@
+/*
+ * 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 javax.servlet.http.HttpServletResponse ;
+import javax.servlet.http.HttpServletResponseWrapper ;
+
+import org.apache.jena.atlas.logging.Log ;
+
+/** Intercepting wrapper so we can track the response settings for logging purposes */
+
+public class HttpServletResponseTracker extends HttpServletResponseWrapper
+{
+ private final HttpAction action ;
+
+ public HttpServletResponseTracker(HttpAction action, HttpServletResponse response)
+ {
+ super(response) ;
+ this.action = action ;
+ }
+
+ @Override
+ public void sendError(int sc, String msg) throws IOException
+ {
+ action.statusCode = sc ;
+ action.message = msg ;
+ super.sendError(sc, msg) ;
+ }
+
+ @Override
+ public void sendError(int sc) throws IOException
+ {
+ action.statusCode = sc ;
+ action.message = null ;
+ super.sendError(sc) ;
+ }
+
+ @Override
+ public void setHeader(String name, String value)
+ {
+ super.setHeader(name, value) ;
+ action.headers.put(name, value) ;
+ }
+
+ @Override
+ public void addHeader(String name, String value)
+ {
+ Log.warn(this, "Unexpected addHeader - not recorded in log") ;
+ super.addHeader(name, value) ;
+ }
+ @Override
+ public void setStatus(int sc)
+ {
+ action.statusCode = sc ;
+ action.message = null ;
+ super.setStatus(sc) ;
+ }
+
+ @Override
+ @Deprecated
+ public void setStatus(int sc, String sm)
+ {
+ action.statusCode = sc ;
+ action.message = sm ;
+ super.setStatus(sc, sm) ;
+ }
+
+ @Override
+ public void setContentLength(int len)
+ {
+ action.contentLength = len ;
+ super.setContentLength(len) ;
+ }
+
+ @Override
+ public void setContentType(String type)
+ {
+ action.contentType = type ;
+ super.setContentType(type) ;
+ }
+
+ // From HttpServletResponse
+// public void addCookie(Cookie cookie) {}
+// public boolean containsHeader(String name) {}
+// public String encodeURL(String url) { }
+// public String encodeRedirectURL(String url) {}
+// public String encodeUrl(String url) {}
+// public String encodeRedirectUrl(String url) {}
+// public void sendError(int sc, String msg) throws IOException
+// public void sendError(int sc) throws IOException
+// public void sendRedirect(String location) throws IOException {}
+// public void setDateHeader(String name, long date) {}
+// public void addDateHeader(String name, long date) {}
+// public void setHeader(String name, String value)
+// public void addHeader(String name, String value)
+// public void setIntHeader(String name, int value) {}
+// public void addIntHeader(String name, int value) {}
+// public void setStatus(int sc)
+// public void setStatus(int sc, String sm)
+// public void sendRedirect(String location) throws IOException {}
+// public void setDateHeader(String name, long date) {}
+// public void addDateHeader(String name, long date) {}
+
+ // From ServletResponse.
+// public ServletResponse getResponse() {}
+// public void setResponse(ServletResponse response) {}
+// public void setCharacterEncoding(String charset) {}
+// public String getCharacterEncoding() {}
+// public ServletOutputStream getOutputStream() throws IOException {}
+// public PrintWriter getWriter() throws IOException {}
+// public void setContentLength(int len) {}
+// public void setContentType(String type) {}
+// public String getContentType() {
+// public void setBufferSize(int size) {}
+// public int getBufferSize() {}
+// public void flushBuffer() throws IOException {}
+// public boolean isCommitted() {}
+// public void reset() {}
+// public void resetBuffer() {}
+// public void setLocale(Locale loc) {}
+// public Locale getLocale() {}
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/NullOutputStream.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/NullOutputStream.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/NullOutputStream.java
new file mode 100644
index 0000000..63e6562
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/NullOutputStream.java
@@ -0,0 +1,53 @@
+/*
+ * 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.* ;
+
+/**
+* Code needed to implement an OutputStream that does nothing.
+*/
+
+
+public class NullOutputStream extends /*Filter*/OutputStream
+{
+ public NullOutputStream()
+ {
+ }
+
+ // The OutputStream operations
+ @Override
+ public void close() { /* .close() ;*/ }
+ @Override
+ public void flush() { /* .flush() ;*/ }
+
+ // Need to implement this one.
+ @Override
+ public void write(int b) { /* .write(b) ;*/ }
+ @Override
+ public void write(byte b[]) { /* this.write(b, 0, b.length) ; */}
+
+ // Good to implement this one.
+ @Override
+ public void write(byte[] b, int off, int len)
+ {
+ // Work function
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads.java
new file mode 100644
index 0000000..06c38b7
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads.java
@@ -0,0 +1,211 @@
+/**
+ * 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.fuseki.Fuseki ;
+import org.apache.jena.fuseki.HttpNames ;
+import org.apache.jena.riot.Lang ;
+import org.apache.jena.riot.RDFDataMgr ;
+import org.apache.jena.riot.RDFLanguages ;
+import org.apache.jena.riot.ReaderRIOT ;
+import org.apache.jena.riot.system.StreamRDF ;
+import org.apache.jena.riot.system.StreamRDFLib ;
+
+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 ;
+
+/**
+ * Servlet that serves up quads for a dataset.
+ */
+
+public class REST_Quads extends SPARQL_REST
+{
+ public REST_Quads() { super(); }
+
+ @Override
+ protected void validate(HttpAction action)
+ {
+ // already checked?
+ }
+
+ @Override
+ protected void doGet(HttpAction action)
+ {
+ MediaType mediaType = HttpAction.contentNegotationQuads(action) ;
+ ServletOutputStream output ;
+ try { output = action.response.getOutputStream() ; }
+ catch (IOException ex) { 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 )
+ log.info(format("[%d] Get: Content-Type=%s, Charset=%s => %s",
+ action.id, mediaType.getContentType(), mediaType.getCharset(), lang.getName())) ;
+ if ( ! RDFLanguages.isQuads(lang) )
+ errorBadRequest("Not a quads format: "+mediaType) ;
+
+ action.beginRead() ;
+ try {
+ DatasetGraph dsg = action.getActiveDSG() ;
+ RDFDataMgr.write(out, dsg, lang) ;
+ 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") ;
+ success(action) ;
+ }
+
+ @Override
+ protected void doHead(HttpAction action)
+ {
+ action.beginRead() ;
+ try {
+ MediaType mediaType = HttpAction.contentNegotationQuads(action) ;
+ success(action) ;
+ } finally { action.endRead() ; }
+ }
+
+ static int counter = 0 ;
+ @Override
+ protected void doPost(HttpAction action)
+ {
+ if ( ! action.getDatasetRef().allowDatasetUpdate )
+ errorMethodNotAllowed("POST") ;
+
+ // Graph Store Protocol mode - POST triples to dataset causes
+ // a new graph to be created and the new URI returned via Location.
+ // Normally off.
+ // When off, POST of triples goes to default graph.
+ boolean gspMode = Fuseki.graphStoreProtocolPostCreate ;
+
+ // Code to pass the GSP test suite.
+ // Not necessarily good code.
+ String x = action.request.getContentType() ;
+ if ( x == null )
+ errorBadRequest("Content-type required for data format") ;
+
+ MediaType mediaType = MediaType.create(x) ;
+ Lang lang = RDFLanguages.contentTypeToLang(mediaType.getContentType()) ;
+ if ( lang == null )
+ lang = RDFLanguages.TRIG ;
+
+ if ( action.verbose )
+ log.info(format("[%d] Post: Content-Type=%s, Charset=%s => %s",
+ action.id, mediaType.getContentType(), mediaType.getCharset(), lang.getName())) ;
+
+ if ( RDFLanguages.isQuads(lang) )
+ doPostQuads(action, lang) ;
+ else if ( gspMode && RDFLanguages.isTriples(lang) )
+ doPostTriplesGSP(action, lang) ;
+ else if ( RDFLanguages.isTriples(lang) )
+ doPostTriples(action, lang) ;
+ else
+ errorBadRequest("Not a triples or quads format: "+mediaType) ;
+ }
+
+ protected void doPostQuads(HttpAction action, Lang lang)
+ {
+ action.beginWrite() ;
+ try {
+ String name = action.request.getRequestURL().toString() ;
+ DatasetGraph dsg = action.getActiveDSG() ;
+ StreamRDF dest = StreamRDFLib.dataset(dsg) ;
+ ReaderRIOT reader = RDFDataMgr.createReader(lang) ;
+ reader.read(action.request.getInputStream(), name, null, dest, null);
+ action.commit();
+ success(action) ;
+ } catch (IOException ex) { action.abort() ; }
+ finally { action.endWrite() ; }
+ }
+
+
+ // POST triples to dataset -- send to default graph.
+ protected void doPostTriples(HttpAction action, Lang lang)
+ {
+ action.beginWrite() ;
+ try {
+ DatasetGraph dsg = action.getActiveDSG() ;
+ // This should not be anythign other than the datasets name via this route.
+ String name = action.request.getRequestURL().toString() ;
+ //log.info(format("[%d] ** Content-length: %d", action.id, action.request.getContentLength())) ;
+ Graph g = dsg.getDefaultGraph() ;
+ StreamRDF dest = StreamRDFLib.graph(g) ;
+ ReaderRIOT reader = RDFDataMgr.createReader(lang) ;
+ reader.read(action.request.getInputStream(), name, null, dest, null);
+ action.commit();
+ success(action) ;
+ } catch (IOException ex) { action.abort() ; }
+ finally { action.endWrite() ; }
+ }
+
+ protected void doPostTriplesGSP(HttpAction action, Lang lang)
+ {
+ action.beginWrite() ;
+ try {
+ DatasetGraph dsg = action.getActiveDSG() ;
+ //log.info(format("[%d] ** Content-length: %d", action.id, action.request.getContentLength())) ;
+
+ String name = action.request.getRequestURL().toString() ;
+ if ( ! name.endsWith("/") )
+ name = name+ "/" ;
+ name = name+(++counter) ;
+ Node gn = NodeFactory.createURI(name) ;
+ Graph g = dsg.getGraph(gn) ;
+ StreamRDF dest = StreamRDFLib.graph(g) ;
+ ReaderRIOT reader = RDFDataMgr.createReader(lang) ;
+ reader.read(action.request.getInputStream(), name, null, dest, null);
+ log.info(format("[%d] Location: %s", action.id, name)) ;
+ action.response.setHeader("Location", name) ;
+ action.commit();
+ successCreated(action) ;
+ } catch (IOException ex) { action.abort() ; }
+ finally { action.endWrite() ; }
+ }
+
+ @Override
+ protected void doDelete(HttpAction action)
+ { errorMethodNotAllowed("DELETE") ; }
+
+ @Override
+ protected void doPut(HttpAction action)
+ { errorMethodNotAllowed("PUT") ; }
+
+ @Override
+ protected void doPatch(HttpAction action)
+ { errorMethodNotAllowed("PATCH") ; }
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseCallback.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseCallback.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseCallback.java
new file mode 100644
index 0000000..1a78627
--- /dev/null
+++ b/jena-fuseki1/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/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseModel.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseModel.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseModel.java
new file mode 100644
index 0000000..f2172f0
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseModel.java
@@ -0,0 +1,143 @@
+/*
+ * 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.fuseki.servlets.ServletBase.error ;
+import static org.apache.jena.fuseki.servlets.ServletBase.errorBadRequest ;
+import static org.apache.jena.fuseki.servlets.ServletBase.errorOccurred ;
+
+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 org.apache.jena.riot.WebContent ;
+import org.apache.jena.web.HttpSC ;
+import org.slf4j.Logger ;
+
+import com.hp.hpl.jena.rdf.model.Model ;
+
+public class ResponseModel
+{
+ private static Logger slog = ServletBase.log ;
+
+ // 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, WebContent.contentTypeJSONLD) ;
+ ResponseOps.put(shortNamesModel, contentOutputJSONRDF, WebContent.contentTypeRDFJSON) ;
+ ResponseOps.put(shortNamesModel, contentOutputJSON, WebContent.contentTypeJSONLD) ;
+ ResponseOps.put(shortNamesModel, contentOutputXML, WebContent.contentTypeRDFXML) ;
+ ResponseOps.put(shortNamesModel, contentOutputText, WebContent.contentTypeTurtle) ;
+ ResponseOps.put(shortNamesModel, contentOutputTTL, WebContent.contentTypeTurtle) ;
+ ResponseOps.put(shortNamesModel, contentOutputNT, WebContent.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.requestLog.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" ;
+ error(HttpSC.NOT_ACCEPTABLE_406, msg) ;
+ }
+
+ String contentType = mimeType ;
+ String charset = WebContent.charsetUTF8 ;
+
+ String forceAccept = ResponseOps.paramForceAccept(request) ;
+ if ( forceAccept != null )
+ {
+ contentType = forceAccept ;
+ charset = WebContent.charsetUTF8 ;
+ }
+
+ Lang lang = RDFLanguages.contentTypeToLang(contentType) ;
+ if ( lang == null )
+ 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(request, response, contentType, charset) ;
+ response.setStatus(HttpSC.OK_200) ;
+ ServletOutputStream out = response.getOutputStream() ;
+ RDFDataMgr.write(out, model, lang) ;
+ out.flush() ;
+ }
+ catch (Exception ex) {
+ slog.info("Exception while writing the response model: "+ex.getMessage(), ex) ;
+ errorOccurred("Exception while writing the response model: "+ex.getMessage(), ex) ;
+ }
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseOps.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseOps.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseOps.java
new file mode 100644
index 0000000..62ad6d5
--- /dev/null
+++ b/jena-fuseki1/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.fuseki.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/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java
new file mode 100644
index 0000000..c42378b
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java
@@ -0,0 +1,320 @@
+/*
+ * 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.fuseki.servlets.ServletBase.errorBadRequest ;
+import static org.apache.jena.fuseki.servlets.ServletBase.errorOccurred ;
+import static org.apache.jena.fuseki.servlets.ServletBase.log ;
+
+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.commons.lang.StringUtils ;
+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) ;
+ private static Logger slog = ServletBase.log ;
+
+ // 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<String, String>() ;
+ static {
+ // Some short names. keys are lowercase.
+ ResponseOps.put(shortNamesResultSet, contentOutputJSON, WebContent.contentTypeResultsJSON) ;
+ ResponseOps.put(shortNamesResultSet, contentOutputSPARQL, WebContent.contentTypeResultsXML) ;
+ ResponseOps.put(shortNamesResultSet, contentOutputXML, WebContent.contentTypeResultsXML) ;
+ ResponseOps.put(shortNamesResultSet, contentOutputText, WebContent.contentTypeTextPlain) ;
+ ResponseOps.put(shortNamesResultSet, contentOutputCSV, WebContent.contentTypeTextCSV) ;
+ ResponseOps.put(shortNamesResultSet, contentOutputTSV, WebContent.contentTypeTextTSV) ;
+ ResponseOps.put(shortNamesResultSet, contentOutputThrift, WebContent.contentTypeResultsThrift) ;
+ }
+
+ interface OutputContent { void output(ServletOutputStream out) ; }
+
+ public static void doResponseResultSet(HttpAction action, Boolean booleanResult)
+ {
+ doResponseResultSet$(action, null, booleanResult, null, DEF.rsOfferTable) ;
+ }
+
+ 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,WebContent.contentTypeResultsXML) )
+ contentType = WebContent.contentTypeXML ;
+
+ // Force to text/plain?
+ String forceAccept = ResponseOps.paramForceAccept(request) ;
+ if ( forceAccept != null )
+ contentType = WebContent.contentTypeTextPlain ;
+
+ // Better : dispatch on MediaType
+ // Fuseki2 uses the SPARQL parser/write registry.
+ if ( equal(serializationType, WebContent.contentTypeResultsXML) )
+ sparqlXMLOutput(action, contentType, resultSet, stylesheetURL, booleanResult) ;
+ else if ( equal(serializationType, WebContent.contentTypeResultsJSON) )
+ jsonOutput(action, contentType, resultSet, booleanResult) ;
+ else if ( equal(serializationType, WebContent.contentTypeTextPlain) )
+ textOutput(action, contentType, resultSet, qPrologue, booleanResult) ;
+ else if ( equal(serializationType, WebContent.contentTypeTextCSV) )
+ csvOutput(action, contentType, resultSet, booleanResult) ;
+ else if (equal(serializationType, WebContent.contentTypeTextTSV) )
+ tsvOutput(action, contentType, resultSet, booleanResult) ;
+ else if (equal(serializationType, WebContent.contentTypeResultsThrift) )
+ thriftOutput(action, contentType, resultSet, booleanResult) ;
+ else
+ errorBadRequest("Can't determine output serialization: "+serializationType) ;
+ }
+
+
+ public static void setHttpResponse(HttpServletRequest httpRequest,
+ HttpServletResponse httpResponse,
+ String contentType, String charset)
+ {
+ // ---- Set up HTTP Response
+ // Stop caching (not that ?queryString URLs are cached anyway)
+ if ( true )
+ {
+ httpResponse.setHeader("Cache-Control", "no-cache") ;
+ httpResponse.setHeader("Pragma", "no-cache") ;
+ }
+ // See: http://www.w3.org/International/O-HTTP-charset.html
+ if ( contentType != null )
+ {
+ if ( charset != null && ! isXML(contentType) )
+ contentType = contentType+"; charset="+charset ;
+ log.trace("Content-Type for response: "+contentType) ;
+ httpResponse.setContentType(contentType) ;
+ }
+ }
+
+ private static boolean isXML(String contentType)
+ {
+ return contentType.equals(WebContent.contentTypeRDFXML)
+ || contentType.equals(WebContent.contentTypeResultsXML)
+ || contentType.equals(WebContent.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, 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 ) ;
+ }
+ } ;
+
+ try {
+ String callback = ResponseOps.paramCallback(action.request) ;
+ ServletOutputStream out = action.response.getOutputStream() ;
+
+ if ( callback != null )
+ {
+ callback = StringUtils.replaceChars(callback, "\r", "") ;
+ callback = StringUtils.replaceChars(callback, "\n", "") ;
+ out.print(callback) ;
+ out.println("(") ;
+ }
+
+ output(action, contentType, WebContent.charsetUTF8, proc) ;
+
+ if ( callback != null )
+ out.println(")") ;
+ } catch (IOException ex) { errorOccurred(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 ) ;
+ }
+ };
+
+ output(action, contentType, WebContent.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 ) ;
+ }
+ } ;
+ output(action, contentType, WebContent.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 ) ;
+ }
+ } ;
+ output(action, contentType, WebContent.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 )
+ slog.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.request, action.response, contentType, charset) ;
+ action.response.setStatus(HttpSC.OK_200) ;
+ ServletOutputStream out = action.response.getOutputStream() ;
+ try
+ {
+ proc.output(out) ;
+ out.flush() ;
+ } catch (QueryCancelledException ex) {
+ // Bother. Status code 200 already sent.
+ slog.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)
+ { 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/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Protocol.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Protocol.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Protocol.java
new file mode 100644
index 0000000..ed57a37
--- /dev/null
+++ b/jena-fuseki1/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.fuseki.HttpNames.paramDefaultGraphURI ;
+import static org.apache.jena.fuseki.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 SPARQL_ServletBase
+{
+ 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 ;
+ }
+
+
+}
+