You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2015/03/05 16:36:45 UTC
[06/23] jena git commit: Rename folder jena-fuseki to jena-fuseki1
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/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());
+ }
+ }
+}
+
+