JENA-1435: New request dispatcher

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

Branch: refs/heads/master
Commit: 6d89af352e1a92dd1338f5d9c6f9641581423cdc
Parents: 057fc73
Author: Andy Seaborne <[email protected]>
Authored: Fri Nov 24 13:35:29 2017 +0000
Committer: Andy Seaborne <[email protected]>
Committed: Tue Dec 12 10:07:37 2017 +0000

----------------------------------------------------------------------
 .../java/org/apache/jena/fuseki/Fuseki.java     |   8 +-
 .../apache/jena/fuseki/build/FusekiBuilder.java |  27 +-
 .../org/apache/jena/fuseki/mgt/ActionCtl.java   |   3 +-
 .../apache/jena/fuseki/mgt/ActionDatasets.java  |  12 +-
 .../jena/fuseki/server/DataAccessPoint.java     |   1 -
 .../apache/jena/fuseki/server/DataService.java  |  25 +-
 .../apache/jena/fuseki/server/FusekiSystem.java |   2 +-
 .../jena/fuseki/server/OperationName.java       |  24 +-
 .../apache/jena/fuseki/servlets/ActionBase.java |  12 +-
 .../apache/jena/fuseki/servlets/ActionLib.java  |  45 +-
 .../jena/fuseki/servlets/ActionSPARQL.java      |  94 ++-
 .../apache/jena/fuseki/servlets/Dispatch.java   |  62 ++
 .../jena/fuseki/servlets/FusekiFilter.java      |   6 +-
 .../apache/jena/fuseki/servlets/HttpAction.java |  24 +-
 .../servlets/HttpServletResponseTracker.java    |   4 +-
 .../jena/fuseki/servlets/SPARQL_Query.java      |   4 +-
 .../fuseki/servlets/SPARQL_UberServlet.java     | 412 -------------
 .../servlets/SPARQL_UberServlet_Original.java   | 416 ++++++++++++++
 .../jena/fuseki/servlets/SPARQL_Update.java     |   2 -
 .../jena/fuseki/servlets/SPARQL_Upload.java     |  10 +-
 .../fuseki/servlets/ServiceRouterServlet.java   | 573 +++++++++++++++++++
 .../org/apache/jena/fuseki/servlets/Upload.java |   4 +-
 .../jena/fuseki/servlets/package-info.java      |  61 ++
 .../org/apache/jena/fuseki/TestDatasetOps.java  |  11 +-
 .../apache/jena/fuseki/TestHttpOperations.java  |   5 +-
 .../jena/fuseki/embedded/FusekiServer.java      |   2 +-
 26 files changed, 1318 insertions(+), 531 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/Fuseki.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/Fuseki.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/Fuseki.java
