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:44 UTC
[05/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/mgt/StatsServlet.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/StatsServlet.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/StatsServlet.java
new file mode 100644
index 0000000..e165355
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/mgt/StatsServlet.java
@@ -0,0 +1,171 @@
+/**
+ * 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.util.Iterator ;
+
+import javax.servlet.ServletOutputStream ;
+import javax.servlet.http.HttpServlet ;
+import javax.servlet.http.HttpServletRequest ;
+import javax.servlet.http.HttpServletResponse ;
+
+import org.apache.jena.atlas.json.JSON ;
+import org.apache.jena.atlas.json.JsonArray ;
+import org.apache.jena.atlas.json.JsonObject ;
+import org.apache.jena.fuseki.server.* ;
+import org.apache.jena.riot.WebContent ;
+
+public class StatsServlet extends HttpServlet
+{
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ //throws ServletException, IOException
+ {
+ try {
+ // Conneg etc.
+ statsJSON(req, resp) ;
+ } catch (IOException e)
+ { }
+ }
+
+ private void statsJSON(HttpServletRequest req, HttpServletResponse resp) throws IOException
+ {
+ ServletOutputStream out = resp.getOutputStream() ;
+ resp.setContentType(WebContent.contentTypeJSON);
+ resp.setCharacterEncoding(WebContent.charsetUTF8) ;
+
+ /*
+ * { "server" : ....
+ * "datasets" : {
+ * "ds1": { counters... }
+ * GSP stucture?
+ *
+ */
+
+ JsonObject obj = new JsonObject() ;
+ JsonObject datasets = new JsonObject() ;
+ JsonObject server = new JsonObject() ;
+ server.put("host", req.getLocalName()+":"+req.getLocalPort()) ;
+
+ for ( String ds : DatasetRegistry.get().keys() )
+ statsJSON(datasets, ds) ;
+
+ obj.put("server", server) ;
+ obj.put("datasets", datasets) ;
+
+ JSON.write(out, obj) ;
+ out.flush() ;
+ }
+
+ private void statsJSON(JsonObject datasets, String ds) {
+ DatasetRef desc = DatasetRegistry.get().get(ds) ;
+ JsonObject stats = new JsonObject() ;
+ datasets.put(ds, stats) ;
+ stats.put(CounterName.Requests.name(), desc.getCounters().value(CounterName.Requests)) ;
+ stats.put(CounterName.RequestsGood.name(), desc.getCounters().value(CounterName.RequestsGood)) ;
+ stats.put(CounterName.RequestsBad.name(), desc.getCounters().value(CounterName.RequestsBad)) ;
+ JsonObject services = new JsonObject() ;
+
+// JsonArray endpoints = new JsonArray() ;
+// services.put("endpoints", endpoints) ;
+// JsonArray srvNames = new JsonArray() ;
+// services.put("names", srvNames) ;
+
+ // There can be several endpoints for one service.
+ for ( ServiceRef srvRef : desc.getServiceRefs() ) {
+ JsonObject epStats = new JsonObject() ;
+ statsJSON(epStats, srvRef) ;
+ services.put(srvRef.name, epStats) ;
+ JsonArray endpoints = new JsonArray() ;
+ epStats.put("endpoints", endpoints) ;
+ for ( String ep : srvRef.endpoints) {
+ endpoints.add(ep) ;
+ }
+ }
+ stats.put("services", services) ;
+ }
+
+ private void statsJSON(JsonObject epStats, ServiceRef srvRef) {
+ for (CounterName cn : srvRef.getCounters().counters()) {
+ Counter c = srvRef.getCounters().get(cn) ;
+ epStats.put(cn.name(), c.value()) ;
+ }
+ }
+
+ private void statsTxt(HttpServletResponse resp) throws IOException
+ {
+ ServletOutputStream out = resp.getOutputStream() ;
+ resp.setContentType(WebContent.contentTypeTextPlain);
+ resp.setCharacterEncoding(WebContent.charsetUTF8) ;
+
+ Iterator<String> iter = DatasetRegistry.get().keys().iterator() ;
+ while(iter.hasNext())
+ {
+ String ds = iter.next() ;
+ DatasetRef desc = DatasetRegistry.get().get(ds) ;
+ statsTxt(out, desc) ;
+ if ( iter.hasNext() )
+ out.println() ;
+ }
+ out.flush() ;
+ }
+ private void statsTxt(ServletOutputStream out, DatasetRef desc) throws IOException
+ {
+ out.println("Dataset: "+desc.name) ;
+ out.println(" Requests = "+desc.getCounters().value(CounterName.Requests)) ;
+ out.println(" Good = "+desc.getCounters().value(CounterName.RequestsGood)) ;
+ out.println(" Bad = "+desc.getCounters().value(CounterName.RequestsBad)) ;
+
+ out.println(" SPARQL Query:") ;
+ out.println(" Request = "+desc.query.getCounters().value(CounterName.Requests)) ;
+ out.println(" Good = "+desc.query.getCounters().value(CounterName.RequestsGood)) ;
+ out.println(" Bad requests = "+desc.query.getCounters().value(CounterName.RequestsBad)) ;
+ out.println(" Timeouts = "+desc.query.getCounters().value(CounterName.QueryTimeouts)) ;
+ out.println(" Bad exec = "+desc.query.getCounters().value(CounterName.QueryExecErrors)) ;
+
+ out.println(" SPARQL Update:") ;
+ out.println(" Request = "+desc.update.getCounters().value(CounterName.Requests)) ;
+ out.println(" Good = "+desc.update.getCounters().value(CounterName.RequestsGood)) ;
+ out.println(" Bad requests = "+desc.update.getCounters().value(CounterName.RequestsBad)) ;
+ out.println(" Bad exec = "+desc.update.getCounters().value(CounterName.UpdateExecErrors)) ;
+
+ out.println(" Upload:") ;
+ out.println(" Requests = "+desc.upload.getCounters().value(CounterName.Requests)) ;
+ out.println(" Good = "+desc.upload.getCounters().value(CounterName.RequestsGood)) ;
+ out.println(" Bad = "+desc.upload.getCounters().value(CounterName.RequestsBad)) ;
+
+ out.println(" SPARQL Graph Store Protocol:") ;
+ out.println(" GETs = "+gspValue(desc, CounterName.GSPget)+ " (good="+gspValue(desc, CounterName.GSPgetGood)+"/bad="+gspValue(desc, CounterName.GSPgetBad)+")") ;
+ out.println(" PUTs = "+gspValue(desc, CounterName.GSPput)+ " (good="+gspValue(desc, CounterName.GSPputGood)+"/bad="+gspValue(desc, CounterName.GSPputBad)+")") ;
+ out.println(" POSTs = "+gspValue(desc, CounterName.GSPpost)+ " (good="+gspValue(desc, CounterName.GSPpostGood)+"/bad="+gspValue(desc, CounterName.GSPpostBad)+")") ;
+ out.println(" DELETEs = "+gspValue(desc, CounterName.GSPdelete)+ " (good="+gspValue(desc, CounterName.GSPdeleteGood)+"/bad="+gspValue(desc, CounterName.GSPdeleteBad)+")") ;
+ out.println(" HEADs = "+gspValue(desc, CounterName.GSPhead)+ " (good="+gspValue(desc, CounterName.GSPheadGood)+"/bad="+gspValue(desc, CounterName.GSPheadBad)+")") ;
+ }
+
+ private long gspValue(DatasetRef desc, CounterName cn) {
+ long x1 = desc.readGraphStore.getCounters().value(cn) ;
+ long x2 = desc.readWriteGraphStore.getCounters().value(cn) ;
+ return x1+x2 ;
+ }
+
+
+}
+
+
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/migrate/GraphLoadUtils.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/migrate/GraphLoadUtils.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/migrate/GraphLoadUtils.java
new file mode 100644
index 0000000..da16863
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/migrate/GraphLoadUtils.java
@@ -0,0 +1,76 @@
+/*
+ * 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.migrate;
+
+import org.apache.jena.atlas.web.TypedInputStream ;
+import org.apache.jena.fuseki.Fuseki ;
+import org.apache.jena.riot.RDFDataMgr ;
+import org.apache.jena.riot.system.StreamRDF ;
+import org.apache.jena.riot.system.StreamRDFLib ;
+
+import com.hp.hpl.jena.graph.Factory ;
+import com.hp.hpl.jena.graph.Graph ;
+import com.hp.hpl.jena.rdf.model.Model ;
+import com.hp.hpl.jena.rdf.model.ModelFactory ;
+
+/** A packaging of code to do a controlled read of a graph or model */
+
+public class GraphLoadUtils
+{
+ // ---- Model level
+
+ public static Model readModel(String uri, int limit)
+ {
+ Graph g = Factory.createGraphMem() ;
+ readUtil(g, uri, limit) ;
+ return ModelFactory.createModelForGraph(g) ;
+ }
+
+ public static void loadModel(Model model, String uri, int limit)
+ {
+ Graph g = model.getGraph() ;
+ readUtil(g, uri, limit) ;
+ }
+
+ // ---- Graph level
+
+ public static Graph readGraph(String uri, int limit)
+ {
+ Graph g = Factory.createGraphMem() ;
+ readUtil(g, uri, limit) ;
+ return g ;
+ }
+
+ public static void loadGraph(Graph g, String uri, int limit)
+ {
+ readUtil(g, uri, limit) ;
+ }
+
+ // ** Worker.
+ private static void readUtil(Graph graph, String uri, int limit)
+ {
+ // We need to do this ourselves, not via riot, to use the webStreamManager
+ StreamRDF sink = StreamRDFLib.graph(graph) ;
+ sink = new SinkRDFLimited(sink, limit) ;
+
+ TypedInputStream input = Fuseki.webStreamManager.open(uri) ;
+ RDFDataMgr.parse(sink, input, uri) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/migrate/Registry.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/migrate/Registry.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/migrate/Registry.java
new file mode 100644
index 0000000..ca30be1
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/migrate/Registry.java
@@ -0,0 +1,42 @@
+/*
+ * 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.migrate;
+
+import java.util.Collection ;
+import java.util.HashMap ;
+import java.util.Map ;
+
+public class Registry<T>
+{
+ protected Map<String, T> registry = new HashMap<String, T>() ;
+
+ public Registry() {}
+
+ public void put(String key, T value) { registry.put(key, value) ; }
+
+ public T get(String key) { return registry.get(key) ; }
+
+ public boolean isRegistered(String key) { return registry.containsKey(key) ; }
+ public void remove(String key) { registry.remove(key) ; }
+ public Collection<String> keys() { return registry.keySet() ; }
+ //public Iterator<String> keys() { return registry.keySet().iterator() ; }
+
+ public int size() { return registry.size() ; }
+ public boolean isEmpty() { return registry.isEmpty() ; }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/migrate/SinkRDFLimited.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/migrate/SinkRDFLimited.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/migrate/SinkRDFLimited.java
new file mode 100644
index 0000000..514d756
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/migrate/SinkRDFLimited.java
@@ -0,0 +1,55 @@
+/*
+ * 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.migrate;
+
+import org.apache.jena.riot.system.StreamRDF ;
+import org.apache.jena.riot.system.StreamRDFWrapper ;
+
+import com.hp.hpl.jena.graph.Triple ;
+import com.hp.hpl.jena.sparql.core.Quad ;
+
+public class SinkRDFLimited extends StreamRDFWrapper
+{
+ private long count = 0 ;
+ private final long limit ;
+
+ public SinkRDFLimited(StreamRDF output, long limit)
+ {
+ super(output) ;
+ this.limit = limit ;
+ }
+
+ @Override
+ public void triple(Triple triple)
+ {
+ count++ ;
+ super.triple(triple) ;
+ }
+
+ @Override
+ public void quad(Quad quad)
+ {
+ count++ ;
+ super.quad(quad) ;
+ }
+
+ public long getCount() { return count ; }
+ public long getLimit() { return limit ; }
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/Counter.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/Counter.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/Counter.java
new file mode 100644
index 0000000..88d4d37
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/Counter.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki.server;
+
+import java.util.concurrent.atomic.AtomicLong ;
+
+/** A statistics counter */
+public class Counter
+{
+ private AtomicLong counter = new AtomicLong(0) ;
+
+ public Counter() {}
+
+ public void inc() { counter.incrementAndGet() ; }
+ public void dec() { counter.decrementAndGet() ; }
+ public long value() { return counter.get() ; }
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/CounterMXBean.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/CounterMXBean.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/CounterMXBean.java
new file mode 100644
index 0000000..2de7658
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/CounterMXBean.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.server;
+
+public interface CounterMXBean
+{
+ long getValue() ;
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/CounterName.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/CounterName.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/CounterName.java
new file mode 100644
index 0000000..2952aa8
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/CounterName.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki.server;
+
+/** Names for all counters */
+public enum CounterName {
+ // There are generic names - apply to all services and datasets
+ // and specific ones.
+
+
+ // Total request received
+ Requests("requests"),
+ // .. of which some and "good" and some are "bad".
+ // #"good" + #"bad" roughly equals #"requests"
+ // except that the total is incremented at the start, and the outcome at the end.
+ // There may also be short term consistency issues.
+ RequestsGood("requests.good"),
+ RequestsBad("requests.bad") ,
+
+ // SPARQL Protocol - query and update - together with upload.
+
+ // Query - standard and ...
+ QueryTimeouts("query.timeouts") ,
+ QueryExecErrors("query.execerrors") ,
+
+ // Update - standard and ...
+ UpdateExecErrors("update.execerrors"),
+
+ // Upload ... standard counters
+
+ // Graph Store Protocol.
+
+ // For each HTTP method
+ GSPget("gsp.get.requests") ,
+ GSPgetGood("gsp.get.requests.good") ,
+ GSPgetBad("gsp.get.requests.bad") ,
+
+ GSPpost("gsp.post.requests") ,
+ GSPpostGood("gsp.post.requests.good") ,
+ GSPpostBad("gsp.post.requests.bad") ,
+
+ GSPdelete("gsp.delete.requests") ,
+ GSPdeleteGood("gsp.delete.requests.good") ,
+ GSPdeleteBad("gsp.delete.requests.bad") ,
+
+ GSPput("gsp.put.requests") ,
+ GSPputGood("gsp.put.requests.good") ,
+ GSPputBad("gsp.put.requests.bad") ,
+
+ GSPhead("gsp.head.requests") ,
+ GSPheadGood("gsp.head.requests.good") ,
+ GSPheadBad("gsp.head.requests.bad") ,
+
+ GSPpatch("gsp.patch.requests") ,
+ GSPpatchGood("gsp.patch.requests.good") ,
+ GSPpatchBad("gsp.patch.requests.bad") ,
+
+ GSPoptions("gsp.options.requests") ,
+ GSPoptionsGood("gsp.options.requests.good") ,
+ GSPoptionsBad("gsp.options.requests.bad") ,
+
+ ;
+
+ private String name ;
+ private CounterName(String name) { this.name = name ; }
+
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/CounterSet.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/CounterSet.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/CounterSet.java
new file mode 100644
index 0000000..7d0d622
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/CounterSet.java
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki.server ;
+
+import java.util.Collection ;
+import java.util.HashMap ;
+import java.util.Map ;
+
+import org.slf4j.Logger ;
+import org.slf4j.LoggerFactory ;
+
+/** A collection of counters */
+public class CounterSet {
+ private static Logger log = LoggerFactory.getLogger(CounterSet.class) ;
+
+ private Map<CounterName, Counter> counters = new HashMap<CounterName, Counter>() ;
+
+ public CounterSet() {}
+
+ public Collection<CounterName> counters() {
+ return counters.keySet() ;
+ }
+
+ public void inc(CounterName c) {
+ get(c).inc() ;
+ }
+
+ public void dec(CounterName c) {
+ get(c).dec() ;
+ }
+
+ public long value(CounterName c) {
+ return get(c).value() ;
+ }
+
+ public void add(CounterName counterName) {
+ if ( counters.containsKey(counterName) ) {
+ log.warn("Duplicate counter in counter set: " + counterName) ;
+ return ;
+ }
+ counters.put(counterName, new Counter()) ;
+ }
+
+ public boolean contains(CounterName cn) {
+ return counters.containsKey(cn) ;
+ }
+
+ public Counter get(CounterName cn) {
+ Counter c = counters.get(cn) ;
+ if ( c == null )
+ log.warn("No counter in counter set: " + cn) ;
+ return c ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/Counters.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/Counters.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/Counters.java
new file mode 100644
index 0000000..4e5ca4b
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/Counters.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.server;
+
+/** Objects that have a counter set */
+public interface Counters {
+ public CounterSet getCounters() ;
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/DatasetMXBean.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/DatasetMXBean.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/DatasetMXBean.java
new file mode 100644
index 0000000..bf38229
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/DatasetMXBean.java
@@ -0,0 +1,35 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki.server;
+
+public interface DatasetMXBean
+{
+ String getName() ;
+
+ long getRequests() ;
+ long getRequestsGood() ;
+ long getRequestsBad() ;
+
+// void enable() ;
+// void disable() ;
+// void setReadOnly() ;
+// boolean getReadOnly() ;
+
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/DatasetRef.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/DatasetRef.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/DatasetRef.java
new file mode 100644
index 0000000..040c759
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/DatasetRef.java
@@ -0,0 +1,241 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki.server;
+
+import java.util.* ;
+import java.util.concurrent.atomic.AtomicLong ;
+
+import org.apache.jena.fuseki.Fuseki ;
+
+import com.hp.hpl.jena.query.ReadWrite ;
+import com.hp.hpl.jena.sparql.core.DatasetGraph ;
+
+public class DatasetRef implements DatasetMXBean, Counters
+{
+ public String name = null ;
+ public DatasetGraph dataset = null ;
+
+ public ServiceRef query = new ServiceRef("query") ;
+ public ServiceRef update = new ServiceRef("update") ;
+ public ServiceRef upload = new ServiceRef("upload") ;
+ public ServiceRef readGraphStore = new ServiceRef("gspRead") ;
+ public ServiceRef readWriteGraphStore = new ServiceRef("gspReadWrite") ;
+
+ // Dataset-level counters.
+ private final CounterSet counters = new CounterSet() ;
+ @Override
+ public CounterSet getCounters() { return counters ; }
+
+ private Map<String, ServiceRef> endpoints = new HashMap<String, ServiceRef>() ;
+ private List<ServiceRef> serviceRefs = new ArrayList<ServiceRef>() ;
+ private boolean initialized = false ;
+
+ // Two step initiation (c.f. Builder pattern)
+ // Create object - incrementally set state - call init to calculate internal datastructures.
+ public DatasetRef() {}
+ public void init() {
+ if ( initialized )
+ Fuseki.serverLog.warn("Already initialized: dataset = "+name) ;
+ initialized = true ;
+ initServices() ;
+ }
+
+ @Override public String toString() { return "DatasetRef:'"+name+"'" ; }
+
+ private void initServices() {
+ add(query) ;
+ add(update) ;
+ add(upload) ;
+ add(readGraphStore) ;
+ add(readWriteGraphStore) ;
+ addCounters() ;
+ }
+
+ private void add(ServiceRef srvRef) {
+ serviceRefs.add(srvRef) ;
+ for ( String ep : srvRef.endpoints )
+ endpoints.put(ep, srvRef) ;
+ }
+
+ public ServiceRef getServiceRef(String service) {
+ if ( ! initialized )
+ Fuseki.serverLog.error("Not initialized: dataset = "+name) ;
+ if ( service.startsWith("/") )
+ service = service.substring(1, service.length()) ;
+ return endpoints.get(service) ;
+ }
+
+ public Collection<ServiceRef> getServiceRefs() {
+ return serviceRefs ;
+ }
+
+ /** Counter of active read transactions */
+ public AtomicLong activeReadTxn = new AtomicLong(0) ;
+
+ /** Counter of active write transactions */
+ public AtomicLong activeWriteTxn = new AtomicLong(0) ;
+
+ /** Cumulative counter of read transactions */
+ public AtomicLong totalReadTxn = new AtomicLong(0) ;
+
+ /** Cumulative counter of writer transactions */
+ public AtomicLong totalWriteTxn = new AtomicLong(0) ;
+
+// /** Count of requests received - anyzservice */
+// public AtomicLong countServiceRequests = new AtomicLong(0) ;
+// /** Count of requests received that fail in some way */
+// public AtomicLong countServiceRequestsBad = new AtomicLong(0) ;
+// /** Count of requests received that fail in some way */
+// public AtomicLong countServiceRequestsOK = new AtomicLong(0) ;
+//
+// // SPARQL Query
+//
+// /** Count of SPARQL Queries successfully executed */
+// public AtomicLong countQueryOK = new AtomicLong(0) ;
+// /** Count of SPARQL Queries with syntax errors */
+// public AtomicLong countQueryBadSyntax = new AtomicLong(0) ;
+// /** Count of SPARQL Queries with timeout on execution */
+// public AtomicLong countQueryTimeout = new AtomicLong(0) ;
+// /** Count of SPARQL Queries with execution errors (not timeouts) */
+// public AtomicLong countQueryBadExecution = new AtomicLong(0) ;
+
+ public void startTxn(ReadWrite mode)
+ {
+ switch(mode)
+ {
+ case READ:
+ activeReadTxn.getAndIncrement() ;
+ totalReadTxn.getAndIncrement() ;
+ break ;
+ case WRITE:
+ activeWriteTxn.getAndIncrement() ;
+ totalWriteTxn.getAndIncrement() ;
+ break ;
+ }
+ }
+
+ public void finishTxn(ReadWrite mode)
+ {
+ switch(mode)
+ {
+ case READ:
+ activeReadTxn.decrementAndGet() ;
+ break ;
+ case WRITE:
+ activeWriteTxn.decrementAndGet() ;
+ break ;
+ }
+ }
+
+ //TODO Need to be able to set this from the config file.
+ public boolean allowDatasetUpdate = false;
+
+ public boolean allowTimeoutOverride = false;
+ public long maximumTimeoutOverride = Long.MAX_VALUE;
+
+ public boolean isReadOnly()
+ {
+ return ! allowDatasetUpdate &&
+ ! update.isActive() &&
+ ! upload.isActive() &&
+ ! readWriteGraphStore.isActive()
+ ;
+ }
+
+ // MBean
+
+ @Override
+ public String getName() { return name ; }
+
+ @Override public long getRequests() {
+ return counters.value(CounterName.Requests) ;
+ }
+
+ @Override
+ public long getRequestsGood() {
+ return counters.value(CounterName.RequestsGood) ;
+ }
+ @Override
+ public long getRequestsBad() {
+ return counters.value(CounterName.RequestsBad) ;
+ }
+
+ private void addCounters() {
+ getCounters().add(CounterName.Requests) ;
+ getCounters().add(CounterName.RequestsGood) ;
+ getCounters().add(CounterName.RequestsBad) ;
+
+ query.getCounters().add(CounterName.Requests) ;
+ query.getCounters().add(CounterName.RequestsGood) ;
+ query.getCounters().add(CounterName.RequestsBad) ;
+ query.getCounters().add(CounterName.QueryTimeouts) ;
+ query.getCounters().add(CounterName.QueryExecErrors) ;
+
+ update.getCounters().add(CounterName.Requests) ;
+ update.getCounters().add(CounterName.RequestsGood) ;
+ update.getCounters().add(CounterName.RequestsBad) ;
+ update.getCounters().add(CounterName.UpdateExecErrors) ;
+
+ upload.getCounters().add(CounterName.Requests) ;
+ upload.getCounters().add(CounterName.RequestsGood) ;
+ upload.getCounters().add(CounterName.RequestsBad) ;
+
+ addCountersForGSP(readWriteGraphStore.getCounters(), false) ;
+ if ( readGraphStore != readWriteGraphStore )
+ addCountersForGSP(readGraphStore.getCounters(), true) ;
+ }
+
+ private void addCountersForGSP(CounterSet cs, boolean readWrite) {
+ cs.add(CounterName.Requests) ;
+ cs.add(CounterName.RequestsGood) ;
+ cs.add(CounterName.RequestsBad) ;
+
+ cs.add(CounterName.GSPget) ;
+ cs.add(CounterName.GSPgetGood) ;
+ cs.add(CounterName.GSPgetBad) ;
+
+ cs.add(CounterName.GSPhead) ;
+ cs.add(CounterName.GSPheadGood) ;
+ cs.add(CounterName.GSPheadBad) ;
+
+ // Add anyway.
+ // if ( ! readWrite )
+ // return ;
+
+ cs.add(CounterName.GSPput) ;
+ cs.add(CounterName.GSPputGood) ;
+ cs.add(CounterName.GSPputBad) ;
+
+ cs.add(CounterName.GSPpost) ;
+ cs.add(CounterName.GSPpostGood) ;
+ cs.add(CounterName.GSPpostBad) ;
+
+ cs.add(CounterName.GSPdelete) ;
+ cs.add(CounterName.GSPdeleteGood) ;
+ cs.add(CounterName.GSPdeleteBad) ;
+
+ cs.add(CounterName.GSPpatch) ;
+ cs.add(CounterName.GSPpatchGood) ;
+ cs.add(CounterName.GSPpatchBad) ;
+
+ cs.add(CounterName.GSPoptions) ;
+ cs.add(CounterName.GSPoptionsGood) ;
+ cs.add(CounterName.GSPoptionsBad) ;
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/DatasetRegistry.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/DatasetRegistry.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/DatasetRegistry.java
new file mode 100644
index 0000000..152e8cd
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/DatasetRegistry.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki.server;
+
+import org.apache.jena.fuseki.migrate.Registry ;
+
+public class DatasetRegistry extends Registry<DatasetRef>
+{
+ private static DatasetRegistry singleton = new DatasetRegistry() ;
+
+ public static DatasetRegistry get() { return singleton ; }
+
+ private DatasetRegistry() {}
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiConfig.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiConfig.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiConfig.java
new file mode 100644
index 0000000..9c36a7c
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiConfig.java
@@ -0,0 +1,374 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki.server;
+
+import java.lang.reflect.Method ;
+import java.util.ArrayList ;
+import java.util.Arrays ;
+import java.util.List ;
+
+import org.apache.jena.atlas.iterator.Iter ;
+import org.apache.jena.atlas.lib.StrUtils ;
+import org.apache.jena.fuseki.Fuseki ;
+import org.apache.jena.fuseki.FusekiConfigException ;
+import org.apache.jena.fuseki.HttpNames ;
+import org.slf4j.Logger ;
+
+import com.hp.hpl.jena.assembler.Assembler ;
+import com.hp.hpl.jena.assembler.JA ;
+import com.hp.hpl.jena.query.ARQ ;
+import com.hp.hpl.jena.query.Dataset ;
+import com.hp.hpl.jena.query.Query ;
+import com.hp.hpl.jena.query.QueryExecution ;
+import com.hp.hpl.jena.query.QueryExecutionFactory ;
+import com.hp.hpl.jena.query.QueryFactory ;
+import com.hp.hpl.jena.query.QuerySolution ;
+import com.hp.hpl.jena.query.QuerySolutionMap ;
+import com.hp.hpl.jena.query.ResultSet ;
+import com.hp.hpl.jena.query.ResultSetFactory ;
+import com.hp.hpl.jena.rdf.model.Literal ;
+import com.hp.hpl.jena.rdf.model.Model ;
+import com.hp.hpl.jena.rdf.model.RDFNode ;
+import com.hp.hpl.jena.rdf.model.ResIterator ;
+import com.hp.hpl.jena.rdf.model.Resource ;
+import com.hp.hpl.jena.rdf.model.Statement ;
+import com.hp.hpl.jena.rdf.model.StmtIterator ;
+import com.hp.hpl.jena.shared.PrefixMapping ;
+import com.hp.hpl.jena.sparql.core.DatasetGraph ;
+import com.hp.hpl.jena.sparql.core.DatasetGraphFactory ;
+import com.hp.hpl.jena.sparql.core.DatasetGraphReadOnly ;
+import com.hp.hpl.jena.sparql.core.assembler.AssemblerUtils ;
+import com.hp.hpl.jena.tdb.TDB ;
+import com.hp.hpl.jena.util.FileManager ;
+import com.hp.hpl.jena.vocabulary.RDF ;
+import com.hp.hpl.jena.vocabulary.RDFS ;
+
+public class FusekiConfig
+{
+ static { Fuseki.init(); }
+
+ // The datastructure that captures a servers configuration.
+
+ // Server port
+ int port ;
+ // Management command port - -1 for none.
+ int mgtPort ;
+ List<DatasetRef> datasets = null ;
+
+
+ private static Logger log = Fuseki.configLog ;
+
+ private static String prefixes = StrUtils.strjoinNL(
+ "PREFIX fu: <http://jena.apache.org/fuseki#>" ,
+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>",
+ "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>",
+ "PREFIX tdb: <http://jena.hpl.hp.com/2008/tdb#>",
+ "PREFIX list: <http://jena.hpl.hp.com/ARQ/list#>",
+ "PREFIX list: <http://jena.hpl.hp.com/ARQ/list#>",
+ "PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>",
+ "PREFIX apf: <http://jena.hpl.hp.com/ARQ/property#>",
+ "PREFIX afn: <http://jena.hpl.hp.com/ARQ/function#>" ,
+ "") ;
+
+ public static ServerConfig defaultConfiguration(String datasetPath, DatasetGraph dsg, boolean allowUpdate, boolean listenLocal)
+ {
+ DatasetRef dbDesc = new DatasetRef() ;
+ dbDesc.name = datasetPath ;
+ dbDesc.dataset = dsg ;
+ dbDesc.query.endpoints.add(HttpNames.ServiceQuery) ;
+ dbDesc.query.endpoints.add(HttpNames.ServiceQueryAlt) ;
+
+ if ( allowUpdate )
+ {
+ dbDesc.update.endpoints.add(HttpNames.ServiceUpdate) ;
+ dbDesc.upload.endpoints.add(HttpNames.ServiceUpload) ;
+ dbDesc.readWriteGraphStore.endpoints.add(HttpNames.ServiceData) ;
+ dbDesc.allowDatasetUpdate = true ;
+ }
+ else
+ dbDesc.readGraphStore.endpoints.add(HttpNames.ServiceData) ;
+ ServerConfig config = new ServerConfig() ;
+ config.datasets = Arrays.asList(dbDesc) ;
+ config.port = 3030 ;
+ config.mgtPort = 3031 ;
+ config.pagesPort = config.port ;
+ config.loopback = listenLocal ;
+ config.jettyConfigFile = null ;
+ config.pages = Fuseki.PagesStatic ;
+ config.enableCompression = true ;
+ config.verboseLogging = false ;
+ return config ;
+ }
+
+ public static ServerConfig configure(String filename)
+ {
+ // Be absolutely sure everything has initialized.
+ // Some initialization registers assemblers and sets abbreviation vocabulary.
+ ARQ.init();
+ TDB.init() ;
+ Fuseki.init() ;
+ Model m = FileManager.get().loadModel(filename) ;
+
+ // Find one server.
+ List<Resource> servers = getByType(FusekiVocab.tServer, m) ;
+ if ( servers.size() == 0 )
+ throw new FusekiConfigException("No server found (no resource with type "+strForResource(FusekiVocab.tServer)) ;
+ if ( servers.size() > 1 )
+ throw new FusekiConfigException(servers.size()+" servers found (must be exactly one in a configuration file)") ;
+
+ // ---- Server
+ Resource server = servers.get(0) ;
+ processServer(server) ;
+
+ // ---- Services
+ ResultSet rs = query("SELECT * { ?s fu:services [ list:member ?member ] }", m) ;
+ if ( ! rs.hasNext() )
+ log.warn("No services found") ;
+
+ List<DatasetRef> services = new ArrayList<DatasetRef>() ;
+
+ for ( ; rs.hasNext() ; )
+ {
+ QuerySolution soln = rs.next() ;
+ Resource svc = soln.getResource("member") ;
+ DatasetRef sd = processService(svc) ;
+ services.add(sd) ;
+ }
+
+ // TODO Properties for the other fields.
+ ServerConfig config = new ServerConfig() ;
+ config.datasets = services ;
+ config.port = 3030 ;
+ config.mgtPort = 3031 ;
+ config.pagesPort = config.port ;
+ config.jettyConfigFile = null ;
+ config.pages = Fuseki.PagesStatic ;
+ config.enableCompression = true ;
+ config.verboseLogging = false ;
+ return config ;
+ }
+
+
+ // DatasetRef used where there isn't a real Dataset e.g. the SPARQL processor.
+
+ private static DatasetRef noDataset = new DatasetRef() ;
+ private static DatasetGraph dummyDSG = new DatasetGraphReadOnly(DatasetGraphFactory.createMemFixed()) ;
+ static {
+ noDataset.name = "" ;
+ noDataset.dataset = dummyDSG ;
+ noDataset.query.endpoints.add(HttpNames.ServiceQuery) ;
+ noDataset.query.endpoints.add(HttpNames.ServiceQueryAlt) ;
+ noDataset.allowDatasetUpdate = false ;
+ noDataset.init();
+ // Don't register it.
+ // This is used as a placeholder and shoudl not be found by "all datasets"
+ // DatasetRegistry.get().put("", noDataset) ;
+ }
+
+ /** Return the DatasetRef (read-only) for when there is no dataset, just a SPARQL Query processor */
+ public static DatasetRef serviceOnlyDatasetRef() { return noDataset ; }
+
+ private static void processServer(Resource server)
+ {
+ // Global, currently.
+ AssemblerUtils.setContext(server, Fuseki.getContext()) ;
+
+ StmtIterator sIter = server.listProperties(JA.loadClass) ;
+ for( ; sIter.hasNext(); )
+ {
+ Statement s = sIter.nextStatement() ;
+ RDFNode rn = s.getObject() ;
+ String className = null ;
+ if ( rn instanceof Resource )
+ {
+ String uri = ((Resource)rn).getURI() ;
+ if ( uri == null )
+ {
+ log.warn("Blank node for class to load") ;
+ continue ;
+ }
+ String javaScheme = "java:" ;
+ if ( ! uri.startsWith(javaScheme) )
+ {
+ log.warn("Class to load is not 'java:': "+uri) ;
+ continue ;
+ }
+ className = uri.substring(javaScheme.length()) ;
+ }
+ if ( rn instanceof Literal )
+ className = ((Literal)rn).getLexicalForm() ;
+ /*Loader.*/loadAndInit(className) ;
+ }
+ // ----
+ }
+
+ private static void loadAndInit(String className)
+ {
+ try {
+ Class<?> classObj = Class.forName(className);
+ log.info("Loaded "+className) ;
+ Method initMethod = classObj.getMethod("init");
+ initMethod.invoke(null);
+ } catch (ClassNotFoundException ex)
+ {
+ log.warn("Class not found: "+className);
+ }
+ catch (Exception e) { throw new FusekiConfigException(e) ; }
+ }
+
+ private static DatasetRef processService(Resource svc)
+ {
+ log.info("Service: "+nodeLabel(svc)) ;
+ DatasetRef sDesc = new DatasetRef() ;
+ sDesc.name = ((Literal)getOne(svc, "fu:name")).getLexicalForm() ;
+ log.info(" name = "+sDesc.name) ;
+
+ addServiceEP("query", sDesc.name, sDesc.query, svc, "fu:serviceQuery") ;
+ addServiceEP("update", sDesc.name, sDesc.update, svc, "fu:serviceUpdate") ;
+ addServiceEP("upload", sDesc.name, sDesc.upload, svc, "fu:serviceUpload") ;
+ addServiceEP("graphStore(RW)", sDesc.name, sDesc.readWriteGraphStore, svc, "fu:serviceReadWriteGraphStore") ;
+ addServiceEP("graphStore(R)", sDesc.name, sDesc.readGraphStore, svc, "fu:serviceReadGraphStore") ;
+ // Extract timeout overriding configuration if present.
+ if (svc.hasProperty(FusekiVocab.pAllowTimeoutOverride)) {
+ sDesc.allowTimeoutOverride = svc.getProperty(FusekiVocab.pAllowTimeoutOverride).getObject().asLiteral().getBoolean();
+ if (svc.hasProperty(FusekiVocab.pMaximumTimeoutOverride)) {
+ sDesc.maximumTimeoutOverride = (int) (svc.getProperty(FusekiVocab.pMaximumTimeoutOverride).getObject().asLiteral().getFloat() * 1000);
+ }
+ }
+
+ Resource datasetDesc = ((Resource)getOne(svc, "fu:dataset")) ;
+
+ // Check if it is in the model.
+ if ( ! datasetDesc.hasProperty(RDF.type) )
+ throw new FusekiConfigException("No rdf:type for dataset "+nodeLabel(datasetDesc)) ;
+
+ Dataset ds = (Dataset)Assembler.general.open(datasetDesc) ;
+ sDesc.dataset = ds.asDatasetGraph() ;
+ return sDesc ;
+
+ }
+
+ private static RDFNode getOne(Resource svc, String property)
+ {
+ String ln = property.substring(property.indexOf(':')+1) ;
+ ResultSet rs = query("SELECT * { ?svc "+property+" ?x}", svc.getModel(), "svc", svc) ;
+ if ( ! rs.hasNext() )
+ throw new FusekiConfigException("No "+ln+" for service "+nodeLabel(svc)) ;
+ RDFNode x = rs.next().get("x") ;
+ if ( rs.hasNext() )
+ throw new FusekiConfigException("Multiple "+ln+" for service "+nodeLabel(svc)) ;
+ return x ;
+ }
+
+ private static List<Resource> getByType(Resource type, Model m)
+ {
+ ResIterator rIter = m.listSubjectsWithProperty(RDF.type, type) ;
+ return Iter.toList(rIter) ;
+ }
+
+ private static void addServiceEP(String label, String name, ServiceRef service, Resource svc, String property)
+ {
+ ResultSet rs = query("SELECT * { ?svc "+property+" ?ep}", svc.getModel(), "svc", svc) ;
+ for ( ; rs.hasNext() ; )
+ {
+ QuerySolution soln = rs.next() ;
+ String epName = soln.getLiteral("ep").getLexicalForm() ;
+ service.endpoints.add(epName) ;
+ log.info(" "+label+" = /"+name+"/"+epName) ;
+ }
+ }
+
+
+ private static ResultSet query(String string, Model m)
+ {
+ return query(string, m, null, null) ;
+ }
+
+ private static ResultSet query(String string, Model m, String varName, RDFNode value)
+ {
+ Query query = QueryFactory.create(prefixes+string) ;
+ QuerySolutionMap initValues = null ;
+ if ( varName != null )
+ initValues = querySolution(varName, value) ;
+ try(QueryExecution qExec = QueryExecutionFactory.create(query, m, initValues)) {
+ ResultSet rs = ResultSetFactory.copyResults(qExec.execSelect()) ;
+ return rs ;
+ }
+ }
+
+ private static QuerySolutionMap querySolution(String varName, RDFNode value)
+ {
+ QuerySolutionMap qsm = new QuerySolutionMap() ;
+ querySolution(qsm, varName, value) ;
+ return qsm ;
+ }
+
+ private static QuerySolutionMap querySolution(QuerySolutionMap qsm, String varName, RDFNode value)
+ {
+ qsm.add(varName, value) ;
+ return qsm ;
+ }
+
+ // Node presentation
+ private static String nodeLabel(RDFNode n)
+ {
+ if ( n == null )
+ return "<null>" ;
+ if ( n instanceof Resource )
+ return strForResource((Resource)n) ;
+
+ Literal lit = (Literal)n ;
+ return lit.getLexicalForm() ;
+ }
+
+ private static String strForResource(Resource r) { return strForResource(r, r.getModel()) ; }
+
+ private static String strForResource(Resource r, PrefixMapping pm)
+ {
+ if ( r == null )
+ return "NULL ";
+ if ( r.hasProperty(RDFS.label))
+ {
+ RDFNode n = r.getProperty(RDFS.label).getObject() ;
+ if ( n instanceof Literal )
+ return ((Literal)n).getString() ;
+ }
+
+ if ( r.isAnon() )
+ return "<<blank node>>" ;
+
+ if ( pm == null )
+ pm = r.getModel() ;
+
+ return strForURI(r.getURI(), pm ) ;
+ }
+
+ private static String strForURI(String uri, PrefixMapping pm)
+ {
+ if ( pm != null )
+ {
+ String x = pm.shortForm(uri) ;
+
+ if ( ! x.equals(uri) )
+ return x ;
+ }
+ return "<"+uri+">" ;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiErrorHandler.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiErrorHandler.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiErrorHandler.java
new file mode 100644
index 0000000..d1660f5
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiErrorHandler.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki.server;
+
+import static java.lang.String.format ;
+
+import java.io.* ;
+
+import javax.servlet.http.HttpServletRequest ;
+import javax.servlet.http.HttpServletResponse ;
+
+import org.apache.jena.fuseki.Fuseki ;
+import org.apache.jena.web.HttpSC ;
+import org.eclipse.jetty.http.HttpHeaders ;
+import org.eclipse.jetty.http.HttpMethods ;
+import org.eclipse.jetty.http.MimeTypes ;
+import org.eclipse.jetty.server.AbstractHttpConnection ;
+import org.eclipse.jetty.server.Request ;
+import org.eclipse.jetty.server.handler.ErrorHandler ;
+
+public class FusekiErrorHandler extends ErrorHandler
+{
+ @Override
+ public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException
+ {
+ AbstractHttpConnection connection = AbstractHttpConnection.getCurrentConnection();
+ connection.getRequest().setHandled(true);
+ String method = request.getMethod();
+
+ if(!method.equals(HttpMethods.GET) && !method.equals(HttpMethods.POST) && !method.equals(HttpMethods.HEAD))
+ return;
+
+ response.setContentType(MimeTypes.TEXT_PLAIN_UTF_8) ;
+ response.setHeader(HttpHeaders.CACHE_CONTROL, "must-revalidate,no-cache,no-store") ;
+
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream(1024) ;
+ //String writer = IO.UTF8(null) ;
+ try(Writer writer = new OutputStreamWriter(bytes, "UTF-8")) {
+
+ handleErrorPage(request, writer, connection.getResponse().getStatus(), connection.getResponse().getReason());
+
+ if ( ! Fuseki.VERSION.equalsIgnoreCase("development") )
+ {
+ writer.write("\n") ;
+ writer.write("\n") ;
+ writer.write(format("Fuseki - version %s (Build date: %s)\n", Fuseki.VERSION, Fuseki.BUILD_DATE)) ;
+ }
+ writer.flush();
+ }
+ response.setContentLength(bytes.size()) ;
+ // Copy
+ response.getOutputStream().write(bytes.toByteArray()) ;
+ }
+
+ @Override
+ protected void handleErrorPage(HttpServletRequest request, Writer writer, int code, String message)
+ throws IOException
+ {
+ if ( message == null )
+ message = HttpSC.getMessage(code) ;
+ writer.write(format("Error %d: %s\n", code, message)) ;
+
+ Throwable th = (Throwable)request.getAttribute("javax.servlet.error.exception");
+ while(th!=null)
+ {
+ writer.write("\n");
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ th.printStackTrace(pw);
+ pw.flush();
+ writer.write(sw.getBuffer().toString());
+ writer.write("\n");
+ th = th.getCause();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiServletContextListener.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiServletContextListener.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiServletContextListener.java
new file mode 100644
index 0000000..f1c9642
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiServletContextListener.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki.server;
+
+import javax.servlet.ServletContextEvent ;
+import javax.servlet.ServletContextListener ;
+
+public class FusekiServletContextListener implements ServletContextListener {
+ // This could do the initialization.
+ private final SPARQLServer sparqlServer ;
+ public FusekiServletContextListener(SPARQLServer sparqlServer) {
+ this.sparqlServer = sparqlServer ;
+ }
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce) {
+// Fuseki.serverLog.info("contextInitialized") ;
+// for ( DatasetRef dsRef : sparqlServer.getDatasets() )
+// Fuseki.serverLog.info("Dataset: "+dsRef.getName()) ;
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce) {
+// Fuseki.serverLog.info("contextDestroyed") ;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiVocab.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiVocab.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiVocab.java
new file mode 100644
index 0000000..d4d4e54
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/FusekiVocab.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki.server;
+
+import org.apache.jena.fuseki.FusekiException ;
+import org.apache.jena.iri.IRI ;
+import org.apache.jena.riot.system.IRIResolver ;
+
+import com.hp.hpl.jena.rdf.model.Property ;
+import com.hp.hpl.jena.rdf.model.Resource ;
+import com.hp.hpl.jena.rdf.model.ResourceFactory ;
+
+public class FusekiVocab
+{
+ public static String NS = "http://jena.apache.org/fuseki#" ;
+
+ public static final Resource tServer = resource("Server") ;
+
+ public static final Property pServices = property("services") ;
+ public static final Property pServiceName = property("name") ;
+
+ public static final Property pServiceQueryEP = property("serviceQuery") ;
+ public static final Property pServiceUpdateEP = property("serviceUpdate") ;
+ public static final Property pServiceUploadEP = property("serviceUpload") ;
+ public static final Property pServiceReadWriteGraphStoreEP = property("serviceReadWriteGraphStore") ;
+ public static final Property pServiceReadgraphStoreEP = property("serviceReadGraphStore") ;
+
+ public static final Property pAllowTimeoutOverride = property("allowTimeoutOverride");
+ public static final Property pMaximumTimeoutOverride = property("maximumTimeoutOverride");
+
+ private static Resource resource(String localname) { return ResourceFactory.createResource(iri(localname)) ; }
+ private static Property property(String localname) { return ResourceFactory.createProperty(iri(localname)) ; }
+
+ private static String iri(String localname)
+ {
+ String uri = NS+localname ;
+ IRI iri = IRIResolver.parseIRI(uri) ;
+ if ( iri.hasViolation(true) )
+ throw new FusekiException("Bad IRI: "+iri) ;
+ if ( ! iri.isAbsolute() )
+ throw new FusekiException("Bad IRI: "+iri) ;
+
+ return uri ;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/SPARQLServer.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/SPARQLServer.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/SPARQLServer.java
new file mode 100644
index 0000000..7448eb2
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/SPARQLServer.java
@@ -0,0 +1,484 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki.server ;
+
+import static java.lang.String.format ;
+import static org.apache.jena.fuseki.Fuseki.serverLog ;
+
+import java.io.FileInputStream ;
+import java.util.* ;
+
+import javax.servlet.DispatcherType ;
+import javax.servlet.http.HttpServlet ;
+
+import org.apache.jena.atlas.lib.FileOps ;
+import org.apache.jena.fuseki.Fuseki ;
+import org.apache.jena.fuseki.FusekiException ;
+import org.apache.jena.fuseki.HttpNames ;
+import org.apache.jena.fuseki.mgt.ActionDataset ;
+import org.apache.jena.fuseki.mgt.MgtFunctions ;
+import org.apache.jena.fuseki.mgt.PageNames ;
+import org.apache.jena.fuseki.servlets.* ;
+import org.apache.jena.fuseki.validation.DataValidator ;
+import org.apache.jena.fuseki.validation.IRIValidator ;
+import org.apache.jena.fuseki.validation.QueryValidator ;
+import org.apache.jena.fuseki.validation.UpdateValidator ;
+import org.apache.jena.riot.WebContent ;
+import org.eclipse.jetty.http.MimeTypes ;
+import org.eclipse.jetty.security.* ;
+import org.eclipse.jetty.security.authentication.BasicAuthenticator ;
+import org.eclipse.jetty.server.Connector ;
+import org.eclipse.jetty.server.Server ;
+import org.eclipse.jetty.server.nio.BlockingChannelConnector ;
+import org.eclipse.jetty.servlet.DefaultServlet ;
+import org.eclipse.jetty.servlet.ServletContextHandler ;
+import org.eclipse.jetty.servlet.ServletHolder ;
+import org.eclipse.jetty.servlets.GzipFilter ;
+import org.eclipse.jetty.util.security.Constraint ;
+import org.eclipse.jetty.xml.XmlConfiguration ;
+
+import com.hp.hpl.jena.sparql.mgt.ARQMgt ;
+import com.hp.hpl.jena.sparql.util.Utils ;
+
+/**
+ * SPARQLServer is the Jena server instance which wraps/utilizes
+ * {@link org.eclipse.jetty.server.Server}. This class provides
+ * immediate access to the {@link org.eclipse.jetty.server.Server#start()} and
+ * {@link org.eclipse.jetty.server.Server#stop()} commands as well as obtaining
+ * instances of the server and server configuration. Finally we can obtain
+ * instances of {@link org.apache.jena.fuseki.server.ServerConfig}.
+ *
+ */
+public class SPARQLServer {
+ static {
+ Fuseki.init() ;
+ }
+
+ private ServerConfig serverConfig ;
+
+ private Server server = null ;
+ private static List<String> epDataset = Arrays.asList("*") ;
+
+ /**
+ * Default constructor which requires a {@link org.apache.jena.fuseki.server.ServerConfig}
+ * object as input. We use this config to specify (verbose) logging, enable compression
+ * etc.
+ * @param config
+ */
+ public SPARQLServer(ServerConfig config) {
+ this.serverConfig = config ;
+ // Currently server-wide.
+ Fuseki.verboseLogging = config.verboseLogging ;
+
+ // GZip compression
+ // Note that regardless of this setting we'll always leave it turned off
+ // for the servlets
+ // where it makes no sense to have it turned on e.g. update and upload
+
+ ServletContextHandler context = buildServer(serverConfig.jettyConfigFile, config.enableCompression) ;
+ configureDatasets(context) ;
+ }
+
+ private void configureDatasets(ServletContextHandler context) {
+ // Build them all.
+ for (DatasetRef dsDesc : serverConfig.datasets)
+ configureOneDataset(context, dsDesc, serverConfig.enableCompression) ;
+
+ }
+
+ /**
+ * Initialize the {@link SPARQLServer} instance.
+ */
+ public void start() {
+ String now = Utils.nowAsString() ;
+ serverLog.info(format("%s %s %s", Fuseki.NAME, Fuseki.VERSION, Fuseki.BUILD_DATE)) ;
+ // This does not get set usefully for Jetty as we use it.
+ // String jettyVersion = org.eclipse.jetty.server.Server.getVersion() ;
+ // serverLog.info(format("Jetty %s",jettyVersion)) ;
+ String host = server.getConnectors()[0].getHost() ;
+ if ( host != null )
+ serverLog.info("Incoming connections limited to " + host) ;
+ serverLog.info(format("Started %s on port %d", now, server.getConnectors()[0].getPort())) ;
+
+ try {
+ server.start() ;
+ } catch (java.net.BindException ex) {
+ serverLog.error("SPARQLServer: Failed to start server: " + ex.getMessage()) ;
+ System.exit(1) ;
+ } catch (Exception ex) {
+ serverLog.error("SPARQLServer: Failed to start server: " + ex.getMessage(), ex) ;
+ System.exit(1) ;
+ }
+
+ ServletContextHandler context = (ServletContextHandler)server.getHandler() ;
+ }
+
+ /**
+ * Stop the {@link SPARQLServer} instance.
+ */
+ public void stop() {
+ String now = Utils.nowAsString() ;
+ serverLog.info(format("Stopped %s on port %d", now, server.getConnectors()[0].getPort())) ;
+ try {
+ server.stop() ;
+ } catch (Exception ex) {
+ Fuseki.serverLog.warn("SPARQLServer: Exception while stopping server: " + ex.getMessage(), ex) ;
+ }
+ removeJMX() ;
+ }
+
+ /**
+ * Get the Jetty instance.
+ * @return Server
+ */
+ public Server getServer() {
+ return server ;
+ }
+
+ /**
+ * Get the datasets associated with the server.
+ * @return returns the datasets via {@link org.apache.jena.fuseki.server.ServerConfig#datasets}
+ */
+ public List<DatasetRef> getDatasets() {
+ return serverConfig.datasets ;
+ }
+
+ /**
+ * Obtain the {@link org.apache.jena.fuseki.server.ServerConfig}
+ * @return ServerConfig
+ */
+ public ServerConfig getServerConfig() {
+ return serverConfig ;
+ }
+
+ // Later : private and in constructor.
+ private ServletContextHandler buildServer(String jettyConfig, boolean enableCompression) {
+ if ( jettyConfig != null ) {
+ // --jetty-config=jetty-fuseki.xml
+ // for detailed configuration of the server using Jetty features.
+ server = configServer(jettyConfig) ;
+ } else
+ server = defaultServerConfig(serverConfig.port, serverConfig.loopback) ;
+ // Keep the server to a maximum number of threads.
+ // server.setThreadPool(new QueuedThreadPool(ThreadPoolSize)) ;
+
+ ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS) ;
+ context.setErrorHandler(new FusekiErrorHandler()) ;
+ context.addEventListener(new FusekiServletContextListener(this));
+
+ // Increase form size.
+ context.getServletContext().getContextHandler().setMaxFormContentSize(10 * 1000 * 1000) ;
+
+ // Wire up authentication if appropriate
+ if ( jettyConfig == null && serverConfig.authConfigFile != null ) {
+ Constraint constraint = new Constraint() ;
+ constraint.setName(Constraint.__BASIC_AUTH) ;
+ constraint.setRoles(new String[]{"fuseki"}) ;
+ constraint.setAuthenticate(true) ;
+
+ ConstraintMapping mapping = new ConstraintMapping() ;
+ mapping.setConstraint(constraint) ;
+ mapping.setPathSpec("/*") ;
+
+ IdentityService identService = new DefaultIdentityService() ;
+
+ ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler() ;
+ securityHandler.addConstraintMapping(mapping) ;
+ securityHandler.setIdentityService(identService) ;
+
+ HashLoginService loginService = new HashLoginService("Fuseki Authentication", serverConfig.authConfigFile) ;
+ loginService.setIdentityService(identService) ;
+
+ securityHandler.setLoginService(loginService) ;
+ securityHandler.setAuthenticator(new BasicAuthenticator()) ;
+
+ context.setSecurityHandler(securityHandler) ;
+
+ serverLog.debug("Basic Auth Configuration = " + serverConfig.authConfigFile) ;
+ }
+
+ // Wire up context handler to server
+ server.setHandler(context) ;
+
+ // Constants. Add RDF types.
+ MimeTypes mt = new MimeTypes() ;
+ mt.addMimeMapping("rdf", WebContent.contentTypeRDFXML + ";charset=utf-8") ;
+ mt.addMimeMapping("ttl", WebContent.contentTypeTurtle + ";charset=utf-8") ;
+ mt.addMimeMapping("nt", WebContent.contentTypeNTriples + ";charset=ascii") ;
+ mt.addMimeMapping("nq", WebContent.contentTypeNQuads + ";charset=ascii") ;
+ mt.addMimeMapping("trig", WebContent.contentTypeTriG + ";charset=utf-8") ;
+
+ // mt.addMimeMapping("tpl", "text/html;charset=utf-8") ;
+ context.setMimeTypes(mt) ;
+ server.setHandler(context) ;
+
+ serverLog.debug("Pages = " + serverConfig.pages) ;
+
+ boolean installManager = true ;
+ boolean installServices = true ;
+
+ String validationRoot = "/validate" ;
+
+ // Should all services be /_/.... or some such?
+
+ if ( installManager || installServices ) {
+ // TODO Respect port.
+ if ( serverConfig.pagesPort != serverConfig.port )
+ serverLog.warn("Not supported yet - pages on a different port to services") ;
+ if ( serverConfig.pages != null ) {
+ if ( ! FileOps.exists(serverConfig.pages) )
+ serverLog.warn("No pages directory - "+serverConfig.pages) ;
+ String base = serverConfig.pages ;
+ Map<String, Object> data = new HashMap<String, Object>() ;
+ data.put("mgt", new MgtFunctions()) ;
+ SimpleVelocityServlet templateEngine = new SimpleVelocityServlet(base, data) ;
+ addServlet(context, templateEngine, "*.tpl", false) ;
+ }
+ }
+
+ if ( installManager ) {
+ // Action when control panel selects a dataset.
+ HttpServlet datasetChooser = new ActionDataset() ;
+ addServlet(context, datasetChooser, PageNames.actionDatasetNames, false) ;
+ }
+
+ if ( installServices ) {
+ // Validators
+ HttpServlet validateQuery = new QueryValidator() ;
+ HttpServlet validateUpdate = new UpdateValidator() ;
+ HttpServlet validateData = new DataValidator() ;
+ HttpServlet validateIRI = new IRIValidator() ;
+
+ HttpServlet dumpService = new DumpServlet() ;
+ HttpServlet generalQueryService = new SPARQL_QueryGeneral() ;
+
+ addServlet(context, validateQuery, validationRoot + "/query", false) ;
+ addServlet(context, validateUpdate, validationRoot + "/update", false) ;
+ addServlet(context, validateData, validationRoot + "/data", false) ;
+ addServlet(context, validateIRI, validationRoot + "/iri", false) ;
+
+ // general query processor.
+ addServlet(context, generalQueryService, HttpNames.ServiceGeneralQuery, enableCompression) ;
+ }
+
+ if ( installManager || installServices ) {
+ String[] files = {"fuseki.html", "index.html"} ;
+ context.setWelcomeFiles(files) ;
+ addContent(context, "/", serverConfig.pages) ;
+ }
+
+ return context ;
+ }
+
+ /** Experimental - off by default. The überservlet sits on the dataset name and handles all requests.
+ * Includes direct naming and quad access to the dataset.
+ */
+ public static boolean überServlet = false ;
+
+ private static List<String> ListOfEmptyString = Arrays.asList("") ;
+
+ private void configureOneDataset(ServletContextHandler context, DatasetRef dsDesc, boolean enableCompression) {
+ String datasetPath = dsDesc.name ;
+ if ( datasetPath.equals("/") )
+ datasetPath = "" ;
+ else
+ if ( !datasetPath.startsWith("/") )
+ datasetPath = "/" + datasetPath ;
+
+ if ( datasetPath.endsWith("/") )
+ datasetPath = datasetPath.substring(0, datasetPath.length() - 1) ;
+
+ dsDesc.init() ;
+
+ DatasetRegistry.get().put(datasetPath, dsDesc) ;
+ serverLog.info(format("Dataset path = %s", datasetPath)) ;
+
+ HttpServlet sparqlQuery = new SPARQL_QueryDataset() ;
+ HttpServlet sparqlUpdate = new SPARQL_Update() ;
+ HttpServlet sparqlUpload = new SPARQL_Upload() ;
+ HttpServlet sparqlHttpR = new SPARQL_REST_R() ;
+ HttpServlet sparqlHttpRW = new SPARQL_REST_RW() ;
+ HttpServlet sparqlDataset = new SPARQL_UberServlet.AccessByConfig() ;
+
+ if ( !überServlet ) {
+ // If uberserver, these are unnecessary but can be used.
+ // If just means the überservlet isn't handling these operations.
+ addServlet(context, datasetPath, sparqlQuery, dsDesc.query, enableCompression) ;
+ addServlet(context, datasetPath, sparqlUpdate, dsDesc.update, false) ;
+ addServlet(context, datasetPath, sparqlUpload, dsDesc.upload, false) ; // No point - no results of any size.
+ addServlet(context, datasetPath, sparqlHttpR, dsDesc.readGraphStore, enableCompression) ;
+ addServlet(context, datasetPath, sparqlHttpRW, dsDesc.readWriteGraphStore, enableCompression) ;
+ // This adds direct operations on the dataset itself.
+ // addServlet(context, datasetPath, sparqlDataset,
+ // ListOfEmptyString, enableCompression) ;
+ } else {
+ // This is the servlet that analyses requests and dispatches them to
+ // the appropriate servlet.
+ // SPARQL Query, SPARQL Update -- handles dataset?query=
+ // dataset?update=
+ // Graph Store Protocol (direct and indirect naming) if enabled.
+ // GET/PUT/POST on the dataset itself.
+ // It also checks for a request that looks like a service request
+ // and passes it
+ // on to the service (this takes precedence over direct naming).
+ addServlet(context, datasetPath, sparqlDataset, epDataset, enableCompression) ;
+ }
+
+ // Add JMX beans to record daatset and it's services.
+ addJMX(dsDesc) ;
+ }
+
+ private static Server configServer(String jettyConfig) {
+ try {
+ serverLog.info("Jetty server config file = " + jettyConfig) ;
+ Server server = new Server() ;
+ XmlConfiguration configuration = new XmlConfiguration(new FileInputStream(jettyConfig)) ;
+ configuration.configure(server) ;
+ return server ;
+ } catch (Exception ex) {
+ serverLog.error("SPARQLServer: Failed to configure server: " + ex.getMessage(), ex) ;
+ throw new FusekiException("Failed to configure a server using configuration file '" + jettyConfig + "'") ;
+ }
+ }
+
+ private static Server defaultServerConfig(int port, boolean loopback) {
+ // Server, with one NIO-based connector, large input buffer size (for
+ // long URLs, POSTed forms (queries, updates)).
+ Server server = new Server() ;
+
+ // Using "= new SelectChannelConnector() ;" on Darwin (OS/X) causes
+ // problems
+ // with initialization not seen (thread scheduling?) in Joseki.
+
+ // BlockingChannelConnector is better for pumping large responses back
+ // but there have been observed problems with DirectMemory allocation
+ // (-XX:MaxDirectMemorySize=1G does not help)
+ // Connector connector = new SelectChannelConnector() ;
+
+ // Connector and specific settings.
+ BlockingChannelConnector bcConnector = new BlockingChannelConnector() ;
+ // bcConnector.setUseDirectBuffers(false) ;
+
+ Connector connector = bcConnector ;
+ // Ignore. 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.
+ if ( loopback )
+ connector.setHost("localhost");
+ connector.setPort(port) ;
+ // Some people do try very large operations ...
+ connector.setRequestHeaderSize(64 * 1024) ;
+ connector.setRequestBufferSize(5 * 1024 * 1024) ;
+ connector.setResponseBufferSize(5 * 1024 * 1024) ;
+ server.addConnector(connector) ;
+ return server ;
+ }
+
+ private static void addContent(ServletContextHandler context, String pathSpec, String pages) {
+ DefaultServlet staticServlet = new DefaultServlet() ;
+ ServletHolder staticContent = new ServletHolder(staticServlet) ;
+ staticContent.setInitParameter("resourceBase", pages) ;
+
+ // Note we set GZip to false for static content because the Jetty
+ // DefaultServlet has
+ // a built-in GZip capability that is better for static content than the
+ // mechanism the
+ // GzipFilter uses for dynamic content
+ addServlet(context, staticContent, pathSpec, false) ;
+ }
+
+ private void addServlet(ServletContextHandler context, String datasetPath, HttpServlet servlet,
+ ServiceRef serviceRef, boolean enableCompression) {
+ addServlet(context, datasetPath, servlet, serviceRef.endpoints, enableCompression) ;
+ }
+
+ // SHARE
+ private static void addServlet(ServletContextHandler context, String datasetPath, HttpServlet servlet,
+ List<String> pathSpecs, boolean enableCompression) {
+ for (String pathSpec : pathSpecs) {
+ if ( pathSpec.equals("") ) {
+ // "" is special -- add as "base" and "base/"
+ addServlet(context, servlet, datasetPath + "/", enableCompression) ;
+ addServlet(context, servlet, datasetPath, enableCompression) ;
+ continue ;
+ }
+
+ if ( pathSpec.endsWith("/") )
+ pathSpec = pathSpec.substring(0, pathSpec.length() - 1) ;
+ if ( pathSpec.startsWith("/") )
+ pathSpec = pathSpec.substring(1, pathSpec.length()) ;
+ addServlet(context, servlet, datasetPath + "/" + pathSpec, enableCompression) ;
+ }
+ }
+
+ private static void addServlet(ServletContextHandler context, HttpServlet servlet, String pathSpec,
+ boolean enableCompression) {
+ ServletHolder holder = new ServletHolder(servlet) ;
+ addServlet(context, holder, pathSpec, enableCompression) ;
+ }
+
+ private static void addServlet(ServletContextHandler context, ServletHolder holder, String pathSpec,
+ boolean enableCompression) {
+ if ( serverLog.isDebugEnabled() ) {
+ if ( enableCompression )
+ serverLog.debug("Add servlet @ " + pathSpec + " (with gzip)") ;
+ else
+ serverLog.debug("Add servlet @ " + pathSpec) ;
+ }
+ context.addServlet(holder, pathSpec) ;
+
+ if ( enableCompression )
+ context.addFilter(GzipFilter.class, pathSpec, EnumSet.allOf(DispatcherType.class)) ;
+ }
+
+ private void addJMX() {
+ DatasetRegistry registry = DatasetRegistry.get() ;
+ for (String ds : registry.keys()) {
+ DatasetRef dsRef = registry.get(ds) ;
+ addJMX(dsRef) ;
+ }
+ }
+
+ private void addJMX(DatasetRef dsRef) {
+ String x = dsRef.name ;
+ // if ( x.startsWith("/") )
+ // x = x.substring(1) ;
+ ARQMgt.register(Fuseki.PATH + ".dataset:name=" + x, dsRef) ;
+ // For all endpoints
+ for (ServiceRef sRef : dsRef.getServiceRefs()) {
+ ARQMgt.register(Fuseki.PATH + ".dataset:name=" + x + "/" + sRef.name, sRef) ;
+ }
+ }
+
+ private void removeJMX() {
+ DatasetRegistry registry = DatasetRegistry.get() ;
+ for (String ds : registry.keys()) {
+ DatasetRef ref = registry.get(ds) ;
+ }
+ }
+
+ private void removeJMX(DatasetRef dsRef) {
+ String x = dsRef.getName() ;
+ ARQMgt.unregister(Fuseki.PATH + ".dataset:name=" + x) ;
+ for (ServiceRef sRef : dsRef.getServiceRefs()) {
+ ARQMgt.unregister(Fuseki.PATH + ".dataset:name=" + x + "/" + sRef.name) ;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/jena/blob/662cf71d/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/ServerConfig.java
----------------------------------------------------------------------
diff --git a/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/ServerConfig.java b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/ServerConfig.java
new file mode 100644
index 0000000..4e0b865
--- /dev/null
+++ b/jena-fuseki1/src/main/java/org/apache/jena/fuseki/server/ServerConfig.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.fuseki.server;
+
+import java.util.List ;
+
+/** This represents a configuration of a SPARQL server.
+ */
+
+public class ServerConfig
+{
+ public ServerConfig() {}
+
+ /** Port to run the server service on */
+ public int port ;
+ /** Port for the management interface : -1 for no management interface */
+ public int mgtPort ;
+ /** Port for the pages UI : this can be the same as the services port. */
+ public int pagesPort ;
+ /** Jetty config file - if null, use the built-in configuration of Jetty */
+ public String jettyConfigFile = null ;
+ /** Listen only on the loopback (localhost) interface */
+ public boolean loopback = false ;
+ /** The local directory for serving the static pages */
+ public String pages ;
+ /** The list of datasets */
+ public List<DatasetRef> datasets ;
+ /** Enable Accept-Encoding compression. Set to false by default.*/
+ public boolean enableCompression = false ;
+
+ /** Enable additional logging */
+ public boolean verboseLogging = false ;
+ /**
+ * Authentication config file used to setup Jetty Basic auth, if a Jetty config file was set this is ignored since Jetty config allows much more complex auth methods to be implemented
+ */
+ public String authConfigFile ;
+
+}
+