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 2018/09/21 10:16:16 UTC

[65/70] [abbrv] jena git commit: Reorganise library code.

Reorganise library code.

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

Branch: refs/heads/master
Commit: 0c218559beb8521a1ed5bf0ef9335056fd6684d1
Parents: 1d4a5f2
Author: Andy Seaborne <an...@apache.org>
Authored: Fri Sep 14 18:24:34 2018 +0100
Committer: Andy Seaborne <an...@apache.org>
Committed: Fri Sep 14 18:24:34 2018 +0100

----------------------------------------------------------------------
 .../java/org/apache/jena/atlas/web/WebLib.java  |  12 +
 .../access/AbstractTestSecurityAssembler.java   |   4 +-
 .../fuseki/access/TestSecurityFilterFuseki.java |   4 +-
 .../java/org/apache/jena/fuseki/Fuseki.java     |  76 ++++++
 .../java/org/apache/jena/fuseki/FusekiLib.java  | 238 -------------------
 .../build/DatasetDescriptionRegistry.java       |  17 +-
 .../apache/jena/fuseki/build/FusekiBuilder.java | 139 +++--------
 .../apache/jena/fuseki/build/FusekiConfig.java  |  88 ++++++-
 .../org/apache/jena/fuseki/conneg/ConNeg.java   | 206 ----------------
 .../org/apache/jena/fuseki/conneg/WebLib.java   |  60 -----
 .../apache/jena/fuseki/servlets/ActionLib.java  |  12 +-
 .../jena/fuseki/servlets/REST_Quads_RW.java     |   4 +-
 .../jena/fuseki/servlets/ResponseDataset.java   |   6 +-
 .../jena/fuseki/servlets/ResponseResultSet.java |   2 +-
 .../jena/fuseki/servlets/SPARQL_GSP_RW.java     |   8 +-
 .../jena/fuseki/servlets/SPARQL_Query.java      |   6 +-
 .../jena/fuseki/servlets/SPARQL_Update.java     |   5 +-
 .../jena/fuseki/servlets/SPARQL_Upload.java     |   6 +-
 .../jena/fuseki/servlets/ServiceRouter.java     |   2 +-
 .../org/apache/jena/fuseki/system/ConNeg.java   | 206 ++++++++++++++++
 .../apache/jena/fuseki/system/FusekiNetLib.java | 179 ++++++++++++++
 .../org/apache/jena/fuseki/system/Upload.java   |   3 +-
 .../jena/fuseki/validation/ValidatorBase.java   |   2 +-
 .../validation/html/DataValidatorHTML.java      |   4 +-
 .../org/apache/jena/fuseki/main/FusekiLib.java  |  74 ++++++
 .../apache/jena/fuseki/main/FusekiTestAuth.java |   4 +-
 .../jena/fuseki/main/FusekiTestServer.java      |   4 +-
 .../jena/fuseki/main/TestEmbeddedFuseki.java    |  20 +-
 .../fuseki/main/TestFusekiCustomOperation.java  |   4 +-
 .../jena/fuseki/main/TestMultipleEmbedded.java  |  16 +-
 .../examples/ExtendFuseki_AddService_1.java     |   4 +-
 .../examples/ExtendFuseki_AddService_2.java     |   4 +-
 .../examples/ExtendFuseki_AddService_3.java     |   4 +-
 .../apache/jena/fuseki/mgt/ActionDatasets.java  |  22 +-
 .../apache/jena/fuseki/webapp/FusekiSystem.java |   2 +-
 .../java/org/apache/jena/fuseki/ServerCtl.java  |   5 +-
 .../java/org/apache/jena/fuseki/TestAuth.java   |   5 +-
 .../org/apache/jena/fuseki/TestBuilder.java     |  10 +-
 .../TestRDFConnectionFusekiBinary.java          |   9 +-
 .../rdfconnection/TestRDFConnectionRemote.java  |   4 +-
 40 files changed, 771 insertions(+), 709 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-arq/src/main/java/org/apache/jena/atlas/web/WebLib.java
----------------------------------------------------------------------
diff --git a/jena-arq/src/main/java/org/apache/jena/atlas/web/WebLib.java b/jena-arq/src/main/java/org/apache/jena/atlas/web/WebLib.java
index a062eca..5d2f4fe 100644
--- a/jena-arq/src/main/java/org/apache/jena/atlas/web/WebLib.java
+++ b/jena-arq/src/main/java/org/apache/jena/atlas/web/WebLib.java
@@ -18,6 +18,9 @@
 
 package org.apache.jena.atlas.web;
 