index 01f6a71..4a4d4bd 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/Fuseki.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/Fuseki.java
@@ -102,10 +102,14 @@ public class Fuseki {
      *  quite sensitive to request route.
      *  <p>
      *  The following places use this switch:
+     *  <ul>
      *  <li>{@code FusekiFilter} for the "clearly not a service" case
-     *  <li>{@code SPARQL_UberServlet}, end of dispatch (after checking for 
http://server/dataset/service)
+     *  <li>{@code ServiceRouterServlet}, end of dispatch (after checking for 
http://server/dataset/service)
      *  <li>{@code SPARQL_GSP.determineTarget} This is all-purpose code - 
should not get there because of other checks.
-     *
+     *  </ul>
+     *  <p>
+     * <b>Note</b><br/>
+     * GSP Direct Naming was implemented to provide two implementations for 
the SPARQL 1.1 implementation report.  
      */
     static public final boolean       GSP_DIRECT_NAMING = false ;
 

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiBuilder.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiBuilder.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiBuilder.java
index c2c4f5f..9eb3b4a 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiBuilder.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiBuilder.java
@@ -46,7 +46,7 @@ public class FusekiBuilder
 {
     private static Logger log = Fuseki.builderLog ;
     
-    /** Build a DataAccessPoint, including DataService at Resource svc */ 
+    /** Build a DataAccessPoint, including DataService, from the description 
at Resource svc */ 
     public static DataAccessPoint buildDataAccessPoint(Resource svc, 
DatasetDescriptionRegistry dsDescMap) {
         RDFNode n = FusekiLib.getOne(svc, "fu:name") ;
         if ( ! n.isLiteral() )
@@ -58,13 +58,13 @@ public class FusekiBuilder
         String name = object.getLexicalForm() ;
         name = DataAccessPoint.canonical(name) ;
 
-        DataService dataService = FusekiBuilder.buildDataService(svc, 
dsDescMap) ;
+        DataService dataService = buildDataServiceCustom(svc, dsDescMap) ;
         DataAccessPoint dataAccess = new DataAccessPoint(name, dataService) ;
         return dataAccess ;
     }
 
-    /** Build a DatasetRef starting at Resource svc */
-    private static DataService buildDataService(Resource svc, 
DatasetDescriptionRegistry dsDescMap) {
+    /** Build a DatasetRef starting at Resource svc, having the services as 
described by the descriptions. */
+    private static DataService buildDataServiceCustom(Resource svc, 
DatasetDescriptionRegistry dsDescMap) {
         if ( log.isDebugEnabled() ) log.debug("Service: " + nodeLabel(svc)) ;
         Resource datasetDesc = ((Resource)getOne(svc, "fu:dataset")) ;
         Dataset ds = getDataset(datasetDesc, dsDescMap);
@@ -83,13 +83,19 @@ public class FusekiBuilder
         
         // Quads - actions directly on the dataset URL are different.
         // In the config file they are also implicit when using GSP.
+        
         if ( ! dataService.getOperation(OperationName.GSP_RW).isEmpty() || ! 
dataService.getOperation(OperationName.Quads_RW).isEmpty() ) {
-            dataService.addEndpoint(OperationName.Quads_RW, "") ;
+            // ReadWrite available.
+            // Dispatch needs introspecting on the HTTP request.
+            dataService.addEndpoint(OperationName.DatasetRequest_RW, "") ;
         } else if ( ! dataService.getOperation(OperationName.GSP_R).isEmpty() 
|| ! dataService.getOperation(OperationName.Quads_R).isEmpty() ) {
-            dataService.addEndpoint(OperationName.Quads_R, "") ;
+            // Read-only available.
+            // Dispatch needs introspecting on the HTTP request.
+            dataService.addEndpoint(OperationName.DatasetRequest_R, "") ;
         }
         
         // XXX 
+        // This needs sorting out -- here, it is only on the whole server, not 
per dataset or even per service.
 //        // Extract timeout overriding configuration if present.
 //        if ( svc.hasProperty(FusekiVocab.pAllowTimeoutOverride) ) {
 //            sDesc.allowTimeoutOverride = 
svc.getProperty(FusekiVocab.pAllowTimeoutOverride).getObject().asLiteral().getBoolean()
 ;
@@ -116,21 +122,22 @@ public class FusekiBuilder
        return ds;
     }
     
-    /** Build a DataService starting at Resource svc */
-    public static DataService buildDataService(DatasetGraph dsg, boolean 
allowUpdate) {
+    /** Build a DataService starting at Resource svc, with the standard 
(default) set of services */
+    public static DataService buildDataServiceStd(DatasetGraph dsg, boolean 
allowUpdate) {
         DataService dataService = new DataService(dsg) ;
         addServiceEP(dataService, OperationName.Query, "query") ;
         addServiceEP(dataService, OperationName.Query, "sparql") ;
         if ( ! allowUpdate ) {
             addServiceEP(dataService, OperationName.GSP_R,      "data") ;
-            addServiceEP(dataService, OperationName.Quads_R,    "") ;
+            addServiceEP(dataService, OperationName.DatasetRequest_R,    "") ;
             return dataService ;
         }
         addServiceEP(dataService, OperationName.GSP_RW,     "data") ;
         addServiceEP(dataService, OperationName.GSP_R,      "get") ;
         addServiceEP(dataService, OperationName.Update,     "update") ;
         addServiceEP(dataService, OperationName.Upload,     "upload") ;
-        addServiceEP(dataService, OperationName.Quads_RW,   "") ;
+        // Dispatch needs introspecting on the HTTP request.
+        addServiceEP(dataService, OperationName.DatasetRequest_RW, "") ;
         return dataService ;
     }
 

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionCtl.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionCtl.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionCtl.java
index 456f97b..4909612 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionCtl.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionCtl.java
@@ -59,8 +59,7 @@ public abstract class ActionCtl extends ActionBase
         return extractItemName(action) ;
     }
 
-    // Execute - no stats.
-    // Intercept point for the UberServlet 
+    // Possible intercept point 
     protected void executeAction(HttpAction action) {
         executeLifecycle(action) ;
     }

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java
index b21d29b..b772372 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java
@@ -46,7 +46,10 @@ import org.apache.jena.fuseki.build.FusekiBuilder ;
 import org.apache.jena.fuseki.build.Template ;
 import org.apache.jena.fuseki.build.TemplateFunctions ;
 import org.apache.jena.fuseki.server.* ;
-import org.apache.jena.fuseki.servlets.* ;
+import org.apache.jena.fuseki.servlets.ActionLib;
+import org.apache.jena.fuseki.servlets.HttpAction;
+import org.apache.jena.fuseki.servlets.ServletOps;
+import org.apache.jena.fuseki.servlets.Upload;
 import org.apache.jena.graph.Node ;
 import org.apache.jena.graph.NodeFactory ;
 import org.apache.jena.query.Dataset ;
@@ -431,8 +434,11 @@ public class ActionDatasets extends ActionContainerItem {
         try { input = request.getInputStream() ; } 
         catch (IOException ex) { IO.exception(ex) ; }
 
+        // Don't log - assemblers are typically small.
+        // Adding this to the log confuses things.
+        // Reserve logging for data uploads. 
 //        int len = request.getContentLength() ;
-//        if ( verbose ) {
+//        if ( action.verbose ) {
 //            if ( len >= 0 )
 //                alog.info(format("[%d]   Body: Content-Length=%d, 
Content-Type=%s, Charset=%s => %s", action.id, len,
 //                                ct.getContentType(), ct.getCharset(), 
lang.getName())) ;
@@ -441,6 +447,6 @@ public class ActionDatasets extends ActionContainerItem {
 //                                ct.getCharset(), lang.getName())) ;
 //        }
         dest.prefix("root", base+"#");
-        ActionSPARQL.parse(action, dest, input, lang, base) ;
+        ActionLib.parse(action, dest, input, lang, base) ;
     }
 }

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataAccessPoint.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataAccessPoint.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataAccessPoint.java
index 5fac02f..53fb4d4 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataAccessPoint.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataAccessPoint.java
@@ -22,7 +22,6 @@ import java.util.concurrent.atomic.AtomicLong ;
 
 import org.apache.jena.fuseki.servlets.HttpAction ;
 
-
 /** A name in the URL space of the server */
 public class DataAccessPoint {
     private final String name ;

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataService.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataService.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataService.java
index ac87b4b..d191272 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataService.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataService.java
@@ -92,7 +92,7 @@ public class DataService { //implements DatasetMXBean {
         operations.put(operationName, endpoint);
     }
     
-    public Endpoint getOperation(String endpointName) {
+    public Endpoint getEndpoint(String endpointName) {
         return endpoints.get(endpointName) ;
     }
 
@@ -113,18 +113,23 @@ public class DataService { //implements DatasetMXBean {
     //@Override
     public boolean allowUpdate()    { return true ; }
 
-    public void goOffline()         { 
-        offlineInProgress.set(true) ;
-        acceptingRequests.set(false) ;
-        state = DatasetStatus.OFFLINE ; 
+    public void goOffline() {
+        offlineInProgress.set(true);
+        acceptingRequests.set(false);
+        state = DatasetStatus.OFFLINE;
     }
-    
-    public void goActive()         { 
-        offlineInProgress.set(false) ;
-        acceptingRequests.set(true) ;
-        state = DatasetStatus.ACTIVE ; 
+
+    public void goActive() {
+        offlineInProgress.set(false);
+        acceptingRequests.set(true);
+        state = DatasetStatus.ACTIVE;
     }
 
+    // Due to concurrency, call isAcceptingRequests().
+//    public boolean isActive() {
+//        return state != DatasetStatus.ACTIVE;
+//    }
+
     public boolean isAcceptingRequests() {
         return acceptingRequests.get() ;
     }

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/FusekiSystem.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/FusekiSystem.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/FusekiSystem.java
index 6a95765..78f6490 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/FusekiSystem.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/FusekiSystem.java
@@ -350,7 +350,7 @@ public class FusekiSystem
     
     private static DataAccessPoint datasetDefaultConfiguration( String name, 
DatasetGraph dsg, boolean allowUpdate) {
         name = DataAccessPoint.canonical(name) ;
-        DataService ds = FusekiBuilder.buildDataService(dsg, allowUpdate) ;
+        DataService ds = FusekiBuilder.buildDataServiceStd(dsg, allowUpdate) ;
         DataAccessPoint dap = new DataAccessPoint(name, ds) ;
         return dap ;
     }

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/OperationName.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/OperationName.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/OperationName.java
index e152645..c18b0a8 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/OperationName.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/OperationName.java
@@ -29,13 +29,17 @@ public class OperationName {
     static private NameMgr<OperationName> mgr = new NameMgr<>(); 
     static public OperationName register(String name, String description) { 
return mgr.register(name, (x)->new OperationName(x, description)); }
     
-    public static final OperationName Query    = register("Query", "SPARQL 
Query");
-    public static final OperationName Update   = register("Update", "SPARQL 
Update");
-    public static final OperationName Upload   = register("Upload", "File 
Upload");
-    public static final OperationName GSP_RW   = register("GSP_RW", "Graph 
Store Protocol");
-    public static final OperationName GSP_R    = register("GSP_R", "Graph 
Store Protocol (Read)");
-    public static final OperationName Quads_RW = register("Quads_RW", "HTTP 
Quads");
-    public static final OperationName Quads_R  = register("Quads_R", "HTTP 
Quads (Read)");
+    public static final OperationName Query          = register("Query", 
"SPARQL Query");
+    public static final OperationName Update         = register("Update", 
"SPARQL Update");
+    public static final OperationName Upload         = register("Upload", 
"File Upload");
+    public static final OperationName GSP_RW         = register("GSP_RW", 
"Graph Store Protocol");
+    public static final OperationName GSP_R          = register("GSP_R", 
"Graph Store Protocol (Read)");
+    public static final OperationName Quads_RW       = register("Quads_RW", 
"HTTP Quads");
+    public static final OperationName Quads_R        = register("Quads_R", 
"HTTP Quads (Read)");
+    
+    // Dummy "operation" used to mark that datasets accept request made 
directly on them. 
+    public static final OperationName DatasetRequest_RW = Quads_RW; 
//register("Dataset", "HTTP Request");
+    public static final OperationName DatasetRequest_R = Quads_R; 
//register("Dataset", "HTTP Request");
     
     private final String description ;
     private final String name ;
@@ -80,6 +84,10 @@ public class OperationName {
             return false;
         return true;
     }
-    
+ 
+    @Override
+    public String toString() {
+        return name;
+    }
 }
 

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionBase.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionBase.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionBase.java
index a64f2ee..3a2cecd 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionBase.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionBase.java
@@ -234,15 +234,15 @@ public abstract class ActionBase extends ServletBase
 
         HttpServletResponseTracker response = action.response ;
         if ( action.verbose ) {
-            if ( action.contentType != null )
-                log.info(format("[%d]   <= %-20s %s", action.id, 
HttpNames.hContentType+":", action.contentType)) ;
-            if ( action.contentLength != -1 )
-                log.info(format("[%d]   <= %-20s %d", action.id, 
HttpNames.hContentLengh+":", action.contentLength)) ;
+            if ( action.responseContentType != null )
+                log.info(format("[%d]   <= %-20s %s", action.id, 
HttpNames.hContentType+":", action.responseContentType)) ;
+            if ( action.responseContentLength != -1 )
+                log.info(format("[%d]   <= %-20s %d", action.id, 
HttpNames.hContentLengh+":", action.responseContentLength)) ;
             for (Map.Entry<String, String> e : action.headers.entrySet()) {
                 // Skip already printed.
-                if ( e.getKey().equalsIgnoreCase(HttpNames.hContentType) && 
action.contentType != null)
+                if ( e.getKey().equalsIgnoreCase(HttpNames.hContentType) && 
action.responseContentType != null)
                     continue;
-                if ( e.getKey().equalsIgnoreCase(HttpNames.hContentLengh) && 
action.contentLength != -1)
+                if ( e.getKey().equalsIgnoreCase(HttpNames.hContentLengh) && 
action.responseContentLength != -1)
                     continue;
                 log.info(format("[%d]   <= %-20s %s", action.id, 
e.getKey()+":", e.getValue())) ;
             }

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionLib.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionLib.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionLib.java
index ae911d0..49e25eb 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionLib.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionLib.java
@@ -18,14 +18,25 @@
 
 package org.apache.jena.fuseki.servlets;
 
+import java.io.InputStream;
+import java.nio.charset.CharacterCodingException;
+
 import javax.servlet.http.HttpServletRequest ;
 
+import org.apache.jena.atlas.RuntimeIOException;
 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.conneg.ConNeg ;
 import org.apache.jena.fuseki.server.DataAccessPoint ;
 import org.apache.jena.fuseki.server.DataAccessPointRegistry ;
+import org.apache.jena.riot.Lang;
+import org.apache.jena.riot.RDFParser;
+import org.apache.jena.riot.RDFParserRegistry;
+import org.apache.jena.riot.RiotException;
+import org.apache.jena.riot.system.ErrorHandler;
+import org.apache.jena.riot.system.ErrorHandlerFactory;
+import org.apache.jena.riot.system.StreamRDF;
 
 /** Operations related to servlets */
 
@@ -35,7 +46,8 @@ public class ActionLib {
      * that assumes the form /dataset/service.
      * @param action the request
      * @return the dataset
-     */    public static String mapRequestToDataset(HttpAction action) {
+     */
+    public static String mapRequestToDataset(HttpAction action) {
          String uri = action.getActionURI() ;
          return mapActionRequestToDataset(uri) ;
      }
@@ -62,7 +74,7 @@ public class ActionLib {
         return uri.substring(0, i) ;
     }
 
-    /** Calculate the operation , given action and data access point */ 
+    /** Calculate the operation, given action and data access point */ 
     public static String mapRequestToOperation(HttpAction action, 
DataAccessPoint dsRef) {
         if ( dsRef == null )
             return "" ;
@@ -134,9 +146,12 @@ public class ActionLib {
         return actionURI(action.request) ;
     }
     
+    /**
+     * @return the URI without context path of the webapp.
+     */
     public static String actionURI(HttpServletRequest request) {
 //      Log.info(this, "URI                     = '"+request.getRequestURI()) ;
-//      Log.info(this, "Context path            = 
'"+request.getContextPath()+"'") ;
+//      Log.info(this, "Context Path            = 
'"+request.getContextPath()+"'") ;
 //      Log.info(this, "Servlet path            = 
'"+request.getServletPath()+"'") ;
 //      ServletContext cxt = this.getServletContext() ;
 //      Log.info(this, "ServletContext path     = '"+cxt.getContextPath()+"'") 
;
@@ -150,7 +165,6 @@ public class ActionLib {
         String x = uri ;
         if ( uri.startsWith(contextPath) )
             x = uri.substring(contextPath.length()) ;
-        //log.info("uriWithoutContextPath: uri = "+uri+" 
contextPath="+contextPath+ "--> x="+x) ;
         return x ;
     }
 
@@ -176,5 +190,28 @@ public class ActionLib {
     public static MediaType contentNegotationQuads(HttpAction action) {
         return contentNegotation(action, DEF.quadsOffer, DEF.acceptNQuads) ;
     }
+    
+
+    /** 
+     * Parse RDF content
+     */
+    public static void parse(HttpAction action, StreamRDF dest, InputStream 
input, Lang lang, String base) {
+        try {
+            if ( ! RDFParserRegistry.isRegistered(lang) )
+                ServletOps.errorBadRequest("No parser for language 
'"+lang.getName()+"'") ;
+            ErrorHandler errorHandler = 
ErrorHandlerFactory.errorHandlerStd(action.log);
+            RDFParser.create()
+                .errorHandler(errorHandler)
+                .source(input)
+                .lang(lang)
+                .base(base)
+                .parse(dest);
+        } catch (RuntimeIOException ex) {
+            if ( ex.getCause() instanceof CharacterCodingException )
+                throw new RiotException("Character Coding Error: 
"+ex.getMessage());
+            throw ex;
+        }
+        catch (RiotException ex) { ServletOps.errorBadRequest("Parse error: 
"+ex.getMessage()) ; }
+    }
 }
 

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionSPARQL.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionSPARQL.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionSPARQL.java
index 93cdbfa..1a0097d 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionSPARQL.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionSPARQL.java
@@ -18,21 +18,20 @@
 
 package org.apache.jena.fuseki.servlets;
 
+import static java.lang.String.format;
 import static org.apache.jena.fuseki.server.CounterName.Requests ;
 import static org.apache.jena.fuseki.server.CounterName.RequestsBad ;
 import static org.apache.jena.fuseki.server.CounterName.RequestsGood ;
 
-import java.io.InputStream ;
-import java.nio.charset.CharacterCodingException;
+import java.io.IOException;
+
+import javax.servlet.ServletException;
 
 import org.apache.jena.atlas.RuntimeIOException ;
 import org.apache.jena.fuseki.Fuseki ;
 import org.apache.jena.fuseki.server.* ;
 import org.apache.jena.query.QueryCancelledException ;
-import org.apache.jena.riot.*;
-import org.apache.jena.riot.system.ErrorHandler ;
-import org.apache.jena.riot.system.ErrorHandlerFactory ;
-import org.apache.jena.riot.system.StreamRDF ;
+import org.apache.jena.web.HttpSC;
 
 /** SPARQL request lifecycle */
 public abstract class ActionSPARQL extends ActionBase
@@ -62,10 +61,9 @@ public abstract class ActionSPARQL extends ActionBase
                 ServletOps.errorNotFound("No dataset for URI: "+datasetUri) ;
                 return ;
             }
-            //dataAccessPoint.
             dSrv = dataAccessPoint.getDataService() ;
             if ( ! dSrv.isAcceptingRequests() ) {
-                ServletOps.errorNotFound("Dataset not active: "+datasetUri) ;
+                ServletOps.error(HttpSC.SERVICE_UNAVAILABLE_503, "Dataset not 
currently active");
                 return ;
             }
         } else {
@@ -73,16 +71,69 @@ public abstract class ActionSPARQL extends ActionBase
             dSrv = DataService.serviceOnlyDataService() ;
         }
 
-        String operationName = mapRequestToOperation(action, dataAccessPoint) ;
         action.setRequest(dataAccessPoint, dSrv) ;
+        String endpointName = mapRequestToOperation(action, dataAccessPoint) ;
         
-        //operationName = ""
+        if ( true ) {
+            // New dispatch
+            OperationName opName = null;
+            if ( ! endpointName.isEmpty() ) {
+                 opName = chooseEndpoint(action, dSrv, endpointName);
+                if ( opName == null )
+                    ServletOps.errorNotFound(format("dataset=%s, service=%s", 
dataAccessPoint.getName(), endpointName));
+                
+            } else {
+                opName = chooseEndpoint(action, dSrv);
+                if ( opName == null )
+                    ServletOps.errorBadRequest(format("dataset=%s",  
dataAccessPoint.getName()));
+            }
+            
+            ActionSPARQL handler = Dispatch.OpNameToHandler.get(opName);
+            // XXX -- replace action.setEndpoint
+            Endpoint ep = dSrv.getEndpoint(endpointName) ;
+            //List<Endpoint> endpoints = dSrv.getOperation(opName);
+            action.setEndpoint(ep, endpointName);
+            handler.executeLifecycle(action);
+            return ;
+        }
         
-        Endpoint op = dSrv.getOperation(operationName) ;
-        action.setEndpoint(op, operationName);
+        // Old dispatch via SPARQL_UberServlet.executeAction override.
+        Endpoint op = dSrv.getEndpoint(endpointName) ;
+        action.setEndpoint(op, endpointName);
         executeAction(action) ;
     }
 
+    // These are overridden by the ServiceRouterServlet.
+    protected OperationName chooseEndpoint(HttpAction action, DataService 
dataService, String serviceName) {
+        Endpoint ep = dataService.getEndpoint(serviceName) ;
+        OperationName opName = ep.getOperationName();
+        return opName;
+    }
+    
+    protected OperationName chooseEndpoint(HttpAction action, DataService 
dataService) {
+        // No default implementation for directly bound services operation 
servlets.
+        return null;
+    }
+
+    private void executeRequest(HttpAction action, ActionSPARQL servlet) {
+        if ( true ) {
+            // Execute an ActionSPARQL.
+            // Bypasses HttpServlet.service to doMethod dispatch.
+            servlet.executeLifecycle(action) ;
+            return ;
+        }
+        if ( false )  {
+            // Execute by calling the whole servlet mechanism.
+            // This causes HttpServlet.service to call the appropriate 
doMethod.
+            // but the action, and the id, are not passed on and a ne one is 
created.
+            try { servlet.service(action.request, action.response) ; }
+            catch (ServletException | IOException e) {
+                ServletOps.errorOccurred(e);
+            }
+        }
+    }
+
+    
     /** Execute a SPARQL request. Statistics have not been adjusted at this 
point.
      * 
      * @param action
@@ -194,23 +245,4 @@ public abstract class ActionSPARQL extends ActionBase
             Fuseki.serverLog.warn("Exception on counter dec", ex) ;
         }
     }
-
-    public static void parse(HttpAction action, StreamRDF dest, InputStream 
input, Lang lang, String base) {
-        try {
-            if ( ! RDFParserRegistry.isRegistered(lang) )
-                ServletOps.errorBadRequest("No parser for language 
'"+lang.getName()+"'") ;
-            ErrorHandler errorHandler = 
ErrorHandlerFactory.errorHandlerStd(action.log);
-            RDFParser.create()
-                .errorHandler(errorHandler)
-                .source(input)
-                .lang(lang)
-                .base(base)
-                .parse(dest);
-        } catch (RuntimeIOException ex) {
-            if ( ex.getCause() instanceof CharacterCodingException )
-                throw new RiotException("Character Coding Error: 
"+ex.getMessage());
-            throw ex;
-        }
-        catch (RiotException ex) { ServletOps.errorBadRequest("Parse error: 
"+ex.getMessage()) ; }
-    }
 }

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/Dispatch.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/Dispatch.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/Dispatch.java
new file mode 100644
index 0000000..d0a4cf4
--- /dev/null
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/Dispatch.java
@@ -0,0 +1,62 @@
+/*
+ * 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.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.jena.fuseki.server.DataService;
+import org.apache.jena.fuseki.server.OperationName;
+import org.apache.jena.riot.WebContent;
+
+/** The global mapping of content-type to OperationName. */
+
+public class Dispatch {
+    /** Map ContentType (lowercase, no charset) to the {@code OperationName} 
for handling it. */  
+    public static Map<String, OperationName> contentTypeToOpName = new 
ConcurrentHashMap<>();
+    static {
+        contentTypeToOpName.put(WebContent.contentTypeSPARQLQuery, 
OperationName.Query);
+        contentTypeToOpName.put(WebContent.contentTypeSPARQLUpdate, 
OperationName.Update);
+    }
+    
+    /** Map {@link OperationName} to servlet handler.
+     * {@code OperartionNames} are the internal symbol identifying an 
operation,
+     * not the name used in the configuration file, which is mapped by {@link 
DataService#getOperation}. 
+     *   
+     *  */  
+    public static Map<OperationName, ActionSPARQL> OpNameToHandler = new 
ConcurrentHashMap<>();
+    
+    public static final ActionSPARQL queryServlet    = new 
SPARQL_QueryDataset() ;
+    public static final ActionSPARQL updateServlet   = new SPARQL_Update() ;
+    public static final ActionSPARQL uploadServlet   = new SPARQL_Upload() ;
+    public static final ActionSPARQL gspServlet_R    = new SPARQL_GSP_R() ;
+    public static final ActionSPARQL gspServlet_RW   = new SPARQL_GSP_RW() ;
+    public static final ActionSPARQL restQuads_R     = new REST_Quads_R() ;
+    public static final ActionSPARQL restQuads_RW    = new REST_Quads_RW() ;
+
+    static {
+        OpNameToHandler.put(OperationName.Query,    queryServlet);
+        OpNameToHandler.put(OperationName.Update,   updateServlet);
+        OpNameToHandler.put(OperationName.Upload,   uploadServlet);
+        OpNameToHandler.put(OperationName.GSP_R,    gspServlet_R);
+        OpNameToHandler.put(OperationName.GSP_RW,   gspServlet_RW);
+        OpNameToHandler.put(OperationName.Quads_R,  restQuads_R);
+        OpNameToHandler.put(OperationName.Quads_RW, restQuads_RW);
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/FusekiFilter.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/FusekiFilter.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/FusekiFilter.java
index 23eec72..44ab013 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/FusekiFilter.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/FusekiFilter.java
@@ -35,7 +35,7 @@ import org.slf4j.Logger ;
  */
 public class FusekiFilter implements Filter {
     private static Logger log = Fuseki.serverLog ;
-    private static SPARQL_UberServlet überServlet = new 
SPARQL_UberServlet.AccessByConfig() ;
+    private static ServiceRouterServlet routerServlet = new 
ServiceRouterServlet.AccessByConfig() ;
     
     @Override
     public void init(FilterConfig filterConfig) {
@@ -70,7 +70,7 @@ public class FusekiFilter implements Filter {
                 if ( registry.isRegistered(datasetUri) ) {
                     if ( LogFilter )
                         log.info("Filter: dispatch") ;
-                    überServlet.doCommon(req, resp) ;
+                    routerServlet.doCommon(req, resp) ;
                     return ;
                 }
 
@@ -85,7 +85,7 @@ public class FusekiFilter implements Filter {
                         if ( datasetUri.startsWith(dsName) ) {
                             if ( LogFilter )
                                 log.info("Filter: dispatch (GSP direct name)") 
;
-                            überServlet.doCommon(req, resp) ;
+                            routerServlet.doCommon(req, resp) ;
                             return ;
                         }
                     }

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java
index 3df0908..6dfb1ee 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java
@@ -82,8 +82,8 @@ public class HttpAction
     // Outcome.
     public int statusCode = -1 ;
     public String message = null ;
-    public int contentLength = -1 ;
-    public String contentType = null ;
+    public int responseContentLength = -1 ;
+    public String responseContentType = null ;
     
     // Cleared to archive:
     public Map <String, String> headers = new HashMap<>() ;
@@ -143,6 +143,16 @@ public class HttpAction
         setDataset(dService.getDataset()) ;
     }
     
+    public void setControlRequest(DataAccessPoint dataAccessPoint, String 
datasetUri) {
+        this.dataAccessPoint = dataAccessPoint ;
+        this.dataService = null ;
+        if ( dataAccessPoint != null )
+            this.dataService = dataAccessPoint.getDataService() ;
+        this.datasetName = datasetUri ;
+        if ( dataService != null )
+            setDataset(dataAccessPoint.getDataService().getDataset()) ; 
+    }
+
     /** Minimum initialization using just a dataset.
      * <p>
      * the HTTP Action will change its transactional state and
@@ -180,16 +190,6 @@ public class HttpAction
         return dsg ;
     }
 
-    public void setControlRequest(DataAccessPoint dataAccessPoint, String 
datasetUri) {
-        this.dataAccessPoint = dataAccessPoint ;
-        this.dataService = null ;
-        if ( dataAccessPoint != null )
-            this.dataService = dataAccessPoint.getDataService() ;
-        this.datasetName = datasetUri ;
-        if ( dataService != null )
-            setDataset(dataAccessPoint.getDataService().getDataset()) ; 
-    }
-    
     /**
      * Return the "Transactional" for this HttpAction.
      */

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpServletResponseTracker.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpServletResponseTracker.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpServletResponseTracker.java
index ac7ce09..47f2b36 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpServletResponseTracker.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpServletResponseTracker.java
@@ -83,13 +83,13 @@ public class HttpServletResponseTracker extends 
HttpServletResponseWrapper
 
     @Override
     public void setContentLength(int len) {
-        action.contentLength = len;
+        action.responseContentLength = len;
         super.setContentLength(len);
     }
 
     @Override
     public void setContentType(String type) {
-        action.contentType = type;
+        action.responseContentType = type;
         super.setContentType(type);
     }
       

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
index 959d114..b0283c2 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
@@ -73,9 +73,7 @@ public abstract class SPARQL_Query extends SPARQL_Protocol
     }
 
     // Choose REST verbs to support.
-
-    // doMethod : Not used with UberServlet dispatch.
-
+    
     @Override
     protected void doPost(HttpServletRequest request, HttpServletResponse 
response) {
         doCommon(request, response) ;

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_UberServlet.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_UberServlet.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_UberServlet.java
deleted file mode 100644
index e9e0587..0000000
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_UberServlet.java
+++ /dev/null
@@ -1,412 +0,0 @@
-/**
- * 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.riot.WebContent.contentTypeSPARQLQuery ;
-import static org.apache.jena.riot.WebContent.contentTypeSPARQLUpdate ;
-
-import java.io.IOException ;
-import java.util.List ;
-
-import javax.servlet.ServletException ;
-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.FusekiException ;
-import org.apache.jena.fuseki.conneg.ConNeg ;
-import org.apache.jena.fuseki.server.* ;
-import org.apache.jena.riot.web.HttpNames ;
-
-/** This servlet can be attached to a dataset location
- *  and acts as a router for all SPARQL operations
- *  (query, update, graph store, both direct and
- *  indirect naming, quads operations on a dataset and
- *  ?query and ?update directly on a dataset.)
- */
-public abstract class SPARQL_UberServlet extends ActionSPARQL
-{
-    private static final long serialVersionUID = -491895535163680509L;
-
-    protected abstract boolean allowQuery(HttpAction action) ;
-    protected abstract boolean allowUpdate(HttpAction action) ;
-    protected abstract boolean allowREST_R(HttpAction action) ;
-    protected abstract boolean allowREST_W(HttpAction action) ;
-    protected abstract boolean allowQuadsR(HttpAction action) ;
-    protected abstract boolean allowQuadsW(HttpAction action) ;
-
-    public static class ReadOnly extends SPARQL_UberServlet
-    {
-        private static final long serialVersionUID = -3486969173228213955L;
-
-        public ReadOnly()    { super() ; }
-        @Override protected boolean allowQuery(HttpAction action)    { return 
true ; }
-        @Override protected boolean allowUpdate(HttpAction action)   { return 
false ; }
-        @Override protected boolean allowREST_R(HttpAction action)   { return 
true ; }
-        @Override protected boolean allowREST_W(HttpAction action)   { return 
false ; }
-        @Override protected boolean allowQuadsR(HttpAction action)   { return 
true ; }
-        @Override protected boolean allowQuadsW(HttpAction action)   { return 
false ; }
-    }
-
-    public static class ReadWrite extends SPARQL_UberServlet
-    {
-        private static final long serialVersionUID = 1383389566691599382L;
-
-        public ReadWrite()    { super() ; }
-        @Override protected boolean allowQuery(HttpAction action)    { return 
true ; }
-        @Override protected boolean allowUpdate(HttpAction action)   { return 
true ; }
-        @Override protected boolean allowREST_R(HttpAction action)   { return 
true ; }
-        @Override protected boolean allowREST_W(HttpAction action)   { return 
true ; }
-        @Override protected boolean allowQuadsR(HttpAction action)   { return 
true ; }
-        @Override protected boolean allowQuadsW(HttpAction action)   { return 
true ; }
-    }
-
-    public static class AccessByConfig extends SPARQL_UberServlet
-    {
-        private static final long serialVersionUID = 5078964040391977778L;
-
-        public AccessByConfig()    { super() ; }
-        @Override protected boolean allowQuery(HttpAction action)    { return 
isEnabled(action, OperationName.Query) ; }
-        @Override protected boolean allowUpdate(HttpAction action)   { return 
isEnabled(action, OperationName.Update) ; }
-        @Override protected boolean allowREST_R(HttpAction action)   { return 
isEnabled(action, OperationName.GSP_R) || isEnabled(action, 
OperationName.GSP_RW) ; }
-        @Override protected boolean allowREST_W(HttpAction action)   { return 
isEnabled(action, OperationName.GSP_RW) ; }
-        @Override protected boolean allowQuadsR(HttpAction action)   { return 
isEnabled(action, OperationName.Quads_R) || isEnabled(action, 
OperationName.Quads_RW) ; }
-        @Override protected boolean allowQuadsW(HttpAction action)   { return 
isEnabled(action, OperationName.Quads_RW) ; }
-
-        // Test whether there is a configuration that allows this action as 
the operation given.
-        // Ignores the operation in the action (set due to parsing - it might 
be "quads"
-        // which is the generic operation when just the dataset is specificed.
-        private boolean isEnabled(HttpAction action, OperationName opName) {
-            // Disregard the operation name of the action
-            DataService dSrv = action.getDataService() ;
-            if ( dSrv == null )
-                return false;
-            return ! dSrv.getOperation(opName).isEmpty() ;
-        }
-    }
-
-    /* This can be used for a single servlet for everything (über-servlet)
-     *
-     * It can check for a request that looks like a service request and passes 
it on.
-     * This takes precedence over direct naming.
-     */
-
-    private final ActionSPARQL queryServlet    = new SPARQL_QueryDataset() ;
-    private final ActionSPARQL updateServlet   = new SPARQL_Update() ;
-    private final ActionSPARQL uploadServlet   = new SPARQL_Upload() ;
-    private final ActionSPARQL gspServlet_R    = new SPARQL_GSP_R() ;
-    private final ActionSPARQL gspServlet_RW   = new SPARQL_GSP_RW() ;
-    private final ActionSPARQL restQuads_R     = new REST_Quads_R() ;
-    private final ActionSPARQL restQuads_RW    = new REST_Quads_RW() ;
-
-    public SPARQL_UberServlet() { super(); }
-
-    private String getEPName(String dsname, List<String> endpoints) {
-        if (endpoints == null || endpoints.size() == 0)
-            return null ;
-        String x = endpoints.get(0) ;
-        if ( ! dsname.endsWith("/") )
-            x = dsname+"/"+x ;
-        else
-            x = dsname+x ;
-        return x ;
-    }
-
-    // These calls should not happen because we hook in at executeAction
-    @Override protected void validate(HttpAction action) { throw new 
FusekiException("Call to SPARQL_UberServlet.validate") ; }
-    @Override protected void perform(HttpAction action)  { throw new 
FusekiException("Call to SPARQL_UberServlet.perform") ; }
-
-    /** Map request to uri in the registry.
-     *  null means no mapping done
-     */
-    @Override
-    protected String mapRequestToDataset(HttpAction action) {
-        String uri = ActionLib.removeContextPath(action) ;
-        return ActionLib.mapRequestToDatasetLongest$(uri, 
action.getDataAccessPointRegistry()) ;
-    }
-
-    /** Intercept the processing cycle at the point where the action has been 
set up,
-     *  the dataset target decided but no validation or execution has been 
done,
-     *  nor any stats have been done.
-     */
-    @Override
-    protected void executeAction(HttpAction action) {
-        
-        // DEBUG: DataAccessPointRegistry.print("UberServlet ");
-        
-        long id = action.id ;
-        HttpServletRequest request = action.request ;
-        HttpServletResponse response = action.response ;
-        String actionURI = action.getActionURI() ;            // No context 
path
-        String method = request.getMethod() ;
-
-        DataAccessPoint desc = action.getDataAccessPoint() ;
-        DataService dSrv = action.getDataService() ;
-
-//        if ( ! dSrv.isActive() )
-//            ServletOps.error(HttpSC.SERVICE_UNAVAILABLE_503, "Dataset not 
currently active");
-
-        // Part after the DataAccessPoint (dataset) name.
-        String trailing = findTrailing(actionURI, desc.getName()) ;
-        String qs = request.getQueryString() ;
-
-        boolean hasParams = request.getParameterMap().size() > 0 ;
-
-        // Is it a query or update because of a ?query= , ?request= parameter? 
-        // Test for parameters - includes HTML forms.
-        boolean isQuery           = request.getParameter(HttpNames.paramQuery) 
!= null ;
-        // Include old name "request="
-        boolean isUpdate          = 
request.getParameter(HttpNames.paramUpdate) != null || 
request.getParameter(HttpNames.paramRequest) != null ;
-
-        boolean hasParamGraph           = 
request.getParameter(HttpNames.paramGraph) != null ;
-        boolean hasParamGraphDefault    = 
request.getParameter(HttpNames.paramGraphDefault) != null ;
-
-        boolean hasTrailing = ( trailing.length() != 0 ) ;
-        
-        String ct = request.getContentType() ;
-        String charset = request.getCharacterEncoding() ;
-
-        MediaType mt = null ;
-        if ( ct != null ) {
-            // Parse it.
-            mt = MediaType.create(ct, charset) ;
-            // Another way to send queries and updates is with the 
content-type. 
-            if ( contentTypeSPARQLQuery.equalsIgnoreCase(ct) )
-                isQuery = true ;
-            else if ( contentTypeSPARQLUpdate.equalsIgnoreCase(ct) )
-                isUpdate = true ;
-        }
-            
-        if (action.log.isInfoEnabled() ) {
-            //String cxt = action.getContextPath() ;
-            action.log.info(format("[%d] %s %s :: '%s' :: %s ? %s", id, 
method, desc.getName(), trailing, (mt==null?"<none>":mt), (qs==null?"":qs))) ;
-        }
-        
-        if ( !hasTrailing ) {
-            // Nothing after the DataAccessPoint i.e. Dataset by name.
-            // Action on the dataset itself. This can be:
-            //
-            //   http://localhost:3030/ds?query=
-            //   http://localhost:3030/ds and a content type of 
"applicatiopn/sparql-query"
-            //
-            //   http://localhost:3030/ds?update=
-            //   http://localhost:3030/ds and a content type of 
"applicatiopn/sparql-update"
-            //
-            //   http://localhost:3030/ds?default ?graph=  GSP
-            //
-            //   http://localhost:3030/ds   REST quads action on the dataset 
itself.
-            if ( isQuery ) {
-                if ( !allowQuery(action) )
-                    ServletOps.errorMethodNotAllowed("SPARQL query : "+method) 
;
-                executeRequest(action, queryServlet) ;
-                return ;
-            }
-
-            if ( isUpdate ) {
-                // SPARQL Update
-                if ( !allowUpdate(action) )
-                    ServletOps.errorMethodNotAllowed("SPARQL update : 
"+method) ;
-                // This will deal with using GET.
-                executeRequest(action, updateServlet) ;
-                return ;
-            }
-
-            // ?graph=, ?default
-            if ( hasParamGraph || hasParamGraphDefault ) {
-                doGraphStoreProtocol(action) ;
-                return ;
-            }
-
-            if ( hasParams ) {
-                // Unrecognized ?key=value
-                ServletOps.errorBadRequest("Malformed request") ;
-            }
-            
-            // REST dataset.
-            boolean isGET = method.equals(HttpNames.METHOD_GET) ;
-            boolean isHEAD = method.equals(HttpNames.METHOD_HEAD) ;
-
-            // Check enabled.
-            if ( isGET || isHEAD ) {
-                if ( allowQuadsR(action) )
-                    restQuads_R.executeLifecycle(action) ;
-                else
-                    ServletOps.errorMethodNotAllowed(method) ;
-                return ;
-            }
-            
-            if ( allowQuadsW(action) )
-                restQuads_RW.executeLifecycle(action) ;
-            else
-                ServletOps.errorMethodNotAllowed("Read-only dataset : 
"+method) ;
-            return ;
-        }
-
-        // Has trailing path name => service or direct naming GSP.
-        
-        final boolean checkForPossibleService = true ;
-        if ( checkForPossibleService && action.getEndpoint() != null ) {
-            // There is a trailing part.
-            // Check it's not the same name as a registered service.
-            // If so, dispatch to that service.
-            if ( serviceDispatch(action, OperationName.Query, queryServlet) ) 
return ;
-            if ( serviceDispatch(action, OperationName.Update, updateServlet) 
) return ;
-            if ( serviceDispatch(action, OperationName.Upload, uploadServlet) 
) return ;
-            if ( hasParams ) {
-                if ( serviceDispatch(action, OperationName.GSP_R, 
gspServlet_R) ) return ;
-                if ( serviceDispatch(action, OperationName.GSP_RW, 
gspServlet_RW) ) return ;
-            } else {
-                // No parameters - do as a quads operation on the dataset.
-                if ( serviceDispatch(action, OperationName.GSP_R, restQuads_R) 
) return ;
-                if ( serviceDispatch(action, OperationName.GSP_RW, 
restQuads_RW) ) return ;
-            }
-            if ( serviceDispatch(action, OperationName.Quads_RW, restQuads_RW) 
) return ;
-            if ( serviceDispatch(action, OperationName.Quads_R, restQuads_R) ) 
return ;
-        }
-        // There is a trailing part - params are illegal by this point.
-        if ( hasParams )
-            // ?? Revisit to include query-on-one-graph
-            //errorBadRequest("Can't invoke a query-string service on a direct 
named graph") ;
-            ServletOps.errorNotFound("Not found: 
dataset='"+printName(desc.getName())+
-                                     "' service='"+printName(trailing)+
-                                     "' query string=?"+qs);
-
-        // There is a trailing part - not a service, no params ==> GSP direct 
naming.
-        if ( ! Fuseki.GSP_DIRECT_NAMING )
-            ServletOps.errorNotFound("Not found: 
dataset='"+printName(desc.getName())+"' service='"+printName(trailing)+"'");
-
-        doGraphStoreProtocol(action);
-    }
-
-    /** See if the operation is enabled for this setup.
-     * Return true if dispatched
-     */
-    private boolean serviceDispatch(HttpAction action, OperationName opName, 
ActionSPARQL servlet) {
-        Endpoint operation = action.getEndpoint() ;
-        if ( operation == null )
-            return false ;
-        if ( ! operation.isType(opName) )
-            return false ;
-        // Handle OPTIONS specially.
-//        if ( 
action.getRequest().getMethod().equals(HttpNames.METHOD_OPTIONS) ) {
-//            // See also ServletBase.CORS_ENABLED
-//            //action.log.info(format("[%d] %s", action.id, 
action.getMethod())) ;
-//            setCommonHeadersForOptions(action.getResponse()) ;
-//            ServletOps.success(action);
-//            return true ;
-//        }
-        executeRequest(action, servlet) ;
-        return true ;
-    }
-    private String printName(String x) {
-        if ( x.startsWith("/") )
-            return x.substring(1) ;
-        return x ;
-    }
-
-    private void doGraphStoreProtocol(HttpAction action) {
-        // The GSP servlets handle direct and indirect naming.
-        Endpoint operation = action.getEndpoint() ;
-        String method = action.request.getMethod() ;
-
-        // Try to route to read service.
-
-        if ( HttpNames.METHOD_GET.equalsIgnoreCase(method) ||
-            HttpNames.METHOD_HEAD.equalsIgnoreCase(method) )
-        {
-            // Graphs Store Protocol, indirect naming, read operations
-            // Try to send to the R service, else drop through to RW service 
dispatch.
-            if ( ! allowREST_R(action))
-                ServletOps.errorForbidden("Forbidden: SPARQL Graph Store 
Protocol : Read operation : "+method) ;
-            executeRequest(action, gspServlet_R) ;
-            return ;
-        }
-
-        // Graphs Store Protocol, indirect naming, write (or read, though 
actually handled above)
-        // operations on the RW service.
-        if ( ! allowREST_W(action))
-            ServletOps.errorForbidden("Forbidden: SPARQL Graph Store Protocol 
: "+method) ;
-        executeRequest(action, gspServlet_RW) ;
-        return ;
-    }
-
-    private void executeRequest(HttpAction action, ActionSPARQL servlet) {
-        if ( true ) {
-            // Execute an ActionSPARQL.
-            // Bypasses HttpServlet.service to doMethod dispatch.
-            servlet.executeLifecycle(action) ;
-            return ;
-        }
-        if ( false )  {
-            // Execute by calling the whole servlet mechanism.
-            // This causes HttpServlet.service to call the appropriate 
doMethod.
-            // but the action, and the id, are not passed on and a ne one is 
created.
-            try { servlet.service(action.request, action.response) ; }
-            catch (ServletException | IOException e) {
-                ServletOps.errorOccurred(e);
-            }
-        }
-    }
-
-    protected static MediaType contentNegotationQuads(HttpAction action) {
-        MediaType mt = ConNeg.chooseContentType(action.request, 
DEF.quadsOffer, DEF.acceptNQuads) ;
-        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 ;
-    }
-
-    /** Find part after the dataset name: service name or the graph (direct 
naming) */
-    protected String findTrailing(String uri, String dsname) {
-        if ( dsname.length() >= uri.length() )
-            return "" ;
-        return uri.substring(dsname.length()+1) ;   // Skip the separating "/"
-    }
-
-    // Route everything to "doCommon"
-    @Override
-    protected void doHead(HttpServletRequest request, HttpServletResponse 
response)
-    { doCommon(request, response) ; }
-
-    @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse 
response)
-    { doCommon(request, response) ; }
-
-    @Override
-    protected void doPost(HttpServletRequest request, HttpServletResponse 
response)
-    { doCommon(request, response) ; }
-
-    @Override
-    protected void doOptions(HttpServletRequest request, HttpServletResponse 
response)
-    { doCommon(request, response) ; }
-
-    @Override
-    protected void doPut(HttpServletRequest request, HttpServletResponse 
response)
-    { doCommon(request, response) ; }
-
-    @Override
-    protected void doDelete(HttpServletRequest request, HttpServletResponse 
response)
-    { doCommon(request, response) ; }
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_UberServlet_Original.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_UberServlet_Original.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_UberServlet_Original.java
new file mode 100644
index 0000000..a12928f
--- /dev/null
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_UberServlet_Original.java
@@ -0,0 +1,416 @@
+/**
+ * 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.riot.WebContent.contentTypeSPARQLQuery ;
+import static org.apache.jena.riot.WebContent.contentTypeSPARQLUpdate ;
+
+import java.io.IOException ;
+import java.util.List ;
+
+import javax.servlet.ServletException ;
+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.FusekiException ;
+import org.apache.jena.fuseki.conneg.ConNeg ;
+import org.apache.jena.fuseki.server.* ;
+import org.apache.jena.riot.web.HttpNames ;
+
+// NOT USED
+//   Retained during migration to the new router servlet.
+//   Delete when that is stable.
+
+/** This servlet can be attached to a dataset location
+ *  and acts as a router for all SPARQL operations
+ *  (query, update, graph store, both direct and
+ *  indirect naming, quads operations on a dataset and
+ *  ?query and ?update directly on a dataset.)
+ */
+public abstract class SPARQL_UberServlet_Original extends ActionSPARQL
+{
+    private static final long serialVersionUID = -491895535163680509L;
+
+    protected abstract boolean allowQuery(HttpAction action) ;
+    protected abstract boolean allowUpdate(HttpAction action) ;
+    protected abstract boolean allowREST_R(HttpAction action) ;
+    protected abstract boolean allowREST_W(HttpAction action) ;
+    protected abstract boolean allowQuadsR(HttpAction action) ;
+    protected abstract boolean allowQuadsW(HttpAction action) ;
+
+    public static class ReadOnly extends SPARQL_UberServlet_Original
+    {
+        private static final long serialVersionUID = -3486969173228213955L;
+
+        public ReadOnly()    { super() ; }
+        @Override protected boolean allowQuery(HttpAction action)    { return 
true ; }
+        @Override protected boolean allowUpdate(HttpAction action)   { return 
false ; }
+        @Override protected boolean allowREST_R(HttpAction action)   { return 
true ; }
+        @Override protected boolean allowREST_W(HttpAction action)   { return 
false ; }
+        @Override protected boolean allowQuadsR(HttpAction action)   { return 
true ; }
+        @Override protected boolean allowQuadsW(HttpAction action)   { return 
false ; }
+    }
+
+    public static class ReadWrite extends SPARQL_UberServlet_Original
+    {
+        private static final long serialVersionUID = 1383389566691599382L;
+
+        public ReadWrite()    { super() ; }
+        @Override protected boolean allowQuery(HttpAction action)    { return 
true ; }
+        @Override protected boolean allowUpdate(HttpAction action)   { return 
true ; }
+        @Override protected boolean allowREST_R(HttpAction action)   { return 
true ; }
+        @Override protected boolean allowREST_W(HttpAction action)   { return 
true ; }
+        @Override protected boolean allowQuadsR(HttpAction action)   { return 
true ; }
+        @Override protected boolean allowQuadsW(HttpAction action)   { return 
true ; }
+    }
+
+    public static class AccessByConfig extends SPARQL_UberServlet_Original
+    {
+        private static final long serialVersionUID = 5078964040391977778L;
+
+        public AccessByConfig()    { super() ; }
+        @Override protected boolean allowQuery(HttpAction action)    { return 
isEnabled(action, OperationName.Query) ; }
+        @Override protected boolean allowUpdate(HttpAction action)   { return 
isEnabled(action, OperationName.Update) ; }
+        @Override protected boolean allowREST_R(HttpAction action)   { return 
isEnabled(action, OperationName.GSP_R) || isEnabled(action, 
OperationName.GSP_RW) ; }
+        @Override protected boolean allowREST_W(HttpAction action)   { return 
isEnabled(action, OperationName.GSP_RW) ; }
+        @Override protected boolean allowQuadsR(HttpAction action)   { return 
isEnabled(action, OperationName.Quads_R) || isEnabled(action, 
OperationName.Quads_RW) ; }
+        @Override protected boolean allowQuadsW(HttpAction action)   { return 
isEnabled(action, OperationName.Quads_RW) ; }
+
+        // Test whether there is a configuration that allows this action as 
the operation given.
+        // Ignores the operation in the action (set due to parsing - it might 
be "quads"
+        // which is the generic operation when just the dataset is specificed.
+        private boolean isEnabled(HttpAction action, OperationName opName) {
+            // Disregard the operation name of the action
+            DataService dSrv = action.getDataService() ;
+            if ( dSrv == null )
+                return false;
+            return ! dSrv.getOperation(opName).isEmpty() ;
+        }
+    }
+
+    /* This can be used for a single servlet for everything (über-servlet)
+     *
+     * It can check for a request that looks like a service request and passes 
it on.
+     * This takes precedence over direct naming.
+     */
+
+    private final ActionSPARQL queryServlet    = new SPARQL_QueryDataset() ;
+    private final ActionSPARQL updateServlet   = new SPARQL_Update() ;
+    private final ActionSPARQL uploadServlet   = new SPARQL_Upload() ;
+    private final ActionSPARQL gspServlet_R    = new SPARQL_GSP_R() ;
+    private final ActionSPARQL gspServlet_RW   = new SPARQL_GSP_RW() ;
+    private final ActionSPARQL restQuads_R     = new REST_Quads_R() ;
+    private final ActionSPARQL restQuads_RW    = new REST_Quads_RW() ;
+
+    public SPARQL_UberServlet_Original() { super(); }
+
+    private String getEPName(String dsname, List<String> endpoints) {
+        if (endpoints == null || endpoints.size() == 0)
+            return null ;
+        String x = endpoints.get(0) ;
+        if ( ! dsname.endsWith("/") )
+            x = dsname+"/"+x ;
+        else
+            x = dsname+x ;
+        return x ;
+    }
+
+    // These calls should not happen because we hook in at executeAction
+    @Override protected void validate(HttpAction action) { throw new 
FusekiException("Call to SPARQL_UberServlet.validate") ; }
+    @Override protected void perform(HttpAction action)  { throw new 
FusekiException("Call to SPARQL_UberServlet.perform") ; }
+
+    /** Map request to uri in the registry.
+     *  null means no mapping done
+     */
+    @Override
+    protected String mapRequestToDataset(HttpAction action) {
+        String uri = ActionLib.removeContextPath(action) ;
+        return ActionLib.mapRequestToDatasetLongest$(uri, 
action.getDataAccessPointRegistry()) ;
+    }
+
+    /** Intercept the processing cycle at the point where the action has been 
set up,
+     *  the dataset target decided but no validation or execution has been 
done,
+     *  nor any stats have been done.
+     */
+    @Override
+    protected void executeAction(HttpAction action) {
+        
+        // DEBUG: DataAccessPointRegistry.print("UberServlet ");
+        
+        long id = action.id ;
+        HttpServletRequest request = action.request ;
+        HttpServletResponse response = action.response ;
+        String actionURI = action.getActionURI() ;            // No context 
path
+        String method = request.getMethod() ;
+
+        DataAccessPoint desc = action.getDataAccessPoint() ;
+        DataService dSrv = action.getDataService() ;
+
+//        if ( ! dSrv.isActive() )
+//            ServletOps.error(HttpSC.SERVICE_UNAVAILABLE_503, "Dataset not 
currently active");
+
+        // Part after the DataAccessPoint (dataset) name.
+        String trailing = findTrailing(actionURI, desc.getName()) ;
+        String qs = request.getQueryString() ;
+
+        boolean hasParams = request.getParameterMap().size() > 0 ;
+
+        // Is it a query or update because of a ?query= , ?request= parameter? 
+        // Test for parameters - includes HTML forms.
+        boolean isQuery           = request.getParameter(HttpNames.paramQuery) 
!= null ;
+        // Include old name "request="
+        boolean isUpdate          = 
request.getParameter(HttpNames.paramUpdate) != null || 
request.getParameter(HttpNames.paramRequest) != null ;
+
+        boolean hasParamGraph           = 
request.getParameter(HttpNames.paramGraph) != null ;
+        boolean hasParamGraphDefault    = 
request.getParameter(HttpNames.paramGraphDefault) != null ;
+
+        boolean hasTrailing = ( trailing.length() != 0 ) ;
+        
+        String ct = request.getContentType() ;
+        String charset = request.getCharacterEncoding() ;
+
+        MediaType mt = null ;
+        if ( ct != null ) {
+            // Parse it.
+            mt = MediaType.create(ct, charset) ;
+            // Another way to send queries and updates is with the 
content-type. 
+            if ( contentTypeSPARQLQuery.equalsIgnoreCase(ct) )
+                isQuery = true ;
+            else if ( contentTypeSPARQLUpdate.equalsIgnoreCase(ct) )
+                isUpdate = true ;
+        }
+            
+        if (action.log.isInfoEnabled() ) {
+            //String cxt = action.getContextPath() ;
+            action.log.info(format("[%d] %s %s :: '%s' :: %s ? %s", id, 
method, desc.getName(), trailing, (mt==null?"<none>":mt), (qs==null?"":qs))) ;
+        }
+        
+        if ( !hasTrailing ) {
+            // Nothing after the DataAccessPoint i.e. Dataset by name.
+            // Action on the dataset itself. This can be:
+            //
+            //   http://localhost:3030/ds?query=
+            //   http://localhost:3030/ds and a content type of 
"applicatiopn/sparql-query"
+            //
+            //   http://localhost:3030/ds?update=
+            //   http://localhost:3030/ds and a content type of 
"applicatiopn/sparql-update"
+            //
+            //   http://localhost:3030/ds?default ?graph=  GSP
+            //
+            //   http://localhost:3030/ds   REST quads action on the dataset 
itself.
+            if ( isQuery ) {
+                if ( !allowQuery(action) )
+                    ServletOps.errorMethodNotAllowed("SPARQL query : "+method) 
;
+                executeRequest(action, queryServlet) ;
+                return ;
+            }
+
+            if ( isUpdate ) {
+                // SPARQL Update
+                if ( !allowUpdate(action) )
+                    ServletOps.errorMethodNotAllowed("SPARQL update : 
"+method) ;
+                // This will deal with using GET.
+                executeRequest(action, updateServlet) ;
+                return ;
+            }
+
+            // ?graph=, ?default
+            if ( hasParamGraph || hasParamGraphDefault ) {
+                doGraphStoreProtocol(action) ;
+                return ;
+            }
+
+            if ( hasParams ) {
+                // Unrecognized ?key=value
+                ServletOps.errorBadRequest("Malformed request") ;
+            }
+            
+            // REST dataset.
+            boolean isGET = method.equals(HttpNames.METHOD_GET) ;
+            boolean isHEAD = method.equals(HttpNames.METHOD_HEAD) ;
+
+            // Check enabled.
+            if ( isGET || isHEAD ) {
+                if ( allowQuadsR(action) )
+                    restQuads_R.executeLifecycle(action) ;
+                else
+                    ServletOps.errorMethodNotAllowed(method) ;
+                return ;
+            }
+            
+            if ( allowQuadsW(action) )
+                restQuads_RW.executeLifecycle(action) ;
+            else
+                ServletOps.errorMethodNotAllowed("Read-only dataset : 
"+method) ;
+            return ;
+        }
+
+        // Has trailing path name => service or direct naming GSP.
+        
+        final boolean checkForPossibleService = true ;
+        if ( checkForPossibleService && action.getEndpoint() != null ) {
+            // There is a trailing part.
+            // Check it's not the same name as a registered service.
+            // If so, dispatch to that service.
+            if ( serviceDispatch(action, OperationName.Query, queryServlet) ) 
return ;
+            if ( serviceDispatch(action, OperationName.Update, updateServlet) 
) return ;
+            if ( serviceDispatch(action, OperationName.Upload, uploadServlet) 
) return ;
+            if ( hasParams ) {
+                if ( serviceDispatch(action, OperationName.GSP_R, 
gspServlet_R) ) return ;
+                if ( serviceDispatch(action, OperationName.GSP_RW, 
gspServlet_RW) ) return ;
+            } else {
+                // No parameters - do as a quads operation on the dataset.
+                if ( serviceDispatch(action, OperationName.GSP_R, restQuads_R) 
) return ;
+                if ( serviceDispatch(action, OperationName.GSP_RW, 
restQuads_RW) ) return ;
+            }
+            if ( serviceDispatch(action, OperationName.Quads_RW, restQuads_RW) 
) return ;
+            if ( serviceDispatch(action, OperationName.Quads_R, restQuads_R) ) 
return ;
+        }
+        // There is a trailing part - params are illegal by this point.
+        if ( hasParams )
+            // ?? Revisit to include query-on-one-graph
+            //errorBadRequest("Can't invoke a query-string service on a direct 
named graph") ;
+            ServletOps.errorNotFound("Not found: 
dataset='"+printName(desc.getName())+
+                                     "' service='"+printName(trailing)+
+                                     "' query string=?"+qs);
+
+        // There is a trailing part - not a service, no params ==> GSP direct 
naming.
+        if ( ! Fuseki.GSP_DIRECT_NAMING )
+            ServletOps.errorNotFound("Not found: 
dataset='"+printName(desc.getName())+"' service='"+printName(trailing)+"'");
+
+        doGraphStoreProtocol(action);
+    }
+
+    /** See if the operation is enabled for this setup.
+     * Return true if dispatched
+     */
+    private boolean serviceDispatch(HttpAction action, OperationName opName, 
ActionSPARQL servlet) {
+        Endpoint operation = action.getEndpoint() ;
+        if ( operation == null )
+            return false ;
+        if ( ! operation.isType(opName) )
+            return false ;
+        // Handle OPTIONS specially.
+//        if ( 
action.getRequest().getMethod().equals(HttpNames.METHOD_OPTIONS) ) {
+//            // See also ServletBase.CORS_ENABLED
+//            //action.log.info(format("[%d] %s", action.id, 
action.getMethod())) ;
+//            setCommonHeadersForOptions(action.getResponse()) ;
+//            ServletOps.success(action);
+//            return true ;
+//        }
+        executeRequest(action, servlet) ;
+        return true ;
+    }
+    private String printName(String x) {
+        if ( x.startsWith("/") )
+            return x.substring(1) ;
+        return x ;
+    }
+
+    private void doGraphStoreProtocol(HttpAction action) {
+        // The GSP servlets handle direct and indirect naming.
+        Endpoint operation = action.getEndpoint() ;
+        String method = action.request.getMethod() ;
+
+        // Try to route to read service.
+
+        if ( HttpNames.METHOD_GET.equalsIgnoreCase(method) ||
+            HttpNames.METHOD_HEAD.equalsIgnoreCase(method) )
+        {
+            // Graphs Store Protocol, indirect naming, read operations
+            // Try to send to the R service, else drop through to RW service 
dispatch.
+            if ( ! allowREST_R(action))
+                ServletOps.errorForbidden("Forbidden: SPARQL Graph Store 
Protocol : Read operation : "+method) ;
+            executeRequest(action, gspServlet_R) ;
+            return ;
+        }
+
+        // Graphs Store Protocol, indirect naming, write (or read, though 
actually handled above)
+        // operations on the RW service.
+        if ( ! allowREST_W(action))
+            ServletOps.errorForbidden("Forbidden: SPARQL Graph Store Protocol 
: "+method) ;
+        executeRequest(action, gspServlet_RW) ;
+        return ;
+    }
+
+    private void executeRequest(HttpAction action, ActionSPARQL servlet) {
+        if ( true ) {
+            // Execute an ActionSPARQL.
+            // Bypasses HttpServlet.service to doMethod dispatch.
+            servlet.executeLifecycle(action) ;
+            return ;
+        }
+        if ( false )  {
+            // Execute by calling the whole servlet mechanism.
+            // This causes HttpServlet.service to call the appropriate 
doMethod.
+            // but the action, and the id, are not passed on and a ne one is 
created.
+            try { servlet.service(action.request, action.response) ; }
+            catch (ServletException | IOException e) {
+                ServletOps.errorOccurred(e);
+            }
+        }
+    }
+
+    protected static MediaType contentNegotationQuads(HttpAction action) {
+        MediaType mt = ConNeg.chooseContentType(action.request, 
DEF.quadsOffer, DEF.acceptNQuads) ;
+        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 ;
+    }
+
+    /** Find part after the dataset name: service name or the graph (direct 
naming) */
+    protected String findTrailing(String uri, String dsname) {
+        if ( dsname.length() >= uri.length() )
+            return "" ;
+        return uri.substring(dsname.length()+1) ;   // Skip the separating "/"
+    }
+
+    // Route everything to "doCommon"
+    @Override
+    protected void doHead(HttpServletRequest request, HttpServletResponse 
response)
+    { doCommon(request, response) ; }
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse 
response)
+    { doCommon(request, response) ; }
+
+    @Override
+    protected void doPost(HttpServletRequest request, HttpServletResponse 
response)
+    { doCommon(request, response) ; }
+
+    @Override
+    protected void doOptions(HttpServletRequest request, HttpServletResponse 
response)
+    { doCommon(request, response) ; }
+
+    @Override
+    protected void doPut(HttpServletRequest request, HttpServletResponse 
response)
+    { doCommon(request, response) ; }
+
+    @Override
+    protected void doDelete(HttpServletRequest request, HttpServletResponse 
response)
+    { doCommon(request, response) ; }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Update.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Update.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Update.java
index 0807bf6..cc9147f 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Update.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Update.java
@@ -74,8 +74,6 @@ public class SPARQL_Update extends SPARQL_Protocol
     public SPARQL_Update()
     { super() ; }
 
-    // doMethod : Not used with UberServlet dispatch.
-
     @Override
     protected void doGet(HttpServletRequest request, HttpServletResponse 
response)
             throws ServletException, IOException {

http://git-wip-us.apache.org/repos/asf/jena/blob/6d89af35/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Upload.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Upload.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Upload.java
index 1dc53df..31bd0c6 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Upload.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Upload.java
@@ -71,6 +71,10 @@ public class SPARQL_Upload extends ActionSPARQL
     }
 
     @Override
+    protected void validate(HttpAction action)
+    {}
+
+    @Override
     protected void perform(HttpAction action) {
         // Only allows one file in the upload.
         boolean isMultipart = 
ServletFileUpload.isMultipartContent(action.request);
@@ -258,7 +262,7 @@ public class SPARQL_Upload extends ActionSPARQL
 
                     StreamRDF x = StreamRDFLib.dataset(dsgTmp) ;
                     StreamRDFCounting dest = StreamRDFLib.count(x) ;
-                    ActionSPARQL.parse(action, dest, stream, lang, base) ;
+                    ActionLib.parse(action, dest, stream, lang, base) ;
                     count = dest.count() ;
                 }
             }
@@ -272,8 +276,4 @@ public class SPARQL_Upload extends ActionSPARQL
         catch (ActionErrorException ex) { throw ex ; }
         catch (Exception ex)            { ServletOps.errorOccurred(ex) ; 
return null ; }
     }
-
-    @Override
-    protected void validate(HttpAction action)
-    {}
 }

Reply via email to