http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiCmd.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiCmd.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiCmd.java
new file mode 100644
index 0000000..77bafe8
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiCmd.java
@@ -0,0 +1,508 @@
+/*
+ * 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 static org.apache.jena.fuseki.Fuseki.serverLog ;
+
+import java.io.File ;
+import java.io.InputStream ;
+import java.util.List ;
+
+import org.apache.jena.atlas.io.IO ;
+import org.apache.jena.atlas.lib.FileOps ;
+import org.apache.jena.atlas.lib.Lib ;
+import org.apache.jena.atlas.lib.StrUtils ;
+import org.apache.jena.atlas.logging.LogCtl ;
+import org.apache.jena.fuseki.mgt.ManagementServer ;
+import org.apache.jena.fuseki.server.FusekiConfig ;
+import org.apache.jena.fuseki.server.SPARQLServer ;
+import org.apache.jena.fuseki.server.ServerConfig ;
+import org.apache.jena.riot.Lang ;
+import org.apache.jena.riot.RDFDataMgr ;
+import org.apache.jena.riot.RDFLanguages ;
+import org.apache.jena.riot.SysRIOT ;
+import org.eclipse.jetty.server.Server ;
+import org.slf4j.Logger ;
+import arq.cmd.CmdException ;
+import arq.cmdline.ArgDecl ;
+import arq.cmdline.CmdARQ ;
+import arq.cmdline.ModDatasetAssembler ;
+
+import com.hp.hpl.jena.query.ARQ ;
+import com.hp.hpl.jena.query.Dataset ;
+import com.hp.hpl.jena.sparql.core.DatasetGraph ;
+import com.hp.hpl.jena.sparql.core.DatasetGraphFactory ;
+import com.hp.hpl.jena.tdb.TDB ;
+import com.hp.hpl.jena.tdb.TDBFactory ;
+import com.hp.hpl.jena.tdb.sys.Names ;
+import com.hp.hpl.jena.tdb.transaction.TransactionManager ;
+
+public class FusekiCmd extends CmdARQ
+{
+    private static String log4Jsetup = StrUtils.strjoinNL(
+          "## Plain output to stdout"
+          , "log4j.appender.jena.plain=org.apache.log4j.ConsoleAppender"
+          , "log4j.appender.jena.plain.target=System.out"
+          , "log4j.appender.jena.plain.layout=org.apache.log4j.PatternLayout"
+          , "log4j.appender.jena.plain.layout.ConversionPattern=%d{HH:mm:ss} 
%-5p %m%n"
+          
+          , "## Plain output with level, to stderr"
+          , "log4j.appender.jena.plainlevel=org.apache.log4j.ConsoleAppender"
+          , "log4j.appender.jena.plainlevel.target=System.err"
+          , 
"log4j.appender.jena.plainlevel.layout=org.apache.log4j.PatternLayout"
+          , 
"log4j.appender.jena.plainlevel.layout.ConversionPattern=%d{HH:mm:ss} %-5p %m%n"
+          
+          , "## Everything"
+          , "log4j.rootLogger=INFO, jena.plain"
+          , "log4j.logger.com.hp.hpl.jena=WARN"
+          , "log4j.logger.org.openjena=WARN"
+          , "log4j.logger.org.apache.jena=WARN"
+          
+          , "# Server log."
+          , "log4j.logger.org.apache.jena.fuseki.Server=INFO"
+          , "# Request log."
+          , "log4j.logger.org.apache.jena.fuseki.Fuseki=INFO"
+          , "log4j.logger.org.apache.jena.tdb.loader=INFO"
+          , "log4j.logger.org.eclipse.jetty=ERROR"
+          
+          , "## Parser output"
+          , "log4j.additivity."+SysRIOT.riotLoggerName+"=false"
+          , "log4j.logger."+SysRIOT.riotLoggerName+"=INFO, jena.plainlevel "
+        ) ;
+
+    
+    // Set logging.
+    // 1/ Use log4j.configuration is defined.
+    // 2/ Use file:log4j.properties 
+    // 3/ Use Built in.
+    
+    static void setLogging() {
+        // No loggers have been created but configuration may have been set 
up. 
+        String x = System.getProperty("log4j.configuration", null) ;
+        
+        if ( x != null && ! x.equals("set") ) {
+            // "set" indicates that CmdMain set logging.
+            // Use standard log4j initialization.
+            return ;
+        }
+        
+        String fn = "log4j.properties" ;
+        File f = new File(fn) ;
+        if ( f.exists() ) {
+            // Use file log4j.properties
+            System.setProperty("log4j.configuration", "file:"+fn) ;
+            return ;
+        }
+        // Use built-in for Fuseki.
+        LogCtl.resetLogging(log4Jsetup) ;     
+    }
+    
+    static { setLogging() ; }
+
+    // Arguments:
+    // --update
+    
+    // Specific switches:
+    
+    // --admin=on/off
+    
+    // --http-update
+    // --http-get
+    
+    // --sparql-query
+    // --sparql-update
+    
+    // pages/validators/
+    // pages/control/
+    // pages/query/ or /pages/sparql/
+    
+    private static ArgDecl argMgtPort       = new ArgDecl(ArgDecl.HasValue, 
"mgtPort", "mgtport") ;
+    private static ArgDecl argMem           = new ArgDecl(ArgDecl.NoValue,  
"mem") ;
+    private static ArgDecl argAllowUpdate   = new ArgDecl(ArgDecl.NoValue,  
"update", "allowUpdate") ;
+    private static ArgDecl argFile          = new ArgDecl(ArgDecl.HasValue, 
"file") ;
+    private static ArgDecl argMemTDB        = new ArgDecl(ArgDecl.NoValue,  
"memtdb", "memTDB") ;
+    private static ArgDecl argTDB           = new ArgDecl(ArgDecl.HasValue, 
"loc", "location") ;
+    private static ArgDecl argPort          = new ArgDecl(ArgDecl.HasValue, 
"port") ;
+    private static ArgDecl argLocalhost     = new ArgDecl(ArgDecl.NoValue, 
"localhost", "local") ;
+    private static ArgDecl argTimeout       = new ArgDecl(ArgDecl.HasValue, 
"timeout") ;
+    private static ArgDecl argFusekiConfig  = new ArgDecl(ArgDecl.HasValue, 
"config", "conf") ;
+    private static ArgDecl argJettyConfig   = new ArgDecl(ArgDecl.HasValue, 
"jetty-config") ;
+    private static ArgDecl argGZip          = new ArgDecl(ArgDecl.HasValue, 
"gzip") ;
+    private static ArgDecl argUber          = new ArgDecl(ArgDecl.NoValue,  
"uber", "über") ;   // Use the überservlet (experimental)
+    private static ArgDecl argBasicAuth     = new ArgDecl(ArgDecl.HasValue, 
"basic-auth") ;
+    
+    private static ArgDecl argGSP           = new ArgDecl(ArgDecl.NoValue,  
"gsp") ;    // GSP compliance mode
+    
+    private static ArgDecl argHome          = new ArgDecl(ArgDecl.HasValue, 
"home") ;
+    private static ArgDecl argPages         = new ArgDecl(ArgDecl.HasValue, 
"pages") ;
+    
+    //private static ModLocation          modLocation =  new ModLocation() ;
+    private static ModDatasetAssembler  modDataset = new ModDatasetAssembler() 
;
+    
+    // fuseki [--mem|--desc assembler.ttl] [--port PORT] **** /datasetURI
+
+    static public void main(String...argv)
+    {
+        // Just to make sure ...
+        ARQ.init() ;
+        TDB.init() ;
+        Fuseki.init() ;
+        new FusekiCmd(argv).mainRun() ;
+    }
+    
+    private int port                    = 3030 ;
+    private int mgtPort                 = -1 ;
+    private boolean listenLocal         = false ;
+
+    private DatasetGraph dsg            = null ; 
+    private String datasetPath          = null ;
+    private boolean allowUpdate         = false ;
+    
+    private String fusekiConfigFile     = null ;
+    private boolean enableCompression   = true ;
+    private String jettyConfigFile      = null ;
+    private String authConfigFile       = null ;
+    private String homeDir              = null ;
+    private String pagesDir             = null ;
+    
+    public FusekiCmd(String...argv)
+    {
+        super(argv) ;
+        
+        if ( false )
+            // Consider ...
+            TransactionManager.QueueBatchSize =  
TransactionManager.QueueBatchSize / 2 ;
+        
+        getUsage().startCategory("Fuseki") ;
+        addModule(modDataset) ;
+        add(argMem,     "--mem",                "Create an in-memory, 
non-persistent dataset for the server") ;
+        add(argFile,    "--file=FILE",          "Create an in-memory, 
non-persistent dataset for the server, initialised with the contents of the 
file") ;
+        add(argTDB,     "--loc=DIR",            "Use an existing TDB database 
(or create if does not exist)") ;
+        add(argMemTDB,  "--memTDB",             "Create an in-memory, 
non-persistent dataset using TDB (testing only)") ;
+        add(argPort,    "--port",               "Listen on this port number") ;
+        add(argPages,   "--pages=DIR",          "Set of pages to serve as 
static content") ; 
+        // Set via jetty config file.
+        add(argLocalhost,   "--localhost",      "Listen only on the localhost 
interface") ;
+        add(argTimeout, "--timeout=",           "Global timeout applied to 
queries (value in ms) -- format is X[,Y] ") ;
+        add(argAllowUpdate, "--update",         "Allow updates (via SPARQL 
Update and SPARQL HTTP Update)") ;
+        add(argFusekiConfig, "--config=",       "Use a configuration file to 
determine the services") ;
+        add(argJettyConfig, "--jetty-config=FILE",  "Set up the server (not 
services) with a Jetty XML file") ;
+        add(argBasicAuth, "--basic-auth=FILE",  "Configure basic auth using 
provided Jetty realm file, ignored if --jetty-config is used") ;
+        add(argMgtPort, "--mgtPort=port",       "Enable the management 
commands on the given port") ; 
+        add(argHome, "--home=DIR",              "Root of Fuseki installation 
(overrides environment variable FUSEKI_HOME)") ; 
+        add(argGZip, "--gzip=on|off",           "Enable GZip compression (HTTP 
Accept-Encoding) if request header set") ;
+        
+        add(argUber) ;
+        //add(argGSP) ;
+        
+        super.modVersion.addClass(TDB.class) ;
+        super.modVersion.addClass(Fuseki.class) ;
+    }
+
+    static String argUsage = "[--config=FILE] 
[--mem|--desc=AssemblerFile|--file=FILE] [--port PORT] /DatasetPathName" ; 
+    
+    @Override
+    protected String getSummary()
+    {
+        return getCommandName()+" "+argUsage ;
+    }
+
+    @Override
+    protected void processModulesAndArgs()
+    {
+        int x = 0 ;
+        
+        Logger log = Fuseki.serverLog ;
+        
+        if ( contains(argFusekiConfig) )
+            fusekiConfigFile = getValue(argFusekiConfig) ;
+        
+        ArgDecl assemblerDescDecl = new ArgDecl(ArgDecl.HasValue, "desc", 
"dataset") ;
+        if ( contains(argMem) ) x++ ; 
+        if ( contains(argFile) ) x++ ;
+        if ( contains(assemblerDescDecl) ) x++ ;
+        if ( contains(argTDB) ) x++ ;
+        if ( contains(argMemTDB) ) x++ ;
+
+        if ( fusekiConfigFile != null )
+        {
+            if ( x >= 1 )
+                throw new CmdException("Dataset specified on the command line 
but a configuration file also given.") ;
+        }
+        else
+        {
+            if ( x != 1 )
+                throw new CmdException("Required: either --config=FILE or one 
of --mem, --file, --loc or --desc") ;
+        }
+        
+        // One of:
+        // argMem, argFile, argMemTDB, argTDB, 
+        
+        
+        if ( contains(argMem) )
+        {
+            log.info("Dataset: in-memory") ;
+            dsg = DatasetGraphFactory.createMem() ;
+        }
+        if ( contains(argFile) )
+        {
+            dsg = DatasetGraphFactory.createMem() ;
+            // replace by RiotLoader after ARQ refresh.
+            String filename = getValue(argFile) ;
+            log.info("Dataset: in-memory: load file: "+filename) ;
+            if ( ! FileOps.exists(filename) )
+                throw new CmdException("File not found: "+filename) ;
+
+            Lang language = RDFLanguages.filenameToLang(filename) ;
+            if ( language == null )
+                throw new CmdException("Can't guess language for file: 
"+filename) ;
+            InputStream input = IO.openFile(filename) ; 
+            
+            if ( RDFLanguages.isQuads(language) )
+                RDFDataMgr.read(dsg, filename) ;
+            else
+                RDFDataMgr.read(dsg.getDefaultGraph(), filename) ;
+        }
+        
+        if ( contains(argMemTDB) )
+        {
+            log.info("TDB dataset: in-memory") ;
+            dsg = TDBFactory.createDatasetGraph() ;
+        }
+        
+        if ( contains(argTDB) )
+        {
+            String dir = getValue(argTDB) ;
+            
+            if ( Lib.equal(dir, Names.memName) ) {
+                log.info("TDB dataset: in-memory") ;
+            } else {
+                if ( ! FileOps.exists(dir) )
+                    throw new CmdException("Directory not found: "+dir) ;
+                log.info("TDB dataset: directory="+dir) ;
+            }
+            dsg = TDBFactory.createDatasetGraph(dir) ;
+        }
+        
+        // Otherwise
+        if ( contains(assemblerDescDecl) )
+        {
+            log.info("Dataset from assembler") ;
+            Dataset ds = modDataset.createDataset() ;
+            if ( ds != null )
+                dsg = ds.asDatasetGraph() ;
+        }
+        
+        if ( contains(argFusekiConfig) )
+        {
+            if ( dsg != null )
+                throw new CmdException("(internal error) Dataset specificed on 
the command line but a a configuration file also given.") ;
+            fusekiConfigFile = getValue(argFusekiConfig) ;
+        }
+        
+        if ( contains(argPort) )
+        {
+            String portStr = getValue(argPort) ;
+            try {
+                port = Integer.parseInt(portStr) ;
+            } catch (NumberFormatException ex)
+            {
+                throw new CmdException(argPort.getKeyName()+" : bad port 
number: "+portStr) ;
+            }
+        }
+        
+        if ( contains(argMgtPort) )
+        {
+            String mgtPortStr = getValue(argMgtPort) ;
+            try {
+                mgtPort = Integer.parseInt(mgtPortStr) ;
+            } catch (NumberFormatException ex)
+            {
+                throw new CmdException(argMgtPort.getKeyName()+" : bad port 
number: "+mgtPortStr) ;
+            }
+        }
+
+        if ( contains(argLocalhost) )
+            listenLocal = true ;
+            
+        if ( fusekiConfigFile == null && dsg == null )
+            throw new CmdException("No dataset defined and no configuration 
file: "+argUsage) ;
+        
+        if ( dsg != null )
+        {
+            if ( getPositional().size() == 0 )
+                throw new CmdException("No dataset path name given") ;
+            if ( getPositional().size() > 1  )
+                throw new CmdException("Multiple dataset path names given") ;
+            datasetPath = getPositionalArg(0) ;
+            if ( datasetPath.length() > 0 && ! datasetPath.startsWith("/") )
+                throw new CmdException("Dataset path name must begin with a /: 
"+datasetPath) ;
+            
+            allowUpdate = contains(argAllowUpdate) ;
+        }
+        
+        if ( contains(argTimeout) )
+        {
+            String str = getValue(argTimeout) ;
+            ARQ.getContext().set(ARQ.queryTimeout, str) ;
+        }
+        
+        if ( contains(argJettyConfig) )
+        {
+            jettyConfigFile = getValue(argJettyConfig) ;
+            if ( !FileOps.exists(jettyConfigFile) )
+                throw new CmdException("No such file: "+jettyConfigFile) ;
+        }
+        
+        if ( contains(argBasicAuth) )
+        {
+            authConfigFile = getValue(argBasicAuth) ;
+            if ( !FileOps.exists(authConfigFile) )
+                throw new CmdException("No such file: " + authConfigFile) ;
+        }
+        
+        if ( contains(argHome) )
+        {
+           List<String> args = super.getValues(argHome) ;
+           homeDir = args.get(args.size()-1) ;
+        }
+        
+        if ( contains(argPages) )
+        {
+           List<String> args = super.getValues(argPages) ;
+           pagesDir = args.get(args.size()-1) ;
+        }
+
+        if ( contains(argGZip) )
+        {
+            if ( ! hasValueOfTrue(argGZip) && ! hasValueOfFalse(argGZip) )
+                throw new CmdException(argGZip.getNames().get(0)+": Not 
understood: "+getValue(argGZip)) ;
+            enableCompression = super.hasValueOfTrue(argGZip) ;
+        }
+        
+        if ( contains(argUber) )
+            SPARQLServer.überServlet = true ;
+        
+        if ( contains(argGSP) )
+        {
+            SPARQLServer.überServlet = true ;
+            Fuseki.graphStoreProtocolPostCreate = true ;
+        }
+
+    }
+
+    private static String sort_out_dir(String path)
+    {
+        path.replace('\\', '/') ;
+        if ( ! path.endsWith("/"))
+            path = path +"/" ;
+        return path ;
+    }
+    
+    @Override
+    protected void exec()
+    {
+        if ( homeDir == null )
+        {
+            if ( System.getenv(Fuseki.FusekiHomeEnv) != null )
+                 homeDir = System.getenv(Fuseki.FusekiHomeEnv) ;
+            else
+                 homeDir = "." ;
+        }
+        
+        homeDir = sort_out_dir(homeDir) ;
+        Fuseki.configLog.info("Home Directory: " + 
FileOps.fullDirectoryPath(homeDir));
+        if ( ! FileOps.exists(homeDir) )
+            Fuseki.configLog.warn("No such directory for Fuseki home: 
"+homeDir) ;
+        
+        String staticContentDir = pagesDir ;
+        if ( staticContentDir == null )
+            staticContentDir = homeDir+Fuseki.PagesStatic ;
+        
+        Fuseki.configLog.debug("Static Content Directory: "+ 
FileOps.fullDirectoryPath(staticContentDir)) ;
+
+        if ( ! FileOps.exists(staticContentDir) ) {
+            Fuseki.configLog.warn("No such directory for static content: " + 
FileOps.fullDirectoryPath(staticContentDir)) ;
+            Fuseki.configLog.warn("You may need to set the --pages or --home 
option to configure static content correctly");
+        }
+        
+        if ( jettyConfigFile != null )
+            Fuseki.configLog.info("Jetty configuration: "+jettyConfigFile) ;
+        
+        ServerConfig serverConfig ;
+        
+        if ( fusekiConfigFile != null )
+        {
+            Fuseki.configLog.info("Configuration file: "+fusekiConfigFile) ;
+            serverConfig = FusekiConfig.configure(fusekiConfigFile) ;
+        }
+        else 
+        {
+            serverConfig = FusekiConfig.defaultConfiguration(datasetPath, dsg, 
allowUpdate, listenLocal) ;
+            if ( ! allowUpdate )
+                Fuseki.serverLog.info("Running in read-only mode.");
+        }
+        
+        // TODO Get from parsing config file.
+        serverConfig.port = port ;
+        serverConfig.pages = staticContentDir ;
+        serverConfig.mgtPort = mgtPort ;
+        serverConfig.pagesPort = port ;
+        serverConfig.loopback = listenLocal ;
+        serverConfig.enableCompression = enableCompression ;
+        serverConfig.jettyConfigFile = jettyConfigFile ;
+        serverConfig.authConfigFile = authConfigFile ;
+        serverConfig.verboseLogging = ( super.isVerbose() || super.isDebug() ) 
;
+        
+        SPARQLServer server = new SPARQLServer(serverConfig) ;
+        
+        // Temporary
+        Fuseki.setServer(server) ;
+        
+        Server mgtServer = null ;
+        
+        if ( mgtPort > 0 )
+        {
+            Fuseki.configLog.info("Management services on port "+mgtPort) ;
+            mgtServer = ManagementServer.createManagementServer(mgtPort) ;
+            try { mgtServer.start() ; }
+            catch (java.net.BindException ex)
+            { serverLog.error("SPARQLServer: Failed to start management 
server: " + ex.getMessage()) ; System.exit(1) ; }
+            catch (Exception ex)
+            { serverLog.error("SPARQLServer: Failed to start management 
server: " + ex.getMessage(), ex) ; System.exit(1) ; }
+        }
+
+        server.start() ;
+        try { server.getServer().join() ; } catch (Exception ex) {}
+
+        if ( mgtServer != null )
+        {
+            try { mgtServer.stop() ; } 
+            catch (Exception e) { serverLog.warn("Failed to cleanly stop the 
management server", e) ; }
+        }
+        System.exit(0) ;
+    }
+    
+
+    @Override
+    protected String getCommandName()
+    {
+        return "fuseki" ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiConfigException.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiConfigException.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiConfigException.java
new file mode 100644
index 0000000..5e1b018
--- /dev/null
+++ 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiConfigException.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+
+public class FusekiConfigException extends FusekiException
+{
+    public FusekiConfigException(String msg, Throwable cause)    { super(msg, 
cause) ; }
+    public FusekiConfigException(String msg)                     { super(msg) 
; }
+    public FusekiConfigException(Throwable cause)                { 
super(cause) ; }
+    public FusekiConfigException()                               { super() ; }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiException.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiException.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiException.java
new file mode 100644
index 0000000..04953ce
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiException.java
@@ -0,0 +1,29 @@
+/*
+ * 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 com.hp.hpl.jena.sparql.ARQException ;
+
+public class FusekiException extends ARQException
+{
+    public FusekiException(String msg, Throwable cause)    { super(msg, cause) 
; }
+    public FusekiException(String msg)                     { super(msg) ; }
+    public FusekiException(Throwable cause)                { super(cause) ; }
+    public FusekiException()                               { super() ; }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiLib.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiLib.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiLib.java
new file mode 100644
index 0000000..5324793
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiLib.java
@@ -0,0 +1,148 @@
+/*
+ * 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.util.Iterator ;
+
+import javax.servlet.http.HttpServletRequest ;
+
+import org.apache.commons.lang.StringUtils ;
+import org.apache.jena.atlas.lib.MultiMap ;
+import org.apache.jena.atlas.lib.MultiMapToList ;
+import org.apache.jena.atlas.web.ContentType ;
+import org.apache.jena.fuseki.servlets.HttpAction ;
+import org.apache.jena.riot.Lang ;
+import org.apache.jena.riot.RDFLanguages ;
+
+import com.hp.hpl.jena.graph.Graph ;
+import com.hp.hpl.jena.graph.Node ;
+import com.hp.hpl.jena.graph.Triple ;
+import com.hp.hpl.jena.shared.PrefixMapping ;
+import com.hp.hpl.jena.sparql.core.DatasetGraph ;
+import com.hp.hpl.jena.sparql.core.Quad ;
+import com.hp.hpl.jena.sparql.util.Convert ;
+
+public class FusekiLib {
+    /** 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 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) {
+        StringBuilder sbuff = new StringBuilder() ;
+        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 = MultiMapToList.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 ( String p : params )
+            {
+                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) ;
+        value = StringUtils.replaceChars(value, "\r", "") ;
+        value = StringUtils.replaceChars(value, "\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) ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiNotFoundException.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiNotFoundException.java
 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiNotFoundException.java
new file mode 100644
index 0000000..be9be90
--- /dev/null
+++ 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiNotFoundException.java
@@ -0,0 +1,26 @@
+/*
+ * 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 org.apache.jena.web.HttpSC ;
+
+public class FusekiNotFoundException extends FusekiRequestException
+{
+    public FusekiNotFoundException(String msg)    { 
super(HttpSC.NOT_FOUND_404, msg) ; }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiRequestException.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiRequestException.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiRequestException.java
new file mode 100644
index 0000000..e197be2
--- /dev/null
+++ 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/FusekiRequestException.java
@@ -0,0 +1,57 @@
+/*
+ * 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 org.apache.jena.web.HttpSC ;
+
+
+public class FusekiRequestException extends FusekiException
+{
+    public static FusekiRequestException create(int code, String msg)
+    {
+        if ( code == HttpSC.NOT_FOUND_404 )
+            return new FusekiNotFoundException(msg) ;
+        return new FusekiRequestException(code, msg) ;
+    }
+    
+    private final int statusCode ;
+    private final String responseMessage ;
+    protected FusekiRequestException(int code, String msg)
+    {
+        super(msg) ;
+        this.statusCode = code ;
+        responseMessage = msg ;
+    }
+    
+    public int getStatusCode()
+    {
+        return statusCode ;
+    }
+
+    public String getResponseMessage()
+    {
+        return responseMessage ;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "HTTP: "+statusCode+" "+getMessage() ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/HttpNames.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/HttpNames.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/HttpNames.java
new file mode 100644
index 0000000..65d73c7
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/HttpNames.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki;
+
+public class HttpNames
+{
+    // Request
+    public static final String hAccept              = "Accept" ;
+    public static final String hAcceptEncoding      = "Accept-Encoding" ;
+    public static final String hAcceptCharset       = "Accept-Charset" ;
+    //public static final String hAcceptLanguage      = "Accept-Language" ;
+
+    // Response
+    public static final String xhAcceptRanges        = "Accept-Ranges" ;
+    public static final String hAllow               = "Allow" ;
+    public static final String hContentEncoding     = "Content-Encoding" ;
+    public static final String hContentLengh        = "Content-Length" ;
+    public static final String hContentLocation     = "Content-Location" ;
+    public static final String hContentRange        = "Content-Range" ;
+    public static final String hContentType         = "Content-Type" ;
+    public static final String hRetryAfter          = "Retry-After" ;
+    public static final String hServer              = "Server" ;
+    public static final String hLocation            = "Location" ; 
+    public static final String hVary                = "Vary" ;
+    public static final String charset              = "charset" ;
+    
+    // CORS: 
+    //   http://www.w3.org/TR/cors/  http://esw.w3.org/CORS_Enabled
+    public static final String hAccessControlAllowOrigin  = 
"Access-Control-Allow-Origin" ;
+    public static final String hAccessControlAllowHeaders = 
"Access-Control-Allow-Headers" ;
+    
+    // Fuseki parameter names 
+    public static final String paramGraph           = "graph" ;
+    public static final String paramGraphDefault    = "default" ;
+
+    public static final String paramQuery           = "query" ;
+    public static final String paramQueryRef        = "query-ref" ;
+    public static final String paramDefaultGraphURI = "default-graph-uri" ;
+    public static final String paramNamedGraphURI   = "named-graph-uri" ;
+    
+    public static final String paramStyleSheet      = "stylesheet" ;
+    public static final String paramAccept          = "accept" ;
+    public static final String paramOutput1         = "output" ;        // See 
Yahoo! developer: http://developer.yahoo.net/common/json.html 
+    public static final String paramOutput2         = "format" ;        // 
Alternative name 
+    public static final String paramCallback        = "callback" ;
+    public static final String paramForceAccept     = "force-accept" ;  // 
Force the accept header at the last moment
+    public static final String paramTimeout         = "timeout" ;
+    
+    public static final String paramUpdate          = "update" ;
+    public static final String paramRequest         = "request" ; 
+    public static final String paramUsingGraphURI        = "using-graph-uri" ;
+    public static final String paramUsingNamedGraphURI   = 
"using-named-graph-uri" ;
+    
+    public static final String METHOD_DELETE        = "DELETE";
+    public static final String METHOD_HEAD          = "HEAD";
+    public static final String METHOD_GET           = "GET";
+    public static final String METHOD_OPTIONS       = "OPTIONS";
+    public static final String METHOD_PATCH         = "PATCH" ;
+    public static final String METHOD_POST          = "POST";
+    public static final String METHOD_PUT           = "PUT";
+    public static final String METHOD_TRACE         = "TRACE";
+
+    public static final String HEADER_IFMODSINCE    = "If-Modified-Since";
+    public static final String HEADER_LASTMOD       = "Last-Modified";
+    
+    // Names for services in the default configuration
+    public static final String ServiceQuery         = "query" ;
+    public static final String ServiceQueryAlt      = "sparql" ;
+    public static final String ServiceUpdate        = "update" ;
+    public static final String ServiceData          = "data" ;
+    public static final String ServiceUpload        = "upload" ;
+    public static final String ServiceGeneralQuery  = "/sparql" ;
+    
+    // Posisble values of fields.
+    // TODO Pull in from results writer.
+    public static final String valueDefault    = "default" ;
+    
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/Test.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/Test.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/Test.java
new file mode 100644
index 0000000..b4f5fed
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/Test.java
@@ -0,0 +1,25 @@
+/*
+ * 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;
+
+public class Test
+{
+    public static void init() { System.out.println("INIT called") ; }
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/conneg/ConNeg.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/conneg/ConNeg.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/conneg/ConNeg.java
new file mode 100644
index 0000000..b448c6c
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/conneg/ConNeg.java
@@ -0,0 +1,205 @@
+/*
+ * 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.fuseki.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
+{
+    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/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/conneg/WebLib.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/conneg/WebLib.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/conneg/WebLib.java
new file mode 100644
index 0000000..fdeb139
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/conneg/WebLib.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki.conneg;
+
+import java.util.Enumeration ;
+
+import javax.servlet.http.HttpServletRequest ;
+
+import org.apache.jena.fuseki.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/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/ActionBackup.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/ActionBackup.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/ActionBackup.java
new file mode 100644
index 0000000..c36e8be
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/ActionBackup.java
@@ -0,0 +1,196 @@
+/**
+ * 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.mgt ;
+
+import static java.lang.String.format ;
+
+import java.io.* ;
+import java.util.concurrent.Callable ;
+import java.util.concurrent.ExecutorService ;
+import java.util.concurrent.Executors ;
+import java.util.zip.GZIPOutputStream ;
+
+import javax.servlet.http.HttpServletRequest ;
+import javax.servlet.http.HttpServletResponse ;
+
+import org.apache.jena.atlas.io.IO ;
+import org.apache.jena.atlas.lib.FileOps ;
+import org.apache.jena.atlas.logging.Log ;
+import org.apache.jena.fuseki.FusekiException ;
+import org.apache.jena.fuseki.FusekiLib ;
+import org.apache.jena.fuseki.server.DatasetRef ;
+import org.apache.jena.fuseki.server.DatasetRegistry ;
+import org.apache.jena.fuseki.servlets.HttpAction ;
+import org.apache.jena.fuseki.servlets.ServletBase ;
+import org.apache.jena.riot.Lang ;
+import org.apache.jena.riot.RDFDataMgr ;
+import org.apache.jena.web.HttpSC ;
+
+import com.hp.hpl.jena.sparql.core.DatasetGraph ;
+import com.hp.hpl.jena.sparql.util.Utils ;
+
+public class ActionBackup extends ServletBase
+{
+    public ActionBackup() { super() ; }
+
+    // Limit to one backup at a time.
+    public static final ExecutorService backupService = 
Executors.newFixedThreadPool(1) ;
+    
+    @Override
+    protected void doPost(HttpServletRequest request, HttpServletResponse 
response) throws IOException
+    {
+        String dataset = FusekiLib.safeParameter(request, "dataset") ;
+        if ( dataset == null )
+        {
+            response.sendError(HttpSC.BAD_REQUEST_400, "Required parameter 
missing: ?dataset=") ;
+            return ;
+        }
+        
+        if ( ! dataset.startsWith("/") )
+            dataset="/"+dataset ;
+        
+        // HttpSession session = request.getSession(true) ;
+        // session.setAttribute("dataset", dataset) ;
+        // session.setMaxInactiveInterval(15*60) ; // 10 mins
+
+        boolean known = DatasetRegistry.get().isRegistered(dataset) ;
+        if (!known)
+        {
+            response.sendError(HttpSC.BAD_REQUEST_400, "No such dataset: " + 
dataset) ;
+            return ;
+        }
+        
+        long id = allocRequestId(request, response);
+        HttpAction action = new HttpAction(id, request, response, false) ;
+        DatasetRef ref = DatasetRegistry.get().get(dataset) ;
+        action.setDataset(ref);
+        scheduleBackup(action) ;
+    }
+
+    static final String BackupArea = "backups" ;  
+    
+    private void scheduleBackup(final HttpAction action)
+    {
+        String dsName = action.dsRef.name ;
+        final String ds = dsName.startsWith("/")? dsName : "/"+dsName ;
+        
+        String timestamp = Utils.nowAsString("yyyy-MM-dd_HH-mm-ss") ;
+        final String filename = BackupArea + ds + "_" + timestamp ;
+        FileOps.ensureDir(BackupArea) ;
+        
+        try {
+            final Callable<Boolean> task = new Callable<Boolean>() {
+                @Override
+                public Boolean call() throws Exception
+                {
+                    log.info(format("[%d] Start backup %s to '%s'", action.id, 
ds, filename)) ;
+                    action.beginRead() ;
+                    try {
+                        backup(action.getActiveDSG(), filename) ;
+                        log.info(format("[%d] Finish backup %s to '%s'", 
action.id, ds, filename)) ;
+                    }
+                    catch ( RuntimeException ex )
+                    {
+                        log.info(format("[%d] Exception during backup: ", 
action.id, ex.getMessage()), ex) ;
+                        return Boolean.FALSE ;
+                    }
+                    finally {
+                        action.endRead() ;
+                    }
+                    return Boolean.TRUE ;
+                }} ;
+            
+            log.info(format("[%d] Schedule backup %s to '%s'", action.id, ds, 
filename)) ;                
+            backupService.submit(task) ;
+        } 
+        //catch (FusekiException ex)
+        catch (RuntimeException ex)
+        {
+            log.warn("Unanticipated exception", ex) ;
+            try { action.response.sendError(HttpSC.INTERNAL_SERVER_ERROR_500, 
ex.getMessage()) ; }
+            catch (IOException e) { IO.exception(e) ; }
+            return ;            
+        }
+        
+        successPage(action, "Backup scheduled - see server log for details") ;
+    }
+    
+    // Share with new ServletBase.
+    protected static void successPage(HttpAction action, String message)
+    {
+        try {
+            action.response.setContentType("text/html");
+            action.response.setStatus(HttpSC.OK_200);
+            PrintWriter out = action.response.getWriter() ;
+            out.println("<html>") ;
+            out.println("<head>") ;
+            out.println("</head>") ;
+            out.println("<body>") ;
+            out.println("<h1>Success</h1>");
+            if ( message != null )
+            {
+                out.println("<p>") ;
+                out.println(message) ;
+                out.println("</p>") ;
+            }
+            out.println("</body>") ;
+            out.println("</html>") ;
+            out.flush() ;
+        } catch (IOException ex) { IO.exception(ex) ; }
+    }
+    
+    public static void backup(DatasetGraph dsg, String backupfile)
+    {
+        if ( ! backupfile.endsWith(".nq") )
+            backupfile = backupfile+".nq" ;
+        
+        OutputStream out = null ;
+        try
+        {
+            if ( true )
+            {
+                // This seems to achive about the same as "gzip -6"
+                // It's not too expensive in elapsed time but it's not zero 
cost.
+                // GZip, large buffer.
+                out = new FileOutputStream(backupfile+".gz") ;
+                out = new GZIPOutputStream(out, 8*1024) ;
+                out = new BufferedOutputStream(out) ;
+            }
+            else
+            {
+                out = new FileOutputStream(backupfile) ;
+                out = new BufferedOutputStream(out) ;
+            }
+            
+            RDFDataMgr.write(out, dsg,Lang.NQUADS) ;
+            out.close() ;
+            out = null ;
+        } 
+        catch (FileNotFoundException e)
+        {
+            Log.warn(ActionBackup.class, "File not found: "+backupfile) ;
+            throw new FusekiException("File not found: "+backupfile) ;
+        } 
+        catch (IOException e) { IO.exception(e) ; }
+        finally {
+            try { if (out != null) out.close() ; }
+            catch (IOException e) { /* ignore */ }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/ActionDataset.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/ActionDataset.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/ActionDataset.java
new file mode 100644
index 0000000..fc3d395
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/ActionDataset.java
@@ -0,0 +1,121 @@
+/*
+ * 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.mgt;
+
+import java.io.IOException ;
+import java.io.UnsupportedEncodingException ;
+
+import javax.servlet.ServletOutputStream ;
+import javax.servlet.http.HttpServlet ;
+import javax.servlet.http.HttpServletRequest ;
+import javax.servlet.http.HttpServletResponse ;
+import javax.servlet.http.HttpSession ;
+
+import org.apache.commons.codec.binary.Base64 ;
+import org.apache.jena.fuseki.FusekiLib ;
+import org.apache.jena.fuseki.HttpNames ;
+import org.apache.jena.fuseki.server.DatasetRegistry ;
+import org.apache.jena.web.HttpSC ;
+
+/** Log-in and choose dataset */
+public class ActionDataset extends HttpServlet
+{
+    @Override
+    protected void doPost(HttpServletRequest request, HttpServletResponse 
response) throws IOException
+    {
+//        request.getRemoteUser() ;
+//        request.getUserPrincipal() ;
+        
+        String dataset = FusekiLib.safeParameter(request, "dataset") ;
+        HttpSession session = request.getSession(true) ;
+        session.setAttribute("dataset", dataset) ;
+        session.setMaxInactiveInterval(15*60) ; // 10 mins
+        
+        boolean known = DatasetRegistry.get().isRegistered(dataset) ;
+        if ( !known )
+        {
+            response.sendError(HttpSC.BAD_REQUEST_400, "No such dataset: 
"+dataset) ;
+            return ;
+        }
+        
+        if ( true )
+        {
+            // Redirect to GET page.
+            response.setHeader(HttpNames.hLocation, PageNames.pageAfterLogin) ;
+            response.setStatus(HttpSC.SEE_OTHER_303) ;
+        }
+        else
+        {
+            // Welcome style - but HTML inline :-(
+            response.setContentType("text/html");
+            response.setStatus(HttpSC.OK_200) ;
+            ServletOutputStream out = response.getOutputStream() ;
+            out.print("<p>"+dataset+"("+known+")</p>") ;
+
+            for ( String name : DatasetRegistry.get().keys() ) {
+                out.print("<li>") ;
+                out.print(name) ;
+                out.println("</li>") ;
+            }
+            out.println("</ul>") ;
+            out.println("<p><a href=\"info\">Next</a></p>") ;
+        }
+        
+//        Cookie cookie = new Cookie("org.apache.jena.fuseki.session", 
dataset) ;
+//        // 24 hours.
+//        cookie.setMaxAge(24*60*60) ;
+        
+    }
+    
+    /**
+     * This method returns true if the HttpServletRequest contains a valid
+     * authorisation header
+     * @param req The HttpServletRequest to test
+     * @return true if the Authorisation header is valid
+     */
+
+    private boolean authenticate(HttpServletRequest req)
+    {
+        String authhead=req.getHeader("Authorization");
+
+        if(authhead!=null)
+        {
+            byte[] up = Base64.decodeBase64(authhead.substring(6)) ;
+            // Decode the authorisation String
+            String usernpass ;
+            try
+            {
+                usernpass = new String(up, "ascii") ;
+            } catch (UnsupportedEncodingException e)
+            {
+                e.printStackTrace();
+                usernpass = null ;
+            }
+            // Split the username from the password
+            String user=usernpass.substring(0,usernpass.indexOf(":"));
+            String password=usernpass.substring(usernpass.indexOf(":")+1);
+
+            if (user.equals("user") && password.equals("pass"))
+                return true;
+        }
+
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/ManagementServer.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/ManagementServer.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/ManagementServer.java
new file mode 100644
index 0000000..5e9dca9
--- /dev/null
+++ 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/ManagementServer.java
@@ -0,0 +1,99 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki.mgt;
+
+import static org.apache.jena.fuseki.Fuseki.serverLog ;
+
+import java.util.List ;
+
+import javax.servlet.http.HttpServlet ;
+
+import org.apache.jena.fuseki.Fuseki ;
+import org.apache.jena.fuseki.server.FusekiErrorHandler ;
+import org.apache.jena.fuseki.servlets.DumpServlet ;
+import org.eclipse.jetty.server.Connector ;
+import org.eclipse.jetty.server.Server ;
+import org.eclipse.jetty.server.nio.SelectChannelConnector ;
+import org.eclipse.jetty.servlet.ServletContextHandler ;
+import org.eclipse.jetty.servlet.ServletHolder ;
+
+public class ManagementServer
+{
+    public static Server createManagementServer(int mgtPort)
+    {
+        Fuseki.serverLog.info("Adding management functions") ;
+        
+        // Separate Jetty server
+        Server server = new Server() ;
+        
+//        BlockingChannelConnector bcConnector = new 
BlockingChannelConnector() ;
+//        bcConnector.setUseDirectBuffers(false) ;
+//        Connector connector = bcConnector ;
+        
+        Connector connector = new SelectChannelConnector() ;
+        // Ignore idle time. 
+        // If set, then if this goes off, it keeps going off and you get a lot 
of log messages.
+        connector.setMaxIdleTime(0) ; // Jetty outputs a lot of messages if 
this goes off.
+        connector.setPort(mgtPort);
+        server.addConnector(connector) ;
+        
+        ServletContextHandler context = new 
ServletContextHandler(ServletContextHandler.SESSIONS);
+        context.setErrorHandler(new FusekiErrorHandler()) ;
+        server.setHandler(context);
+        
+        // Add the server control servlet
+        addServlet(context, new MgtCmdServlet(),    "/mgt") ;
+        addServlet(context, new DumpServlet(),      "/dump") ;
+        addServlet(context, new StatsServlet(),     "/stats") ;
+        addServlet(context, new PingServlet(),      "/ping") ;
+        
+        return server ; 
+        // Old plan
+//      // Development : server control panel.
+//      addServlet(context, new ServerServlet(), "/server") ;
+//      addServlet(context, new ActionBackup(), "/backup") ;
+    }
+
+    // SHARE
+    private static void addServlet(ServletContextHandler context, String 
datasetPath, HttpServlet servlet, List<String> pathSpecs)
+    {
+        for ( String pathSpec : pathSpecs )
+        {
+            if ( pathSpec.endsWith("/") )
+                pathSpec = pathSpec.substring(0, pathSpec.length()-1) ;
+            if ( pathSpec.startsWith("/") )
+                pathSpec = pathSpec.substring(1, pathSpec.length()) ;
+            addServlet(context, servlet, datasetPath+"/"+pathSpec) ;
+        }
+    }
+
+    private static void addServlet(ServletContextHandler context, HttpServlet 
servlet, String pathSpec)
+    {
+        ServletHolder holder = new ServletHolder(servlet) ;
+        addServlet(context, holder, pathSpec) ;
+    }
+    
+    private static void addServlet(ServletContextHandler context, 
ServletHolder holder, String pathSpec)
+    {
+        serverLog.debug("Add servlet @ "+pathSpec) ;
+        context.addServlet(holder, pathSpec) ;
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/MgtCmdServlet.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/MgtCmdServlet.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/MgtCmdServlet.java
new file mode 100644
index 0000000..5385e75
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/MgtCmdServlet.java
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/** A servlet that dumps its request
+ */
+
+// Could be neater - much, much neater!
+
+package org.apache.jena.fuseki.mgt ;
+
+import java.io.IOException ;
+import java.io.PrintWriter ;
+
+import javax.servlet.http.HttpServlet ;
+import javax.servlet.http.HttpServletRequest ;
+import javax.servlet.http.HttpServletResponse ;
+
+import org.apache.jena.fuseki.Fuseki ;
+import org.apache.jena.fuseki.server.DatasetRef ;
+import org.apache.jena.fuseki.server.SPARQLServer ;
+import org.apache.jena.fuseki.server.ServiceRef ;
+import org.apache.jena.web.HttpSC ;
+import org.slf4j.Logger ;
+
+import com.hp.hpl.jena.Jena ;
+import com.hp.hpl.jena.query.ARQ ;
+import com.hp.hpl.jena.tdb.TDB ;
+
+/** Control functions for a Fuskei server */
+
+public class MgtCmdServlet extends HttpServlet
+{
+    // Experimental - likely to change. 
+    private static Logger log = Fuseki.serverLog ;
+
+    public MgtCmdServlet()
+    {
+
+    }
+
+    @Override
+    public void init()
+    {
+        return ;
+    }
+
+    public static String paramCmd     = "cmd" ;
+    public static String cmdBackup    = "backup" ;          // 
&dataset=/datasetname
+    public static String cmdRestart   = "restart" ;         // Not implemented.
+    public static String cmdShutdown  = "shutdown" ;        // Server stops, 
no questions asked. (Not implemented)
+
+    ActionBackup         actionBackup = new ActionBackup() ;
+
+    @Override
+    public void doPost(HttpServletRequest req, HttpServletResponse resp) 
throws IOException
+    {
+        // Commands format:
+        // ?cmd=backup&<other args per command>
+
+        String[] args = req.getParameterValues(paramCmd) ;
+        if ( args == null ) {
+            resp.setContentType("text/plain") ;
+            resp.setStatus(HttpSC.BAD_REQUEST_400) ;
+
+            return ;
+        }
+        for ( String cmd : args ) {
+            if ( log.isInfoEnabled() )
+                log.info("Management command: " + cmd) ;
+
+            if ( cmd.equalsIgnoreCase(cmdBackup) ) {
+                actionBackup.doPost(req, resp) ;
+                continue ;
+            }
+            if ( cmd.equalsIgnoreCase(cmdRestart) ) {
+
+                continue ;
+            }
+            if ( cmd.equalsIgnoreCase(cmdShutdown) ) {
+                Fuseki.getServer().stop() ;
+                continue ;
+            }
+            log.warn("Unrecognized command : " + cmd) ;
+
+        }
+    }
+
+    @Override
+    public void doGet(HttpServletRequest req, HttpServletResponse resp)
+    {
+        try {
+            // serverLog.info("Fuseki Server Config servlet") ;
+
+            PrintWriter out = resp.getWriter() ;
+            resp.setContentType("text/plain") ;
+            SPARQLServer server = Fuseki.getServer() ;
+
+            out.println("Software:") ;
+            String fusekiVersion = Fuseki.VERSION ;
+            if ( fusekiVersion.equals("${project.version}") )
+                fusekiVersion = "(development)" ;
+
+            out.printf("  %s %s\n", Fuseki.NAME, fusekiVersion) ;
+            out.printf("  %s %s\n", TDB.NAME, TDB.VERSION) ;
+            out.printf("  %s %s\n", ARQ.NAME, ARQ.VERSION) ;
+            out.printf("  %s %s\n", Jena.NAME, Jena.VERSION) ;
+
+            // out.printf("Port: %s\n",
+            // server.getServer().getConnectors()[0].getPort()) ;
+            out.println() ;
+
+            for ( DatasetRef dsRef : server.getDatasets() ) {
+                datasetRefDetails(out, dsRef) ;
+                out.println() ;
+            }
+        }
+        catch (IOException ex) {}
+    }
+
+    private static void datasetRefDetails(PrintWriter out, DatasetRef dsRef)
+    {
+        if ( dsRef.name != null )
+            out.println("Name = " + dsRef.name) ;
+        else
+            out.println("Name = <unset>") ;
+
+        endpointDetail(out, "Query", dsRef, dsRef.query) ;
+        endpointDetail(out, "Update", dsRef, dsRef.update) ;
+        endpointDetail(out, "Upload", dsRef, dsRef.upload) ;
+        endpointDetail(out, "Graphs(Read)", dsRef, dsRef.readGraphStore) ;
+        endpointDetail(out, "Graphs(RW)", dsRef, dsRef.readWriteGraphStore) ;
+    }
+
+    private static void endpointDetail(PrintWriter out, String label, 
DatasetRef dsRef, ServiceRef service)
+    {
+        boolean first = true ;
+        out.printf("   %-15s :: ", label) ;
+
+        for ( String s : service.endpoints ) {
+            if ( !first )
+                out.print(" , ") ;
+            first = false ;
+            s = "/" + dsRef.name + "/" + s ;
+            out.print(s) ;
+        }
+        out.println() ;
+    }
+
+    @Override
+    public String getServletInfo()
+    {
+        return "Fuseki Control Servlet" ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/MgtFunctions.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/MgtFunctions.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/MgtFunctions.java
new file mode 100644
index 0000000..e43b1e2
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/MgtFunctions.java
@@ -0,0 +1,180 @@
+/*
+ * 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.mgt;
+
+import java.util.List ;
+
+import javax.servlet.http.HttpServletRequest ;
+import javax.servlet.http.HttpSession ;
+
+import org.apache.jena.atlas.io.IndentedLineBuffer ;
+import org.apache.jena.atlas.iterator.Iter ;
+import org.apache.jena.fuseki.Fuseki ;
+import org.apache.jena.fuseki.server.DatasetRef ;
+import org.apache.jena.fuseki.server.DatasetRegistry ;
+import org.apache.jena.fuseki.server.ServiceRef ;
+
+import com.hp.hpl.jena.shared.PrefixMapping ;
+import com.hp.hpl.jena.sparql.core.DatasetGraph ;
+import com.hp.hpl.jena.sparql.core.Prologue ;
+import com.hp.hpl.jena.sparql.serializer.PrologueSerializer ;
+import com.hp.hpl.jena.tdb.store.DatasetGraphTDB ;
+
+/** Avoid code in JSPs */
+public class MgtFunctions
+{
+    /** Return the name of the current dataset */ 
+    public static String dataset(HttpServletRequest request, String dftValue)
+    {
+        String ds = dataset(request) ;
+        if ( ds == null )
+            return dftValue ;
+        return ds ;
+    }
+    
+    /** Return the name of the current dataset */ 
+    public static String dataset(HttpServletRequest request)
+    {
+        HttpSession session = request.getSession(false) ;
+        if ( session == null )
+            return "No session";
+        String ds = (String)session.getAttribute("dataset") ;
+        return ds ;
+    }
+
+    /** Return the dataset description reference for currnet dataset */  
+    public static DatasetRef datasetDesc(HttpServletRequest request)
+    {
+        HttpSession session = request.getSession(false) ;
+        if ( session == null )
+            return null ;
+        String ds = (String)session.getAttribute("dataset") ;
+        return DatasetRegistry.get().get(ds) ;
+    }
+
+    /** Return lists of datasets */ 
+    public static List<String> datasets(HttpServletRequest request)
+    {
+        return Iter.toList(DatasetRegistry.get().keys()) ;
+    }
+
+    /** Return name of */  
+    public static String actionDataset(HttpServletRequest request)
+    {
+        return PageNames.actionDatasetNames ;
+    }
+
+    // Service name getters ...
+    
+    /** Return a SPARQL query service name for the dataset */
+    public static String serviceQuery(String dataset)
+    {
+        String dft = "sparql" ; 
+        DatasetRef ref = getFromRegistry(dataset) ;
+        if ( ref == null )
+            return dft ;
+        return serviceNameOrDefault(ref.query, dft) ;
+    }
+    
+    /** Return a SPARQL update service name for the dataset */
+    public static String serviceUpdate(String dataset)
+    {
+        String dft = "update" ; 
+        DatasetRef ref = getFromRegistry(dataset) ;
+        if ( ref == null )
+            return dft ;
+        return serviceNameOrDefault(ref.update, dft) ;
+    }
+    
+    /** Return a SPARQL upload service name for the dataset */
+    public static String serviceUpload(String dataset)
+    {
+        String dft = "upload" ;
+        DatasetRef ref = getFromRegistry(dataset) ;
+        if ( ref == null )
+            return dft ;
+        return serviceNameOrDefault(ref.upload, dft) ;
+    }
+
+    /** Return a SPARQL Graph Store Protocol (Read) service name for the 
dataset */
+    public static String serviceGraphRead(String dataset)
+    {
+        String dft = "get" ;
+        DatasetRef ref = getFromRegistry(dataset) ;
+        if ( ref == null )
+            return dft ;
+        return serviceNameOrDefault(ref.readGraphStore, dft) ;
+    }
+
+    /** Return a SPARQL Graph Store Protocol (Read-Write) service name for the 
dataset */
+    public static String serviceGraphReadWrite(String dataset)
+    {
+        String dft = "data" ;
+        DatasetRef ref = getFromRegistry(dataset) ;
+        if ( ref == null )
+            return dft ;
+        return serviceNameOrDefault(ref.readWriteGraphStore, dft) ;
+    }
+
+    private static DatasetRef getFromRegistry(String dataset)
+    {
+        DatasetRegistry registry = DatasetRegistry.get() ;
+        if ( registry == null )
+        {
+            Fuseki.serverLog.warn("No dataset registry") ;
+            return null ;
+        }
+        
+        DatasetRef ref = registry.get(dataset) ;
+        if ( ref == null )
+            Fuseki.serverLog.warn("Dataset not found: "+dataset) ;
+        return ref ;
+    }
+
+    private static String serviceNameOrDefault(ServiceRef service, String 
defaultValue)
+    {
+        if ( service.endpoints.isEmpty() )
+            return defaultValue ;
+        String x = service.endpoints.get(0) ;
+        if ( x.startsWith("/") )
+            x = x.substring(1) ;
+        return x ;
+    }
+    
+    /** Return prefixes for the datasets, SPARQL syntax. */ 
+    public static String prefixes(HttpServletRequest request)
+    {
+        String dsName = dataset(request) ;
+        DatasetRef desc = getFromRegistry(dsName) ;
+        if ( desc == null )
+            return "<not found>" ;
+        DatasetGraph dsg = desc.dataset ; 
+        
+        if ( dsg instanceof DatasetGraphTDB )
+        {
+            PrefixMapping pmap = 
((DatasetGraphTDB)dsg).getPrefixes().getPrefixMapping() ;
+            Prologue prologue = new Prologue(pmap) ;
+            IndentedLineBuffer buff = new IndentedLineBuffer() ;
+            PrologueSerializer.output(buff, prologue) ;
+            buff.append("\n") ;
+            return buff.asString() ;
+        }
+        return "" ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/PageNames.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/PageNames.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/PageNames.java
new file mode 100644
index 0000000..4dc315b
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/PageNames.java
@@ -0,0 +1,33 @@
+/*
+ * 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.mgt;
+
+public class PageNames
+{
+    //public static final String pageControlPanel     = "/control-panel.tpl" ;
+    
+    /** The dispatch URL for the place to go after login (0.2.1 - login = 
choose dataset) */
+    public static final String pageAfterLogin      = "/sparql.tpl" ;
+    
+    /** This is the full web dispatch URL: control-panel.tpl knowns 
+     * the name indirectly because it gets it via velocity
+     * calling mgt.actionDataset.
+     */
+    public static final String actionDatasetNames   = "/$/datasets" ;
+}

http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/PingServlet.java
----------------------------------------------------------------------
diff --git 
a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/PingServlet.java 
b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/PingServlet.java
new file mode 100644
index 0000000..5d4ca53
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/PingServlet.java
@@ -0,0 +1,75 @@
+/**
+ * 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.mgt;
+
+import static org.apache.jena.riot.WebContent.charsetUTF8 ;
+import static org.apache.jena.riot.WebContent.contentTypeTextPlain ;
+
+import java.io.IOException ;
+
+import javax.servlet.ServletOutputStream ;
+import javax.servlet.http.HttpServlet ;
+import javax.servlet.http.HttpServletRequest ;
+import javax.servlet.http.HttpServletResponse ;
+
+import org.apache.jena.fuseki.Fuseki ;
+import org.apache.jena.riot.web.HttpNames ;
+import org.apache.jena.web.HttpSC ;
+
+import com.hp.hpl.jena.sparql.util.Utils ;
+
+/** 
+ * The ping servlet provides a low costy, uncached endpoint that can be used
+ * to determine if this component is running and responding.  For example,
+ * a nagios check should use this endpoint.    
+ */
+public class PingServlet extends HttpServlet
+{
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
+        doCommon(req, resp); 
+    }
+    
+    @Override
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
+        doCommon(req, resp); 
+    }
+    
+
+    @Override
+    protected void doHead(HttpServletRequest req, HttpServletResponse resp) {
+        doCommon(req, resp); 
+    }
+
+    protected void doCommon(HttpServletRequest request, HttpServletResponse 
response) {
+        try {
+            response.setHeader(HttpNames.hCacheControl, 
"must-revalidate,no-cache,no-store");
+            response.setHeader(HttpNames.hPragma, "no-cache");
+            response.setContentType(contentTypeTextPlain);
+            response.setCharacterEncoding(charsetUTF8) ;
+            response.setStatus(HttpSC.OK_200);
+            ServletOutputStream out = response.getOutputStream() ;
+            out.println(Utils.nowAsXSDDateTimeString());
+        } catch (IOException ex) {
+            Fuseki.serverLog.warn("ping :: IOException :: "+ex.getMessage());
+        }
+    }
+}
+
+

Reply via email to