+import java.io.IOException;
+import java.net.ServerSocket;
+
 public class WebLib
 {
     /** Split a string, removing whitespace around the split string.
@@ -33,4 +36,13 @@ public class WebLib
         return x ;
     }
 
+    /** Choose an unused port for a server to listen on */
+    public static int choosePort() {
+        try (ServerSocket s = new ServerSocket(0)) {
+            return s.getLocalPort();
+        } catch (IOException ex) {
+            throw new RuntimeException("Failed to find a port");
+        }
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/AbstractTestSecurityAssembler.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/AbstractTestSecurityAssembler.java b/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/AbstractTestSecurityAssembler.java
index 562e3e8..a7e5ac1 100644
--- a/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/AbstractTestSecurityAssembler.java
+++ b/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/AbstractTestSecurityAssembler.java
@@ -32,8 +32,8 @@ import org.apache.jena.atlas.iterator.Iter;
 import org.apache.jena.atlas.lib.SetUtils;
 import org.apache.jena.atlas.lib.StrUtils;
 import org.apache.jena.atlas.web.HttpException;
-import org.apache.jena.fuseki.FusekiLib;
 import org.apache.jena.fuseki.main.FusekiServer;
+import org.apache.jena.fuseki.system.FusekiNetLib;
 import org.apache.jena.graph.Node;
 import org.apache.jena.query.Dataset;
 import org.apache.jena.query.QuerySolution;
@@ -102,7 +102,7 @@ public abstract class AbstractTestSecurityAssembler {
     }
     
     private static FusekiServer setup(String assembler, boolean sharedDatabase) {
-        int port = FusekiLib.choosePort();
+        int port = FusekiNetLib.choosePort();
         FusekiServer server = DataAccessCtl.fusekiBuilder((a)->user.get())
             .port(port)
             .parseConfigFile(assembler)

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/TestSecurityFilterFuseki.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/TestSecurityFilterFuseki.java b/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/TestSecurityFilterFuseki.java
index 844b67e..fb236ab 100644
--- a/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/TestSecurityFilterFuseki.java
+++ b/jena-fuseki2/jena-fuseki-access/src/test/java/org/apache/jena/fuseki/access/TestSecurityFilterFuseki.java
@@ -34,9 +34,9 @@ import java.util.Set;
 import org.apache.jena.atlas.iterator.Iter;
 import org.apache.jena.atlas.lib.SetUtils;
 import org.apache.jena.atlas.web.HttpException;
-import org.apache.jena.fuseki.FusekiLib;
 import org.apache.jena.fuseki.jetty.JettyLib;
 import org.apache.jena.fuseki.main.FusekiServer;
+import org.apache.jena.fuseki.system.FusekiNetLib;
 import org.apache.jena.graph.Node;
 import org.apache.jena.query.QuerySolution;
 import org.apache.jena.rdf.model.Model;
@@ -81,7 +81,7 @@ public class TestSecurityFilterFuseki {
 
     // Set up Fuseki with two datasets, "data1" backed by TDB and "data2" backed by TDB2.
     @BeforeClass public static void beforeClass() {
-        int port = FusekiLib.choosePort();
+        int port = FusekiNetLib.choosePort();
         addTestData(testdsg1);
         addTestData(testdsg2);
         addTestData(testdsg3);

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/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 4e5f1ac..dc5493b 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
@@ -18,17 +18,29 @@
 
 package org.apache.jena.fuseki ;
 
+import java.io.IOException;
 import java.util.Calendar ;
 import java.util.TimeZone ;
 import java.util.concurrent.TimeUnit ;
 
 import javax.servlet.ServletContext;
 
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpOptions;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.protocol.HttpContext;
 import org.apache.jena.atlas.lib.DateTimeUtils ;
+import org.apache.jena.atlas.logging.Log;
+import org.apache.jena.atlas.web.HttpException;
+import org.apache.jena.fuseki.system.FusekiNetLib;
 import org.apache.jena.query.ARQ ;
+import org.apache.jena.rdfconnection.RDFConnectionRemote;
 import org.apache.jena.riot.system.stream.LocatorFTP ;
 import org.apache.jena.riot.system.stream.LocatorHTTP ;
 import org.apache.jena.riot.system.stream.StreamManager ;
+import org.apache.jena.riot.web.HttpOp;
 import org.apache.jena.sparql.SystemARQ ;
 import org.apache.jena.sparql.lib.Metadata ;
 import org.apache.jena.sparql.mgt.SystemInfo ;
@@ -278,4 +290,68 @@ public class Fuseki {
     static {
         init() ;
     }
+
+    /** Retrun a free port */
+    public static int choosePort() {
+        return FusekiNetLib.choosePort();
+    }
+    
+    /**
+     * Test whether a URL identifies a Fuseki server. This operation can not guarantee to
+     * detect a Fuseki server - for example, it may be behind a reverse proxy that masks
+     * the signature.
+     */
+    public static boolean isFuseki(String datasetURL) {
+        HttpOptions request = new HttpOptions(datasetURL);
+        HttpClient httpClient = HttpOp.getDefaultHttpClient();
+        if ( httpClient == null ) 
+            httpClient = HttpClients.createSystem();
+        return isFuseki(request, httpClient, null);
+    }
+
+    /**
+     * Test whether a {@link RDFConnectionRemote} connects to a Fuseki server. This
+     * operation can not guaranttee to detech a Fuseki server - for example, it may be
+     * behind a reverse proxy that masks the signature.
+     */
+    public static boolean isFuseki(RDFConnectionRemote connection) {
+        HttpOptions request = new HttpOptions(connection.getDestination());
+        HttpClient httpClient = connection.getHttpClient();
+        if ( httpClient == null ) 
+            httpClient = HttpClients.createSystem();
+        HttpContext httpContext = connection.getHttpContext();
+        return isFuseki(request, httpClient, httpContext);
+    }
+
+    private static boolean isFuseki(HttpOptions request, HttpClient httpClient, HttpContext httpContext) {
+        try {
+            HttpResponse response = httpClient.execute(request);
+            // Fuseki does not send "Server" in release mode.
+            // (best practice).
+            // All we can do is try for the "Fuseki-Request-ID" 
+            String reqId = safeGetHeader(response, "Fuseki-Request-ID");
+            if ( reqId != null )
+                return true;
+    
+            // If returning "Server"
+            String serverIdent = safeGetHeader(response, "Server");
+            if ( serverIdent != null ) {
+                Log.debug(ARQ.getHttpRequestLogger(), "Server: "+serverIdent);
+                boolean isFuseki = serverIdent.startsWith("Apache Jena Fuseki");
+                if ( !isFuseki )
+                    isFuseki = serverIdent.toLowerCase().contains("fuseki");
+                return isFuseki;
+            }
+            return false; 
+        } catch (IOException ex) {
+            throw new HttpException("Failed to check for a Fuseki server", ex);
+        }
+    }
+
+    static String safeGetHeader(HttpResponse response, String header) {
+        Header h = response.getFirstHeader(header);
+        if ( h == null )
+            return null;
+        return h.getValue();
+    }
 }

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/FusekiLib.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/FusekiLib.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/FusekiLib.java
deleted file mode 100644
index e540a67..0000000
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/FusekiLib.java
+++ /dev/null
@@ -1,238 +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;
-
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.util.Iterator ;
-
-import javax.servlet.http.HttpServletRequest ;
-
-import org.apache.http.Header;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpOptions;
-import org.apache.http.impl.client.HttpClients;
-import org.apache.http.protocol.HttpContext;
-import org.apache.jena.atlas.logging.Log;
-import org.apache.jena.atlas.web.ContentType ;
-import org.apache.jena.atlas.web.HttpException;
-import org.apache.jena.ext.com.google.common.collect.ArrayListMultimap;
-import org.apache.jena.ext.com.google.common.collect.Multimap;
-import org.apache.jena.fuseki.servlets.HttpAction ;
-import org.apache.jena.graph.Graph ;
-import org.apache.jena.graph.Node ;
-import org.apache.jena.graph.Triple ;
-import org.apache.jena.query.* ;
-import org.apache.jena.rdfconnection.RDFConnectionRemote;
-import org.apache.jena.riot.Lang ;
-import org.apache.jena.riot.RDFLanguages ;
-import org.apache.jena.riot.web.HttpOp;
-import org.apache.jena.shared.PrefixMapping ;
-import org.apache.jena.sparql.core.DatasetGraph ;
-import org.apache.jena.sparql.core.Quad ;
-import org.apache.jena.sparql.util.Convert ;
-
-public class FusekiLib {
-    // ==> ActionLib
-    
-    /** Get the content type of an action or return the default.
-     * @param  action
-     * @return ContentType
-     */
-    public static ContentType getContentType(HttpAction action) {
-        return getContentType(action.request) ;
-    }
-    
-    /** Get the content type of an action or return the default.
-     * @param  request
-     * @return ContentType
-     */
-    public static ContentType getContentType(HttpServletRequest request) {
-        String contentTypeHeader = request.getContentType() ;
-        if ( contentTypeHeader == null ) 
-            return null ;
-        return ContentType.create(contentTypeHeader) ;
-    }
-    
-    /** Get the incoming {@link Lang} based on Content-Type of an action.
-     * @param  action
-     * @param  dft Default if no "Content-Type:" found. 
-     * @return ContentType
-     */
-    public static Lang getLangFromAction(HttpAction action, Lang dft) {
-        String contentTypeHeader = action.request.getContentType() ;
-        if ( contentTypeHeader == null )
-            return dft ;
-        return RDFLanguages.contentTypeToLang(contentTypeHeader) ;
-    }
-
-    static String fmtRequest(HttpServletRequest request) {
-        StringBuffer sbuff = new StringBuffer() ;
-        sbuff.append(request.getMethod()) ;
-        sbuff.append(" ") ;
-        sbuff.append(Convert.decWWWForm(request.getRequestURL())) ;
-
-        String qs = request.getQueryString() ;
-        if ( qs != null ) {
-            String tmp = request.getQueryString() ;
-            tmp = Convert.decWWWForm(tmp) ;
-            tmp = tmp.replace('\n', ' ') ;
-            tmp = tmp.replace('\r', ' ') ;
-            sbuff.append("?").append(tmp) ;
-        }
-        return sbuff.toString() ;
-    }
-
-    /** Parse the query string - do not process the body even for a form */
-    public static Multimap<String, String> parseQueryString(HttpServletRequest req) {
-        Multimap<String, String> map = ArrayListMultimap.create() ;
-
-        // Don't use ServletRequest.getParameter or getParamterNames
-        // as that reads form data. This code parses just the query string.
-        if ( req.getQueryString() != null ) {
-            String[] params = req.getQueryString().split("&") ;
-            for (int i = 0; i < params.length; i++) {
-                String p = params[i] ;
-                String[] x = p.split("=", 2) ;
-                String name = null ;
-                String value = null ;
-
-                if ( x.length == 0 ) { // No "="
-                    name = p ;
-                    value = "" ;
-                } else if ( x.length == 1 ) { // param=
-                    name = x[0] ;
-                    value = "" ;
-                } else { // param=value
-                    name = x[0] ;
-                    value = x[1] ;
-                }
-                map.put(name, value) ;
-            }
-        }
-        return map ;
-    }
-    
-    public static String safeParameter(HttpServletRequest request, String pName) {
-        String value = request.getParameter(pName) ;
-        if ( value == null )
-            return null ;
-        value = value.replace("\r", "") ;
-        value = value.replace("\n", "") ;
-        return value ;
-    }
-
-    // Do the addition directly on the dataset
-    public static void addDataInto(Graph data, DatasetGraph dsg, Node graphName) {
-        // Prefixes?
-        if ( graphName == null )
-            graphName = Quad.defaultGraphNodeGenerated ;
-
-        Iterator<Triple> iter = data.find(Node.ANY, Node.ANY, Node.ANY) ;
-        for (; iter.hasNext();) {
-            Triple t = iter.next() ;
-            dsg.add(graphName, t.getSubject(), t.getPredicate(), t.getObject()) ;
-        }
-
-        PrefixMapping pmapSrc = data.getPrefixMapping() ;
-        PrefixMapping pmapDest = dsg.getDefaultGraph().getPrefixMapping() ;
-        pmapDest.setNsPrefixes(pmapSrc) ;
-    }
-    
-    public static void addDataInto(DatasetGraph src, DatasetGraph dest) {
-        Iterator<Quad> iter = src.find(Node.ANY, Node.ANY, Node.ANY, Node.ANY) ;
-        for (; iter.hasNext();) {
-            Quad q = iter.next() ;
-            dest.add(q) ;
-        }
-
-        PrefixMapping pmapSrc = src.getDefaultGraph().getPrefixMapping() ;
-        PrefixMapping pmapDest = dest.getDefaultGraph().getPrefixMapping() ;
-        pmapDest.withDefaultMappings(pmapSrc) ;
-    }
-
-    /** Choose an unused port for a server to listen on */
-    public static int choosePort() {
-        try (ServerSocket s = new ServerSocket(0)) {
-            return s.getLocalPort();
-        } catch (IOException ex) {
-            throw new FusekiException("Failed to find a port");
-        }
-    }
-
-    /**
-     * Test whether a URL identifies a Fuseki server. This operation can not guarantee to
-     * detect a Fuseki server - for example, it may be behind a reverse proxy that masks
-     * the signature.
-     */
-    public static boolean isFuseki(String datasetURL) {
-        HttpOptions request = new HttpOptions(datasetURL);
-        HttpClient httpClient = HttpOp.getDefaultHttpClient();
-        if ( httpClient == null ) 
-            httpClient = HttpClients.createSystem();
-        return isFuseki(request, httpClient, null);
-    }
-
-    /**
-     * Test whether a {@link RDFConnectionRemote} connects to a Fuseki server. This
-     * operation can not guaranttee to detech a Fuseki server - for example, it may be
-     * behind a reverse proxy that masks the signature.
-     */
-    public static boolean isFuseki(RDFConnectionRemote connection) {
-        HttpOptions request = new HttpOptions(connection.getDestination());
-        HttpClient httpClient = connection.getHttpClient();
-        if ( httpClient == null ) 
-            httpClient = HttpClients.createSystem();
-        HttpContext httpContext = connection.getHttpContext();
-        return isFuseki(request, httpClient, httpContext);
-    }
-
-    private static boolean isFuseki(HttpOptions request, HttpClient httpClient, HttpContext httpContext) {
-        try {
-            HttpResponse response = httpClient.execute(request);
-            // Fuseki does not send "Server" in release mode.
-            // (best practice).
-            // All we can do is try for the "Fuseki-Request-ID" 
-            String reqId = safeGetHeader(response, "Fuseki-Request-ID");
-            if ( reqId != null )
-                return true;
-
-            // If returning "Server"
-            String serverIdent = safeGetHeader(response, "Server");
-            if ( serverIdent != null ) {
-                Log.debug(ARQ.getHttpRequestLogger(), "Server: "+serverIdent);
-                boolean isFuseki = serverIdent.startsWith("Apache Jena Fuseki");
-                if ( !isFuseki )
-                    isFuseki = serverIdent.toLowerCase().contains("fuseki");
-                return isFuseki;
-            }
-            return false; 
-        } catch (IOException ex) {
-            throw new HttpException("Failed to check for a Fuseki server", ex);
-        }
-    }
-    
-    private static String safeGetHeader(HttpResponse response, String header) {
-        Header h = response.getFirstHeader(header);
-        if ( h == null )
-            return null;
-        return h.getValue();
-    }
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/DatasetDescriptionRegistry.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/DatasetDescriptionRegistry.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/DatasetDescriptionRegistry.java
index 6443b55..b49c5be 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/DatasetDescriptionRegistry.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/DatasetDescriptionRegistry.java
@@ -18,6 +18,9 @@
 
 package org.apache.jena.fuseki.build;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import org.apache.jena.atlas.logging.Log ;
 import org.apache.jena.query.Dataset;
 import org.apache.jena.rdf.model.Resource;
@@ -36,27 +39,17 @@ import org.apache.jena.rdf.model.Resource;
  */
 public class DatasetDescriptionRegistry  {
 	
-	private RefCountingMap<Resource, Dataset> map = new RefCountingMap<>() ;
+	private Map<Resource, Dataset> map = new HashMap<>();
 	
 	public DatasetDescriptionRegistry() {}
 	
-    /** Use a mapping. This will add a mapping or increment any reference counting. */
     public void register(Resource node, Dataset ds) {
         Dataset dsCurrent = map.get(node) ;
         if ( dsCurrent != null ) {
             if ( ! dsCurrent.equals(ds) )
                 Log.warn(this.getClass(), "Replacing registered dataset for "+node);
         }
-        map.add(node, ds);
-    }
-
-    /** Stop using a mapping. */
-    public void unregister(Resource node) {
-        map.remove(node);
-    }
-
-    public int refCount(Resource node) {
-        return map.refCount(node);
+        map.put(node, ds);
     }
 
     public Dataset get(Resource node) {

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/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 2a673c7..c9fe706 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
@@ -18,113 +18,23 @@
 
 package org.apache.jena.fuseki.build;
 
-import static java.lang.String.format ;
-import static org.apache.jena.fuseki.server.FusekiVocab.pServiceQueryEP;
-import static org.apache.jena.fuseki.server.FusekiVocab.pServiceReadGraphStoreEP;
-import static org.apache.jena.fuseki.server.FusekiVocab.pServiceReadQuadsEP;
-import static org.apache.jena.fuseki.server.FusekiVocab.pServiceReadWriteGraphStoreEP;
-import static org.apache.jena.fuseki.server.FusekiVocab.pServiceReadWriteQuadsEP;
-import static org.apache.jena.fuseki.server.FusekiVocab.pServiceUpdateEP;
-import static org.apache.jena.fuseki.server.FusekiVocab.pServiceUploadEP;
-
-import org.apache.jena.assembler.Assembler ;
-import org.apache.jena.datatypes.xsd.XSDDatatype ;
-import org.apache.jena.fuseki.Fuseki ;
-import org.apache.jena.fuseki.FusekiConfigException ;
-import org.apache.jena.fuseki.server.DataAccessPoint ;
+import org.apache.jena.fuseki.FusekiConfigException;
+import org.apache.jena.fuseki.server.DataAccessPoint;
+import org.apache.jena.fuseki.server.DataAccessPointRegistry;
 import org.apache.jena.fuseki.server.DataService ;
 import org.apache.jena.fuseki.server.Operation ;
-import org.apache.jena.query.Dataset ;
 import org.apache.jena.query.QuerySolution ;
 import org.apache.jena.query.ResultSet ;
-import org.apache.jena.rdf.model.Literal ;
 import org.apache.jena.rdf.model.Property ;
-import org.apache.jena.rdf.model.RDFNode ;
 import org.apache.jena.rdf.model.Resource ;
 import org.apache.jena.sparql.core.DatasetGraph ;
-import org.apache.jena.sparql.util.FmtUtils ;
-import org.apache.jena.vocabulary.RDF ;
 
 /**
  * Helper functions use to construct Fuseki servers.
+ * @see FusekiConfig
  */
 public class FusekiBuilder
 {
-    /** Build a DataAccessPoint, including DataService, from the description at Resource svc */ 
-    public static DataAccessPoint buildDataAccessPoint(Resource svc, DatasetDescriptionRegistry dsDescMap) {
-        RDFNode n = FusekiBuildLib.getOne(svc, "fu:name") ;
-        if ( ! n.isLiteral() )
-            throw new FusekiConfigException("Not a literal for access point name: "+FmtUtils.stringForRDFNode(n));
-        Literal object = n.asLiteral() ;
-
-        if ( object.getDatatype() != null && ! object.getDatatype().equals(XSDDatatype.XSDstring) )
-            Fuseki.configLog.error(format("Service name '%s' is not a string", FmtUtils.stringForRDFNode(object)));
-        String name = object.getLexicalForm() ;
-        name = DataAccessPoint.canonical(name) ;
-
-        DataService dataService = buildDataServiceCustom(svc, dsDescMap) ;
-        DataAccessPoint dataAccess = new DataAccessPoint(name, dataService) ;
-        return dataAccess ;
-    }
-
-    /** Build a DatasetRef starting at Resource svc, having the services as described by the descriptions. */
-    private static DataService buildDataServiceCustom(Resource svc, DatasetDescriptionRegistry dsDescMap) {
-        Resource datasetDesc = ((Resource)getOne(svc, "fu:dataset")) ;
-        Dataset ds = getDataset(datasetDesc, dsDescMap);
- 
-        // In case the assembler included ja:contents
-        DataService dataService = new DataService(ds.asDatasetGraph()) ;
-
-        addServiceEP(dataService, Operation.Query,  svc,    pServiceQueryEP) ;
-        addServiceEP(dataService, Operation.Update, svc,    pServiceUpdateEP) ;
-        addServiceEP(dataService, Operation.Upload, svc,    pServiceUploadEP);
-        addServiceEP(dataService, Operation.GSP_R,  svc,    pServiceReadGraphStoreEP) ;
-        addServiceEP(dataService, Operation.GSP_RW, svc,    pServiceReadWriteGraphStoreEP) ;
-
-        addServiceEP(dataService, Operation.Quads_R, svc,   pServiceReadQuadsEP) ;
-        addServiceEP(dataService, Operation.Quads_RW, svc,  pServiceReadWriteQuadsEP) ;
-        
-        // Quads - actions directly on the dataset URL are different.
-        // In the config file they are also implicit when using GSP.
-        
-        if ( ! dataService.getEndpoints(Operation.GSP_RW).isEmpty() || ! dataService.getEndpoints(Operation.Quads_RW).isEmpty() ) {
-            // ReadWrite available.
-            // Dispatch needs introspecting on the HTTP request.
-            dataService.addEndpoint(Operation.DatasetRequest_RW, "") ;
-        } else if ( ! dataService.getEndpoints(Operation.GSP_R).isEmpty() || ! dataService.getEndpoints(Operation.Quads_R).isEmpty() ) {
-            // Read-only available.
-            // Dispatch needs introspecting on the HTTP request.
-            dataService.addEndpoint(Operation.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() ;
-//            if ( svc.hasProperty(FusekiVocab.pMaximumTimeoutOverride) ) {
-//                sDesc.maximumTimeoutOverride = (int)(svc.getProperty(FusekiVocab.pMaximumTimeoutOverride).getObject().asLiteral().getFloat() * 1000) ;
-//            }
-//        }
-
-        return dataService ;
-    }
-    
-    public static Dataset getDataset(Resource datasetDesc, DatasetDescriptionRegistry dsDescMap) {
-    	// check if this one already built
-    	Dataset ds = dsDescMap.get(datasetDesc);
-    	if (ds == null) {
-    	    // Check if the description is in the model.
-            if ( !datasetDesc.hasProperty(RDF.type) )
-                throw new FusekiConfigException("No rdf:type for dataset " + FusekiBuildLib.nodeLabel(datasetDesc)) ;
-            ds = (Dataset)Assembler.general.open(datasetDesc) ;
-    	}
-    	// Some kind of check that it is "the same" dataset.  
-    	// It can be different if two descriptions in different files have the same URI.
-    	dsDescMap.register(datasetDesc, ds);
-    	return ds;
-    }
-    
     /** 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) ;
@@ -153,18 +63,7 @@ public class FusekiBuilder
         dataService.addEndpoint(operation, endpointName) ; 
     }
 
-    public static RDFNode getOne(Resource svc, String property) {
-        String ln = property.substring(property.indexOf(':') + 1) ;
-        ResultSet rs = FusekiBuildLib.query("SELECT * { ?svc " + property + " ?x}", svc.getModel(), "svc", svc) ;
-        if ( !rs.hasNext() )
-            throw new FusekiConfigException("No " + ln + " for service " + FusekiBuildLib.nodeLabel(svc)) ;
-        RDFNode x = rs.next().get("x") ;
-        if ( rs.hasNext() )
-            throw new FusekiConfigException("Multiple " + ln + " for service " + FusekiBuildLib.nodeLabel(svc)) ;
-        return x ;
-    }
-
-    private static void addServiceEP(DataService dataService, Operation operation, Resource svc, Property property) {
+    public static void addServiceEP(DataService dataService, Operation operation, Resource svc, Property property) {
         String p = "<"+property.getURI()+">" ;
         ResultSet rs = FusekiBuildLib.query("SELECT * { ?svc " + p + " ?ep}", svc.getModel(), "svc", svc) ;
         for ( ; rs.hasNext() ; ) {
@@ -174,5 +73,33 @@ public class FusekiBuilder
             //log.info("  " + operation.name + " = " + dataAccessPoint.getName() + "/" + epName) ;
         }
     }
+    
+    public static void addDataService(DataAccessPointRegistry dataAccessPoints, String name, DataService dataService) {
+        name = DataAccessPoint.canonical(name);
+        if ( dataAccessPoints.isRegistered(name) )
+            throw new FusekiConfigException("Data service name already registered: "+name);
+        DataAccessPoint dap = new DataAccessPoint(name, dataService);
+        dataAccessPoints.register(dap);
+    }
+    
+    public static void addDataset(DataAccessPointRegistry dataAccessPoints, String name, DatasetGraph dsg, boolean withUpdate) {
+        name = DataAccessPoint.canonical(name);
+        if ( dataAccessPoints.isRegistered(name) )
+            throw new FusekiConfigException("Data service name already registered: "+name);
+        DataAccessPoint dap = buildDataAccessPoint(name, dsg, withUpdate);
+        dataAccessPoints.register(dap);
+    }
+    
+    private static DataAccessPoint buildDataAccessPoint(String name, DatasetGraph dsg, boolean withUpdate) { 
+        // See Builder. DRY.
+        DataService dataService = FusekiBuilder.buildDataServiceStd(dsg, withUpdate);
+        DataAccessPoint dap = new DataAccessPoint(name, dataService);
+        return dap;
+    }
+    
+    public static void removeDataset(DataAccessPointRegistry dataAccessPoints, String name) {
+        name = DataAccessPoint.canonical(name);
+        dataAccessPoints.remove(name);
+    }
 }
 

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiConfig.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiConfig.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiConfig.java
index 9673cfa..7bf5ea0 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiConfig.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiConfig.java
@@ -18,6 +18,8 @@
 
 package org.apache.jena.fuseki.build ;
 
+import static java.lang.String.format;
+import static org.apache.jena.fuseki.server.FusekiVocab.*;
 import static org.apache.jena.riot.RDFLanguages.filenameToLang;
 import static org.apache.jena.riot.RDFParserRegistry.isRegistered;
 
@@ -32,9 +34,11 @@ import java.util.ArrayList ;
 import java.util.Collections ;
 import java.util.List ;
 
+import org.apache.jena.assembler.Assembler;
 import org.apache.jena.assembler.JA ;
 import org.apache.jena.atlas.lib.IRILib ;
 import org.apache.jena.atlas.lib.StrUtils ;
+import org.apache.jena.datatypes.xsd.XSDDatatype;
 import org.apache.jena.fuseki.Fuseki ;
 import org.apache.jena.fuseki.FusekiConfigException ;
 import org.apache.jena.fuseki.server.* ;
@@ -45,7 +49,9 @@ import org.apache.jena.query.ResultSet ;
 import org.apache.jena.rdf.model.* ;
 import org.apache.jena.riot.Lang;
 import org.apache.jena.sparql.core.assembler.AssemblerUtils ;
+import org.apache.jena.sparql.util.FmtUtils;
 import org.apache.jena.sparql.util.graph.GraphUtils;
+import org.apache.jena.vocabulary.RDF;
 import org.slf4j.Logger ;
 
 public class FusekiConfig {
@@ -117,7 +123,7 @@ public class FusekiConfig {
         for ( ; rs.hasNext() ; ) {
             QuerySolution soln = rs.next() ;
             Resource svc = soln.getResource("service") ;
-            DataAccessPoint acc = FusekiBuilder.buildDataAccessPoint(svc, dsDescMap) ;
+            DataAccessPoint acc = buildDataAccessPoint(svc, dsDescMap) ;
             accessPoints.add(acc) ;
         }
         return accessPoints ;
@@ -191,10 +197,86 @@ public class FusekiConfig {
         }
 
         for ( Resource service : services ) {
-            DataAccessPoint acc = FusekiBuilder.buildDataAccessPoint(service, dsDescMap) ; 
+            DataAccessPoint acc = buildDataAccessPoint(service, dsDescMap) ; 
             dataServiceRef.add(acc) ;
         }
     }
+    
+    /** Build a DataAccessPoint, including DataService, from the description at Resource svc */ 
+    public static DataAccessPoint buildDataAccessPoint(Resource svc, DatasetDescriptionRegistry dsDescMap) {
+        RDFNode n = FusekiBuildLib.getOne(svc, "fu:name") ;
+        if ( ! n.isLiteral() )
+            throw new FusekiConfigException("Not a literal for access point name: "+FmtUtils.stringForRDFNode(n));
+        Literal object = n.asLiteral() ;
+
+        if ( object.getDatatype() != null && ! object.getDatatype().equals(XSDDatatype.XSDstring) )
+            Fuseki.configLog.error(format("Service name '%s' is not a string", FmtUtils.stringForRDFNode(object)));
+        String name = object.getLexicalForm() ;
+        name = DataAccessPoint.canonical(name) ;
+
+        DataService dataService = buildDataServiceCustom(svc, dsDescMap) ;
+        DataAccessPoint dataAccess = new DataAccessPoint(name, dataService) ;
+        return dataAccess ;
+    }
+
+    /** Build a DatasetRef starting at Resource svc, having the services as described by the descriptions. */
+    private static DataService buildDataServiceCustom(Resource svc, DatasetDescriptionRegistry dsDescMap) {
+        Resource datasetDesc = ((Resource)FusekiBuildLib.getOne(svc, "fu:dataset")) ;
+        Dataset ds = getDataset(datasetDesc, dsDescMap);
+ 
+        // In case the assembler included ja:contents
+        DataService dataService = new DataService(ds.asDatasetGraph()) ;
+
+        FusekiBuilder.addServiceEP(dataService, Operation.Query,  svc,    pServiceQueryEP) ;
+        FusekiBuilder.addServiceEP(dataService, Operation.Update, svc,    pServiceUpdateEP) ;
+        FusekiBuilder.addServiceEP(dataService, Operation.Upload, svc,    pServiceUploadEP);
+        FusekiBuilder.addServiceEP(dataService, Operation.GSP_R,  svc,    pServiceReadGraphStoreEP) ;
+        FusekiBuilder.addServiceEP(dataService, Operation.GSP_RW, svc,    pServiceReadWriteGraphStoreEP) ;
+
+        FusekiBuilder.addServiceEP(dataService, Operation.Quads_R, svc,   pServiceReadQuadsEP) ;
+        FusekiBuilder.addServiceEP(dataService, Operation.Quads_RW, svc,  pServiceReadWriteQuadsEP) ;
+        
+        // Quads - actions directly on the dataset URL are different.
+        // In the config file they are also implicit when using GSP.
+        
+        if ( ! dataService.getEndpoints(Operation.GSP_RW).isEmpty() || ! dataService.getEndpoints(Operation.Quads_RW).isEmpty() ) {
+            // ReadWrite available.
+            // Dispatch needs introspecting on the HTTP request.
+            dataService.addEndpoint(Operation.DatasetRequest_RW, "") ;
+        } else if ( ! dataService.getEndpoints(Operation.GSP_R).isEmpty() || ! dataService.getEndpoints(Operation.Quads_R).isEmpty() ) {
+            // Read-only available.
+            // Dispatch needs introspecting on the HTTP request.
+            dataService.addEndpoint(Operation.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() ;
+//            if ( svc.hasProperty(FusekiVocab.pMaximumTimeoutOverride) ) {
+//                sDesc.maximumTimeoutOverride = (int)(svc.getProperty(FusekiVocab.pMaximumTimeoutOverride).getObject().asLiteral().getFloat() * 1000) ;
+//            }
+//        }
+
+        return dataService ;
+    }
+    
+    public static Dataset getDataset(Resource datasetDesc, DatasetDescriptionRegistry dsDescMap) {
+        // check if this one already built
+        Dataset ds = dsDescMap.get(datasetDesc);
+        if (ds == null) {
+            // Check if the description is in the model.
+            if ( !datasetDesc.hasProperty(RDF.type) )
+                throw new FusekiConfigException("No rdf:type for dataset " + FusekiBuildLib.nodeLabel(datasetDesc)) ;
+            ds = (Dataset)Assembler.general.open(datasetDesc) ;
+        }
+        // Some kind of check that it is "the same" dataset.  
+        // It can be different if two descriptions in different files have the same URI.
+        dsDescMap.register(datasetDesc, ds);
+        return ds;
+    }
+
 
     // ---- System database
     /** Read the system database */
@@ -230,7 +312,7 @@ public class FusekiConfig {
                 Model m = ds.getNamedModel(g.getURI()) ;
                 // Rebase the resource of the service description to the containing graph.
                 Resource svc = m.wrapAsResource(s.asNode()) ;
-                DataAccessPoint ref = FusekiBuilder.buildDataAccessPoint(svc, dsDescMap) ;
+                DataAccessPoint ref = buildDataAccessPoint(svc, dsDescMap) ;
                 refs.add(ref) ;
             }
             ds.commit(); 

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/conneg/ConNeg.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/conneg/ConNeg.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/conneg/ConNeg.java
deleted file mode 100644
index 672d2b9..0000000
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/conneg/ConNeg.java
+++ /dev/null
@@ -1,206 +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.conneg;
-
-import static org.apache.jena.riot.web.HttpNames.hAcceptCharset ;
-
-import javax.servlet.http.HttpServletRequest ;
-
-import org.apache.jena.atlas.web.AcceptList ;
-import org.apache.jena.atlas.web.MediaRange ;
-import org.apache.jena.atlas.web.MediaType ;
-import org.slf4j.Logger ;
-import org.slf4j.LoggerFactory ;
-
-/**
- * <p>Content negotiation is a mechanism defined in the HTTP specification
- * that makes it possible to serve different versions of a document
- * (or more generally, a resource representation) at the same URI, so that
- * user agents can specify which version fit their capabilities the best.</p>
- *
- * <p>ConNeg is used in Fuseki to help matching the content media type requested
- * by the user, against the list of offered media types.</p>
- *
- * @see <a href="http://en.wikipedia.org/wiki/Content_negotiation">http://en.wikipedia.org/wiki/Content_negotiation</a>
- * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1">http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1</a>
- */
-public class ConNeg
-{
-    // Logger
-    private static Logger log = LoggerFactory.getLogger(ConNeg.class) ;
-    // See riot.ContentNeg (client side).
-    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
-
-    /**
-     * Parses the content type. It splits the string by semi-colon and finds the
-     * other features such as the "q" quality factor.  For a complete documentation
-     * on how the parsing happens, see
-     * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1">http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1</a>.
-     *
-     * @param contentType content type string
-     * @return parsed media type
-     */
-    static public MediaType parse(String contentType)
-    {
-        try {
-            return MediaType.create(contentType) ;
-        } catch (RuntimeException ex) { return null ; }
-    }
-
-    /**
-     * <p>Creates a {@link AcceptList} with the given HTTP header string and
-     * uses the {@link AcceptList#match(MediaType)} method to decide which
-     * media type matches the HTTP header string.</p>
-     *
-     * <p>The <em>q</em> quality factor is used to decide which choice is the best
-     * match.</p>
-     *
-     * @param headerString HTTP header string
-     * @param offerList accept list
-     * @return matched media type
-     */
-    static public MediaType match(String headerString, AcceptList offerList)
-    {
-        AcceptList l = new AcceptList(headerString) ;
-        return AcceptList.match(l, offerList) ;
-    }
-
-    /**
-     * Match a single media type against a header string.
-     *
-     * @param headerString HTTP header string
-     * @param mediaRangeStr Semi-colon separated list of media types
-     * @return the matched media type or <code>null</code> if there was no match
-     */
-    public static String match(String headerString, String mediaRangeStr)
-    {
-        AcceptList l = new AcceptList(headerString) ;
-        MediaRange aItem = new MediaRange(mediaRangeStr) ;  // MediaType
-        MediaType m = l.match(aItem) ;
-        if ( m == null )
-            return null ;
-        return m.toHeaderString() ;
-    }
-
-    /**
-     * Split and trims a string using a given regex.
-     *
-     * @param s string
-     * @param splitStr given regex
-     * @return an array with the trimmed strings found
-     */
-    /*package*/ static String[] split(String s, String splitStr)
-    {
-        String[] x = s.split(splitStr,2) ;
-        for ( int i = 0 ; i < x.length ; i++ )
-        {
-            x[i] = x[i].trim() ;
-        }
-        return x ;
-    }
-
-    /**
-     * <p>Chooses the charset by using the Accept-Charset HTTP header.</p>
-     *
-     * <p>See {@link ConNeg#choose(String, AcceptList, MediaType)}.</p>
-     *
-     * @param httpRequest HTTP request
-     * @param myPrefs accept list
-     * @param defaultMediaType default media type
-     * @return media type chosen
-     */
-    public static MediaType chooseCharset(HttpServletRequest httpRequest,
-                                          AcceptList myPrefs,
-                                          MediaType defaultMediaType)
-    {
-        String a = httpRequest.getHeader(hAcceptCharset) ;
-        if ( log.isDebugEnabled() )
-            log.debug("Accept-Charset request: "+a) ;
-        
-        MediaType item = choose(a, myPrefs, defaultMediaType) ;
-        
-        if ( log.isDebugEnabled() )
-            log.debug("Charset chosen: "+item) ;
-    
-        return item ;
-    }
-
-    /**
-     * <p>Choose the content media type by extracting the Accept HTTP header from
-     * the HTTP request and choosing
-     * (see {@link ConNeg#choose(String, AcceptList, MediaType)}) a content media
-     * type that matches the header.</p>
-     *
-     * @param httpRequest HTTP request
-     * @param myPrefs accept list
-     * @param defaultMediaType default media type
-     * @return media type chosen
-     */
-    public static MediaType chooseContentType(HttpServletRequest httpRequest,
-                                              AcceptList myPrefs,
-                                              MediaType defaultMediaType)
-    {
-        String a = WebLib.getAccept(httpRequest) ;
-        if ( log.isDebugEnabled() )
-            log.debug("Accept request: "+a) ;
-        
-        MediaType item = choose(a, myPrefs, defaultMediaType) ;
-    
-        if ( log.isDebugEnabled() )
-            log.debug("Content type chosen: "+item) ;
-    
-        return item ;
-    }
-
-    /**
-     * <p>This method receives a HTTP header string, an {@link AcceptList} and a
-     * default {@link MediaType}.</p>
-     *
-     * <p>If the header string is null, it returns the given default MediaType.</p>
-     *
-     * <p>Otherwise it builds an {@link AcceptList} object with the header string
-     * and uses it to match against the given MediaType.</p>
-     *
-     * @param headerString HTTP header string
-     * @param myPrefs accept list
-     * @param defaultMediaType default media type
-     * @return a media type or <code>null</code> if none matched or if the
-     *          HTTP header string and the default media type are <code>null</code>.
-     */
-    private static MediaType choose(String headerString, AcceptList myPrefs,
-                                    MediaType defaultMediaType)
-    {
-        if ( headerString == null )
-            return defaultMediaType ;
-        
-        AcceptList headerList = new AcceptList(headerString) ;
-        
-        if ( myPrefs == null )
-        {
-            MediaType i = headerList.first() ;
-            if ( i == null ) return defaultMediaType ;
-            return i ;
-        }
-    
-        MediaType i = AcceptList.match(headerList, myPrefs) ;
-        if ( i == null )
-            return defaultMediaType ;
-        return i ;
-    }
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/conneg/WebLib.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/conneg/WebLib.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/conneg/WebLib.java
deleted file mode 100644
index 38dc265..0000000
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/conneg/WebLib.java
+++ /dev/null
@@ -1,60 +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.conneg;
-
-import java.util.Enumeration ;
-
-import javax.servlet.http.HttpServletRequest ;
-
-import org.apache.jena.riot.web.HttpNames ;
-
-public class WebLib
-{
-    /** Split a string, removing whitespace around the split string.
-     * e.g. Use in splitting HTTP accept/content-type headers.  
-     */
-    public static String[] split(String s, String splitStr)
-    {
-        String[] x = s.split(splitStr,2) ;
-        for ( int i = 0 ; i < x.length ; i++ )
-        {
-            x[i] = x[i].trim() ;
-        }
-        return x ;
-    }
-
-    /** Migrate to WebLib */
-    public static String getAccept(HttpServletRequest httpRequest)
-    {
-        // There can be multiple accept headers -- note many tools don't allow these to be this way (e.g. wget, curl)
-        Enumeration<String> en = httpRequest.getHeaders(HttpNames.hAccept) ;
-        if ( ! en.hasMoreElements() )
-            return null ;
-        StringBuilder sb = new StringBuilder() ;
-        String sep = "" ;
-        for ( ; en.hasMoreElements() ; )
-        {
-            String x = en.nextElement() ;
-            sb.append(sep) ;
-            sep = ", " ;
-            sb.append(x) ;
-        }
-        return sb.toString() ;
-    }
-}

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/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 e81b7ab..33d51d6 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
@@ -25,11 +25,13 @@ import javax.servlet.http.HttpServletRequest ;
 
 import org.apache.jena.atlas.RuntimeIOException;
 import org.apache.jena.atlas.web.AcceptList ;
+import org.apache.jena.atlas.web.ContentType;
 import org.apache.jena.atlas.web.MediaType ;
 import org.apache.jena.fuseki.DEF ;
-import org.apache.jena.fuseki.conneg.ConNeg ;
 import org.apache.jena.fuseki.server.DataAccessPoint ;
 import org.apache.jena.fuseki.server.DataAccessPointRegistry ;
+import org.apache.jena.fuseki.system.ConNeg;
+import org.apache.jena.fuseki.system.FusekiNetLib;
 import org.apache.jena.riot.Lang;
 import org.apache.jena.riot.RDFParser;
 import org.apache.jena.riot.RDFParserRegistry;
@@ -211,5 +213,13 @@ public class ActionLib {
         }
         catch (RiotException ex) { ServletOps.errorBadRequest("Parse error: "+ex.getMessage()) ; }
     }
+
+    /** Get the content type of an action or return the default.
+     * @param  action
+     * @return ContentType
+     */
+    public static ContentType getContentType(HttpAction action) {
+        return FusekiNetLib.getContentType(action.request) ;
+    }
 }
 

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_RW.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_RW.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_RW.java
index 859ef95..6cf210b 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_RW.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/REST_Quads_RW.java
@@ -18,7 +18,7 @@
 
 package org.apache.jena.fuseki.servlets ;
 
-import org.apache.jena.fuseki.FusekiLib ;
+import org.apache.jena.fuseki.system.FusekiNetLib;
 import org.apache.jena.fuseki.system.Upload;
 import org.apache.jena.fuseki.system.UploadDetails;
 import org.apache.jena.riot.RiotException ;
@@ -131,7 +131,7 @@ public class REST_Quads_RW extends REST_Quads_R {
             DatasetGraph dsg = decideDataset(action);
             if ( clearFirst )
                 dsg.clear() ;
-            FusekiLib.addDataInto(dsgTmp, dsg) ;
+            FusekiNetLib.addDataInto(dsgTmp, dsg) ;
             action.commit() ;
             ServletOps.success(action) ;
         } catch (Exception ex) {

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseDataset.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseDataset.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseDataset.java
index 99ed62c..9d86ee1 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseDataset.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseDataset.java
@@ -30,8 +30,8 @@ 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.fuseki.system.ConNeg;
+import org.apache.jena.fuseki.system.FusekiNetLib;
 import org.apache.jena.query.Dataset;
 import org.apache.jena.query.DatasetFactory ;
 import org.apache.jena.rdf.model.Model ;
@@ -93,7 +93,7 @@ public class ResponseDataset
         if ( mimeType == null )
         {
             Fuseki.actionLog.warn("Can't find MIME type for response") ;
-            String x = WebLib.getAccept(request) ;
+            String x = FusekiNetLib.getAccept(request) ;
             String msg ;
             if ( x == null )
                 msg = "No Accept: header" ;

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java
index 464f5b8..8771629 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ResponseResultSet.java
@@ -34,7 +34,7 @@ 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.fuseki.system.ConNeg;
 import org.apache.jena.query.QueryCancelledException ;
 import org.apache.jena.query.ResultSet ;
 import org.apache.jena.query.ResultSetFormatter ;

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_RW.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_RW.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_RW.java
index 2b4952f..afe0a31 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_RW.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_GSP_RW.java
@@ -24,8 +24,8 @@ import static org.apache.jena.riot.WebContent.matchContentType ;
 import org.apache.jena.atlas.web.ContentType ;
 import org.apache.jena.atlas.web.MediaType ;
 import org.apache.jena.fuseki.DEF ;
-import org.apache.jena.fuseki.FusekiLib ;
-import org.apache.jena.fuseki.conneg.ConNeg ;
+import org.apache.jena.fuseki.system.ConNeg;
+import org.apache.jena.fuseki.system.FusekiNetLib;
 import org.apache.jena.fuseki.system.Upload;
 import org.apache.jena.fuseki.system.UploadDetails;
 import org.apache.jena.fuseki.system.UploadDetails.PreState;
@@ -81,7 +81,7 @@ public class SPARQL_GSP_RW extends SPARQL_GSP_R
     protected void doPost(HttpAction action)        { doPutPost(action, false) ; }
 
     private void doPutPost(HttpAction action, boolean overwrite) {
-        ContentType ct = FusekiLib.getContentType(action) ;
+        ContentType ct = ActionLib.getContentType(action) ;
         if ( ct == null )
             ServletOps.errorBadRequest("No Content-Type:") ;
 
@@ -180,7 +180,7 @@ public class SPARQL_GSP_RW extends SPARQL_GSP_R
             existedBefore = target.exists() ; 
             if ( overwrite && existedBefore )
                 clearGraph(target) ;
-            FusekiLib.addDataInto(graphTmp, target.dsg, target.graphName) ;
+            FusekiNetLib.addDataInto(graphTmp, target.dsg, target.graphName) ;
             details.setExistedBefore(existedBefore) ;
             action.commit() ;
             return details ;

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/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 931f27f..6bee41d 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
@@ -49,7 +49,7 @@ import org.apache.jena.atlas.json.JsonObject;
 import org.apache.jena.atlas.web.ContentType ;
 import org.apache.jena.fuseki.Fuseki ;
 import org.apache.jena.fuseki.FusekiException ;
-import org.apache.jena.fuseki.FusekiLib ;
+import org.apache.jena.fuseki.system.FusekiNetLib;
 import org.apache.jena.query.* ;
 import org.apache.jena.rdf.model.Model ;
 import org.apache.jena.riot.web.HttpNames ;
@@ -159,7 +159,7 @@ public abstract class SPARQL_Query extends SPARQL_Protocol
      */
     protected void validateParams(HttpAction action, Collection<String> params) {
         HttpServletRequest request = action.request ;
-        ContentType ct = FusekiLib.getContentType(request) ;
+        ContentType ct = FusekiNetLib.getContentType(request) ;
         boolean mustHaveQueryParam = true ;
         if ( ct != null ) {
             String incoming = ct.getContentType() ;
@@ -218,7 +218,7 @@ public abstract class SPARQL_Query extends SPARQL_Protocol
             return ;
         }
 
-        ContentType ct = FusekiLib.getContentType(action) ;
+        ContentType ct = ActionLib.getContentType(action) ;
 
         // POST application/x-www-form-url
         // POST ?query= and no Content-Type

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/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 2b05907..cb327c8 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
@@ -48,7 +48,6 @@ import org.apache.jena.atlas.lib.Bytes ;
 import org.apache.jena.atlas.lib.StrUtils ;
 import org.apache.jena.atlas.web.ContentType ;
 import org.apache.jena.fuseki.Fuseki ;
-import org.apache.jena.fuseki.FusekiLib ;
 import org.apache.jena.graph.Node ;
 import org.apache.jena.graph.NodeFactory ;
 import org.apache.jena.iri.IRI ;
@@ -98,7 +97,7 @@ public class SPARQL_Update extends SPARQL_Protocol
 
     @Override
     protected void perform(HttpAction action) {
-        ContentType ct = FusekiLib.getContentType(action) ;
+        ContentType ct = ActionLib.getContentType(action) ;
         if ( ct == null )
             ct = ctSPARQLUpdate ;
 
@@ -127,7 +126,7 @@ public class SPARQL_Update extends SPARQL_Protocol
         if ( ! HttpNames.METHOD_POST.equalsIgnoreCase(request.getMethod()) )
             ServletOps.errorMethodNotAllowed("SPARQL Update : use POST") ;
 
-        ContentType ct = FusekiLib.getContentType(action) ;
+        ContentType ct = ActionLib.getContentType(action) ;
         if ( ct == null )
             ct = ctSPARQLUpdate ;
 

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/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 b87a7ce..2fc7d60 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
@@ -27,7 +27,7 @@ import javax.servlet.http.HttpServletResponse ;
 
 import org.apache.commons.fileupload.servlet.ServletFileUpload ;
 import org.apache.jena.fuseki.Fuseki ;
-import org.apache.jena.fuseki.FusekiLib ;
+import org.apache.jena.fuseki.system.FusekiNetLib;
 import org.apache.jena.fuseki.system.Upload;
 import org.apache.jena.fuseki.system.UploadDetailsWithName;
 import org.apache.jena.graph.Node ;
@@ -138,9 +138,9 @@ public class SPARQL_Upload extends ActionService
         action.beginWrite() ;
         try {
             if ( gn != null )
-                FusekiLib.addDataInto(dataTmp.getDefaultGraph(), action.getActiveDSG(), gn) ;
+                FusekiNetLib.addDataInto(dataTmp.getDefaultGraph(), action.getActiveDSG(), gn) ;
             else
-                FusekiLib.addDataInto(dataTmp, action.getActiveDSG()) ;
+                FusekiNetLib.addDataInto(dataTmp, action.getActiveDSG()) ;
 
             action.commit() ;
             return count ;

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceRouter.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceRouter.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceRouter.java
index 9a3a2b2..8ec9cd1 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceRouter.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceRouter.java
@@ -27,10 +27,10 @@ import org.apache.jena.atlas.web.AcceptList;
 import org.apache.jena.atlas.web.MediaType;
 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.DataService;
 import org.apache.jena.fuseki.server.Endpoint;
 import org.apache.jena.fuseki.server.Operation;
+import org.apache.jena.fuseki.system.ConNeg;
 import org.apache.jena.riot.web.HttpNames;
 
 /**

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/ConNeg.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/ConNeg.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/ConNeg.java
new file mode 100644
index 0000000..364a803
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/ConNeg.java
@@ -0,0 +1,206 @@
+/*
+ * 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.system;
+
+import static org.apache.jena.riot.web.HttpNames.hAcceptCharset ;
+
+import javax.servlet.http.HttpServletRequest ;
+
+import org.apache.jena.atlas.web.AcceptList ;
+import org.apache.jena.atlas.web.MediaRange ;
+import org.apache.jena.atlas.web.MediaType ;
+import org.slf4j.Logger ;
+import org.slf4j.LoggerFactory ;
+
+/**
+ * <p>Content negotiation is a mechanism defined in the HTTP specification
+ * that makes it possible to serve different versions of a document
+ * (or more generally, a resource representation) at the same URI, so that
+ * user agents can specify which version fit their capabilities the best.</p>
+ *
+ * <p>ConNeg is used in Fuseki to help matching the content media type requested
+ * by the user, against the list of offered media types.</p>
+ *
+ * @see <a href="http://en.wikipedia.org/wiki/Content_negotiation">http://en.wikipedia.org/wiki/Content_negotiation</a>
+ * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1">http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1</a>
+ */
+public class ConNeg
+{
+    // Logger
+    private static Logger log = LoggerFactory.getLogger(ConNeg.class) ;
+    // See riot.ContentNeg (client side).
+    // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
+
+    /**
+     * Parses the content type. It splits the string by semi-colon and finds the
+     * other features such as the "q" quality factor.  For a complete documentation
+     * on how the parsing happens, see
+     * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1">http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1</a>.
+     *
+     * @param contentType content type string
+     * @return parsed media type
+     */
+    static public MediaType parse(String contentType)
+    {
+        try {
+            return MediaType.create(contentType) ;
+        } catch (RuntimeException ex) { return null ; }
+    }
+
+    /**
+     * <p>Creates a {@link AcceptList} with the given HTTP header string and
+     * uses the {@link AcceptList#match(MediaType)} method to decide which
+     * media type matches the HTTP header string.</p>
+     *
+     * <p>The <em>q</em> quality factor is used to decide which choice is the best
+     * match.</p>
+     *
+     * @param headerString HTTP header string
+     * @param offerList accept list
+     * @return matched media type
+     */
+    static public MediaType match(String headerString, AcceptList offerList)
+    {
+        AcceptList l = new AcceptList(headerString) ;
+        return AcceptList.match(l, offerList) ;
+    }
+
+    /**
+     * Match a single media type against a header string.
+     *
+     * @param headerString HTTP header string
+     * @param mediaRangeStr Semi-colon separated list of media types
+     * @return the matched media type or <code>null</code> if there was no match
+     */
+    public static String match(String headerString, String mediaRangeStr)
+    {
+        AcceptList l = new AcceptList(headerString) ;
+        MediaRange aItem = new MediaRange(mediaRangeStr) ;  // MediaType
+        MediaType m = l.match(aItem) ;
+        if ( m == null )
+            return null ;
+        return m.toHeaderString() ;
+    }
+
+    /**
+     * Split and trims a string using a given regex.
+     *
+     * @param s string
+     * @param splitStr given regex
+     * @return an array with the trimmed strings found
+     */
+    /*package*/ static String[] split(String s, String splitStr)
+    {
+        String[] x = s.split(splitStr,2) ;
+        for ( int i = 0 ; i < x.length ; i++ )
+        {
+            x[i] = x[i].trim() ;
+        }
+        return x ;
+    }
+
+    /**
+     * <p>Chooses the charset by using the Accept-Charset HTTP header.</p>
+     *
+     * <p>See {@link ConNeg#choose(String, AcceptList, MediaType)}.</p>
+     *
+     * @param httpRequest HTTP request
+     * @param myPrefs accept list
+     * @param defaultMediaType default media type
+     * @return media type chosen
+     */
+    public static MediaType chooseCharset(HttpServletRequest httpRequest,
+                                          AcceptList myPrefs,
+                                          MediaType defaultMediaType)
+    {
+        String a = httpRequest.getHeader(hAcceptCharset) ;
+        if ( log.isDebugEnabled() )
+            log.debug("Accept-Charset request: "+a) ;
+        
+        MediaType item = choose(a, myPrefs, defaultMediaType) ;
+        
+        if ( log.isDebugEnabled() )
+            log.debug("Charset chosen: "+item) ;
+    
+        return item ;
+    }
+
+    /**
+     * <p>Choose the content media type by extracting the Accept HTTP header from
+     * the HTTP request and choosing
+     * (see {@link ConNeg#choose(String, AcceptList, MediaType)}) a content media
+     * type that matches the header.</p>
+     *
+     * @param httpRequest HTTP request
+     * @param myPrefs accept list
+     * @param defaultMediaType default media type
+     * @return media type chosen
+     */
+    public static MediaType chooseContentType(HttpServletRequest httpRequest,
+                                              AcceptList myPrefs,
+                                              MediaType defaultMediaType)
+    {
+        String a = FusekiNetLib.getAccept(httpRequest) ;
+        if ( log.isDebugEnabled() )
+            log.debug("Accept request: "+a) ;
+        
+        MediaType item = choose(a, myPrefs, defaultMediaType) ;
+    
+        if ( log.isDebugEnabled() )
+            log.debug("Content type chosen: "+item) ;
+    
+        return item ;
+    }
+
+    /**
+     * <p>This method receives a HTTP header string, an {@link AcceptList} and a
+     * default {@link MediaType}.</p>
+     *
+     * <p>If the header string is null, it returns the given default MediaType.</p>
+     *
+     * <p>Otherwise it builds an {@link AcceptList} object with the header string
+     * and uses it to match against the given MediaType.</p>
+     *
+     * @param headerString HTTP header string
+     * @param myPrefs accept list
+     * @param defaultMediaType default media type
+     * @return a media type or <code>null</code> if none matched or if the
+     *          HTTP header string and the default media type are <code>null</code>.
+     */
+    private static MediaType choose(String headerString, AcceptList myPrefs,
+                                    MediaType defaultMediaType)
+    {
+        if ( headerString == null )
+            return defaultMediaType ;
+        
+        AcceptList headerList = new AcceptList(headerString) ;
+        
+        if ( myPrefs == null )
+        {
+            MediaType i = headerList.first() ;
+            if ( i == null ) return defaultMediaType ;
+            return i ;
+        }
+    
+        MediaType i = AcceptList.match(headerList, myPrefs) ;
+        if ( i == null )
+            return defaultMediaType ;
+        return i ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/FusekiNetLib.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/FusekiNetLib.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/FusekiNetLib.java
new file mode 100644
index 0000000..114b0dd
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/FusekiNetLib.java
@@ -0,0 +1,179 @@
+/*
+ * 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.system;
+
+import java.util.Enumeration;
+import java.util.Iterator ;
+
+import javax.servlet.http.HttpServletRequest ;
+
+import org.apache.jena.atlas.web.ContentType ;
+import org.apache.jena.atlas.web.WebLib;
+import org.apache.jena.ext.com.google.common.collect.ArrayListMultimap;
+import org.apache.jena.ext.com.google.common.collect.Multimap;
+import org.apache.jena.fuseki.FusekiException;
+import org.apache.jena.fuseki.servlets.HttpAction ;
+import org.apache.jena.graph.Graph ;
+import org.apache.jena.graph.Node ;
+import org.apache.jena.graph.Triple ;
+import org.apache.jena.riot.Lang ;
+import org.apache.jena.riot.RDFLanguages ;
+import org.apache.jena.riot.web.HttpNames;
+import org.apache.jena.shared.PrefixMapping ;
+import org.apache.jena.sparql.core.DatasetGraph ;
+import org.apache.jena.sparql.core.Quad ;
+import org.apache.jena.sparql.util.Convert ;
+
+public class FusekiNetLib {
+    /** Get the content type of an action or return the default.
+     * @param  request
+     * @return ContentType
+     */
+    public static ContentType getContentType(HttpServletRequest request) {
+        String contentTypeHeader = request.getContentType() ;
+        if ( contentTypeHeader == null ) 
+            return null ;
+        return ContentType.create(contentTypeHeader) ;
+    }
+    
+    /** Get the incoming {@link Lang} based on Content-Type of an action.
+     * @param  action
+     * @param  dft Default if no "Content-Type:" found. 
+     * @return ContentType
+     */
+    public static Lang getLangFromAction(HttpAction action, Lang dft) {
+        String contentTypeHeader = action.request.getContentType() ;
+        if ( contentTypeHeader == null )
+            return dft ;
+        return RDFLanguages.contentTypeToLang(contentTypeHeader) ;
+    }
+    
+    public static String getAccept(HttpServletRequest httpRequest)
+    {
+        // There can be multiple accept headers -- note many tools don't allow these to be this way (e.g. wget, curl)
+        Enumeration<String> en = httpRequest.getHeaders(HttpNames.hAccept) ;
+        if ( ! en.hasMoreElements() )
+            return null ;
+        StringBuilder sb = new StringBuilder() ;
+        String sep = "" ;
+        for ( ; en.hasMoreElements() ; )
+        {
+            String x = en.nextElement() ;
+            sb.append(sep) ;
+            sep = ", " ;
+            sb.append(x) ;
+        }
+        return sb.toString() ;
+    }
+
+
+    /** Helper function for displayign an HttpServletRequest */
+    public static String fmtRequest(HttpServletRequest request) {
+        StringBuffer sbuff = new StringBuffer() ;
+        sbuff.append(request.getMethod()) ;
+        sbuff.append(" ") ;
+        sbuff.append(Convert.decWWWForm(request.getRequestURL())) ;
+
+        String qs = request.getQueryString() ;
+        if ( qs != null ) {
+            String tmp = request.getQueryString() ;
+            tmp = Convert.decWWWForm(tmp) ;
+            tmp = tmp.replace('\n', ' ') ;
+            tmp = tmp.replace('\r', ' ') ;
+            sbuff.append("?").append(tmp) ;
+        }
+        return sbuff.toString() ;
+    }
+
+    /** Parse the query string - do not process the body even for a form */
+    public static Multimap<String, String> parseQueryString(HttpServletRequest req) {
+        Multimap<String, String> map = ArrayListMultimap.create() ;
+
+        // Don't use ServletRequest.getParameter or getParamterNames
+        // as that reads form data. This code parses just the query string.
+        if ( req.getQueryString() != null ) {
+            String[] params = req.getQueryString().split("&") ;
+            for (int i = 0; i < params.length; i++) {
+                String p = params[i] ;
+                String[] x = p.split("=", 2) ;
+                String name = null ;
+                String value = null ;
+
+                if ( x.length == 0 ) { // No "="
+                    name = p ;
+                    value = "" ;
+                } else if ( x.length == 1 ) { // param=
+                    name = x[0] ;
+                    value = "" ;
+                } else { // param=value
+                    name = x[0] ;
+                    value = x[1] ;
+                }
+                map.put(name, value) ;
+            }
+        }
+        return map ;
+    }
+    
+    public static String safeParameter(HttpServletRequest request, String pName) {
+        String value = request.getParameter(pName) ;
+        if ( value == null )
+            return null ;
+        value = value.replace("\r", "") ;
+        value = value.replace("\n", "") ;
+        return value ;
+    }
+
+    // Do the addition directly on the dataset
+    public static void addDataInto(Graph data, DatasetGraph dsg, Node graphName) {
+        // Prefixes?
+        if ( graphName == null )
+            graphName = Quad.defaultGraphNodeGenerated ;
+
+        Iterator<Triple> iter = data.find(Node.ANY, Node.ANY, Node.ANY) ;
+        for (; iter.hasNext();) {
+            Triple t = iter.next() ;
+            dsg.add(graphName, t.getSubject(), t.getPredicate(), t.getObject()) ;
+        }
+
+        PrefixMapping pmapSrc = data.getPrefixMapping() ;
+        PrefixMapping pmapDest = dsg.getDefaultGraph().getPrefixMapping() ;
+        pmapDest.setNsPrefixes(pmapSrc) ;
+    }
+    
+    public static void addDataInto(DatasetGraph src, DatasetGraph dest) {
+        Iterator<Quad> iter = src.find(Node.ANY, Node.ANY, Node.ANY, Node.ANY) ;
+        for (; iter.hasNext();) {
+            Quad q = iter.next() ;
+            dest.add(q) ;
+        }
+
+        PrefixMapping pmapSrc = src.getDefaultGraph().getPrefixMapping() ;
+        PrefixMapping pmapDest = dest.getDefaultGraph().getPrefixMapping() ;
+        pmapDest.withDefaultMappings(pmapSrc) ;
+    }
+
+    public static int choosePort() {
+        try { 
+            return WebLib.choosePort();
+        } catch (RuntimeException ex) {
+            throw new FusekiException(ex.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/Upload.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/Upload.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/Upload.java
index 0624afc..a956ae4 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/Upload.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/Upload.java
@@ -33,7 +33,6 @@ import org.apache.commons.fileupload.servlet.ServletFileUpload ;
 import org.apache.commons.fileupload.util.Streams ;
 import org.apache.jena.atlas.io.IO ;
 import org.apache.jena.atlas.web.ContentType ;
-import org.apache.jena.fuseki.FusekiLib ;
 import org.apache.jena.fuseki.servlets.ActionErrorException;
 import org.apache.jena.fuseki.servlets.ActionLib;
 import org.apache.jena.fuseki.servlets.HttpAction;
@@ -56,7 +55,7 @@ public class Upload {
      *  This function is used by GSP.
      */ 
     public static UploadDetails incomingData(HttpAction action, StreamRDF dest) {
-        ContentType ct = FusekiLib.getContentType(action) ;
+        ContentType ct = ActionLib.getContentType(action) ;
         
         if ( ct == null ) {
             ServletOps.errorBadRequest("No content type") ;

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/validation/ValidatorBase.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/validation/ValidatorBase.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/validation/ValidatorBase.java
index 7601f69..542a5d2 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/validation/ValidatorBase.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/validation/ValidatorBase.java
@@ -35,11 +35,11 @@ import org.apache.jena.atlas.web.ContentType;
 import org.apache.jena.atlas.web.MediaType;
 import org.apache.jena.fuseki.DEF;
 import org.apache.jena.fuseki.Fuseki;
-import org.apache.jena.fuseki.conneg.ConNeg;
 import org.apache.jena.fuseki.servlets.ActionErrorException;
 import org.apache.jena.fuseki.servlets.ActionLib;
 import org.apache.jena.fuseki.servlets.ServletBase;
 import org.apache.jena.fuseki.servlets.ServletOps;
+import org.apache.jena.fuseki.system.ConNeg;
 import org.apache.jena.fuseki.validation.json.ValidationAction;
 import org.apache.jena.riot.web.HttpNames;
 import org.apache.jena.web.HttpSC;

http://git-wip-us.apache.org/repos/asf/jena/blob/0c218559/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/validation/html/DataValidatorHTML.java
----------------------------------------------------------------------
diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/validation/html/DataValidatorHTML.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/validation/html/DataValidatorHTML.java
index 8017dbe..235108b 100644
--- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/validation/html/DataValidatorHTML.java
+++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/validation/html/DataValidatorHTML.java
@@ -28,7 +28,7 @@ import javax.servlet.http.HttpServletRequest ;
 import javax.servlet.http.HttpServletResponse ;
 
 import org.apache.jena.atlas.io.IO ;
-import org.apache.jena.fuseki.FusekiLib ;
+import org.apache.jena.fuseki.system.FusekiNetLib;
 import org.apache.jena.riot.Lang;
 import org.apache.jena.riot.RDFLanguages;
 import org.apache.jena.riot.RDFParser;
@@ -54,7 +54,7 @@ public class DataValidatorHTML
         try {
 //            if ( log.isInfoEnabled() )
 //                log.info("data validation request") ;
-            String syntax = FusekiLib.safeParameter(httpRequest, paramSyntax) ;
+            String syntax = FusekiNetLib.safeParameter(httpRequest, paramSyntax) ;
             if ( syntax == null || syntax.equals("") )
                 syntax = RDFLanguages.NQUADS.getName() ;