This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/master by this push:
new 33bfa90 JENA-1671: Fix general query servlet.
new 4e1e517 Merge pull request #531 from afs/fuseki-web-query
33bfa90 is described below
commit 33bfa90de9758d22ec49620f4c9db590ac7d0d45
Author: Andy Seaborne <[email protected]>
AuthorDate: Thu Feb 14 16:21:00 2019 +0000
JENA-1671: Fix general query servlet.
* direct servlet as ActionService
* remove dataset description from query if processed
---
.../access/AccessCtl_SPARQL_QueryDataset.java | 14 ++--
.../org/apache/jena/fuseki/server/Operation.java | 9 ++-
.../apache/jena/fuseki/servlets/ActionService.java | 35 +++++++--
.../apache/jena/fuseki/servlets/SPARQL_Query.java | 14 +++-
.../jena/fuseki/servlets/SPARQL_QueryDataset.java | 5 +-
.../jena/fuseki/servlets/SPARQL_QueryGeneral.java | 34 ++++++---
.../apache/jena/fuseki/servlets/ServiceRouter.java | 2 +-
.../apache/jena/fuseki/main/cmds/FusekiMain.java | 5 +-
.../{CustomService.java => CustomTestService.java} | 2 +-
.../org/apache/jena/fuseki/main/TC_Fuseki.java | 2 +-
.../{TS_EmbeddedFuseki.java => TS_FusekiMain.java} | 10 +--
.../fuseki/main/TestFusekiCustomOperation.java | 36 ++++++++-
.../apache/jena/fuseki/main/TestFusekiMainCmd.java | 85 ++++++++++++++++++++++
.../{SpecialService.java => ExampleService.java} | 2 +-
.../main/examples/ExtendFuseki_AddService_1.java | 4 +-
.../main/examples/ExtendFuseki_AddService_2.java | 2 +-
.../main/examples/ExtendFuseki_AddService_3.java | 4 +-
17 files changed, 212 insertions(+), 53 deletions(-)
diff --git
a/jena-fuseki2/jena-fuseki-access/src/main/java/org/apache/jena/fuseki/access/AccessCtl_SPARQL_QueryDataset.java
b/jena-fuseki2/jena-fuseki-access/src/main/java/org/apache/jena/fuseki/access/AccessCtl_SPARQL_QueryDataset.java
index 3788355..54948a9 100644
---
a/jena-fuseki2/jena-fuseki-access/src/main/java/org/apache/jena/fuseki/access/AccessCtl_SPARQL_QueryDataset.java
+++
b/jena-fuseki2/jena-fuseki-access/src/main/java/org/apache/jena/fuseki/access/AccessCtl_SPARQL_QueryDataset.java
@@ -25,6 +25,7 @@ import java.util.Collections;
import java.util.List;
import java.util.function.Function;
+import org.apache.jena.atlas.lib.Pair;
import org.apache.jena.fuseki.servlets.ActionService;
import org.apache.jena.fuseki.servlets.HttpAction;
import org.apache.jena.fuseki.servlets.SPARQL_QueryDataset;
@@ -44,27 +45,28 @@ public class AccessCtl_SPARQL_QueryDataset extends
SPARQL_QueryDataset {
}
private static boolean ALLOW_FROM = true;
-
+
@Override
protected Collection<String> customParams() {
// The additional ?user.
return Collections.singletonList("user");
}
-
+
/** Decide the dataset - this modifies the query
* If the query has a dataset description.
*/
@Override
- protected DatasetGraph decideDataset(HttpAction action, Query query,
String queryStringLog) {
+ protected Pair<DatasetGraph, Query> decideDataset(HttpAction action, Query
query, String queryStringLog) {
DatasetGraph dsg = action.getActiveDSG();
if ( ! DataAccessCtl.isAccessControlled(dsg) )
return super.decideDataset(action, query, queryStringLog);
-
+
DatasetDescription dsDesc0 = getDatasetDescription(action, query);
SecurityContext sCxt = DataAccessLib.getSecurityContext(action, dsg,
requestUser);
- return dynamicDataset(action, query, dsg, dsDesc0, sCxt);
+ DatasetGraph dsg2 = dynamicDataset(action, query, dsg, dsDesc0, sCxt);
+ return Pair.create(dsg2, query);
}
-
+
private DatasetGraph dynamicDataset(HttpAction action, Query query,
DatasetGraph dsg0, DatasetDescription dsDesc0, SecurityContext sCxt) {
if ( dsDesc0 == null )
return dsg0;
diff --git
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Operation.java
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Operation.java
index 7037f0d..f9afc8a 100644
---
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Operation.java
+++
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Operation.java
@@ -27,10 +27,15 @@ import
org.apache.jena.fuseki.servlets.ServiceDispatchRegistry;
*/
public class Operation {
- // Create intern'ed symbols.
+ /** Create/intern. */
static private NameMgr<Operation> mgr = new NameMgr<>();
static public Operation register(String name, String description) {
- return mgr.register(name, (x)->new Operation(x, description));
+ return mgr.register(name, (x)->create(x, description));
+ }
+
+ /** Create; not registered */
+ static private Operation create(String name, String description) {
+ return new Operation(name, description);
}
public static final Operation Query = register("Query", "SPARQL
Query");
diff --git
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionService.java
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionService.java
index fe87407..c329cda 100644
---
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionService.java
+++
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionService.java
@@ -25,6 +25,8 @@ import static
org.apache.jena.fuseki.server.CounterName.RequestsGood;
import java.io.IOException;
import java.util.Collection;
+import java.util.Collections;
+import java.util.function.BiFunction;
import javax.servlet.ServletException;
@@ -38,8 +40,26 @@ import org.apache.jena.web.HttpSC;
/** Service request lifecycle */
public abstract class ActionService extends ActionBase {
+
+ private final BiFunction<HttpAction, Operation, ActionService>
selectProcessor;
+
+ /**
+ * ActionService for a directly called serlvet. The request handler will be
+ * {@code this.executeLifecycle}.
+ */
protected ActionService() {
super(Fuseki.actionLog);
+ selectProcessor = (action, operation)->this;
+ }
+
+ /**
+ * ActionService to redirect to another ActionService to be request
handler will be
+ * {@code selectProcessor.executeLifecycle}.
+ * @see ServiceRouter
+ */
+ protected ActionService(BiFunction<HttpAction, Operation, ActionService>
selectProcessor) {
+ super(Fuseki.actionLog);
+ this.selectProcessor = selectProcessor;
}
protected abstract void validate(HttpAction action);
@@ -85,7 +105,7 @@ public abstract class ActionService extends ActionBase {
String endpointName = mapRequestToOperation(action, dataAccessPoint);
// ServiceRouter dispatch
- Operation operation = null;
+ Operation operation;
if ( !endpointName.isEmpty() ) {
operation = chooseOperation(action, dSrv, endpointName);
if ( operation == null )
@@ -96,8 +116,6 @@ public abstract class ActionService extends ActionBase {
} else {
// Endpoint ""
operation = chooseOperation(action, dSrv);
- if ( operation == null )
- ServletOps.errorBadRequest(format("dataset=%s",
dataAccessPoint.getName()));
}
// ---- Auth checking.
@@ -120,15 +138,18 @@ public abstract class ActionService extends ActionBase {
// No Endpoint name given; there may be several endpoints for the
operation.
// authorization is the AND of all endpoints.
Collection<Endpoint> x = getEndpoints(dSrv, operation);
- if ( x.isEmpty() )
+ if ( operation != null && x.isEmpty() )
throw new InternalErrorException("Inconsistent: no endpoints
for "+operation);
x.forEach(ep->{
Auth.allow(user, ep.getAuthPolicy(),
ServletOps::errorForbidden);
});
}
// ---- End auth checking.
-
- ActionService handler =
action.getServiceDispatchRegistry().findHandler(operation);
+
+ // Decide the code to execute the request.
+ // For ServiceRouter, this involves a lookup in the service dispatch
registry.
+ // For directly called services, they override the operations called
by this.executeLifecycle.
+ ActionService handler = selectProcessor.apply(action, operation);
if ( handler == null )
ServletOps.errorBadRequest(format("dataset=%s: op=%s",
dataAccessPoint.getName(), operation.getName()));
handler.executeLifecycle(action);
@@ -140,6 +161,8 @@ public abstract class ActionService extends ActionBase {
// If asked for GSP_R and there are no endpoints for GSP_R, try GSP_RW.
// Ditto Quads_R -> Quads_RW.
private Collection<Endpoint> getEndpoints(DataService dSrv, Operation
operation) {
+ if ( operation == null )
+ return Collections.emptySet();
Collection<Endpoint> x = dSrv.getEndpoints(operation);
if ( x == null || x.isEmpty() ) {
if ( operation == Operation.GSP_R )
diff --git
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
index b69a336..3dc66a1 100644
---
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
+++
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_Query.java
@@ -37,6 +37,7 @@ import javax.servlet.http.HttpServletResponse ;
import org.apache.jena.atlas.io.IO ;
import org.apache.jena.atlas.io.IndentedLineBuffer ;
import org.apache.jena.atlas.json.JsonObject;
+import org.apache.jena.atlas.lib.Pair;
import org.apache.jena.atlas.web.ContentType ;
import org.apache.jena.fuseki.Fuseki ;
import org.apache.jena.fuseki.system.FusekiNetLib;
@@ -279,8 +280,13 @@ public abstract class SPARQL_Query extends SPARQL_Protocol
// Assumes finished whole thing by end of sendResult.
try {
action.beginRead() ;
- DatasetGraph dataset = decideDataset(action, query,
queryStringLog) ;
- try ( QueryExecution qExec = createQueryExecution(action, query,
dataset) ; ) {
+ Pair<DatasetGraph, Query> p = decideDataset(action, query,
queryStringLog) ;
+ DatasetGraph dataset = p.getLeft();
+ Query q = p.getRight();
+ if ( q == null )
+ q = query;
+
+ try ( QueryExecution qExec = createQueryExecution(action, q,
dataset) ; ) {
SPARQLResult result = executeQuery(action, qExec, query,
queryStringLog) ;
// Deals with exceptions itself.
sendResults(action, result, query.getPrologue()) ;
@@ -390,9 +396,9 @@ public abstract class SPARQL_Query extends SPARQL_Protocol
* @param action
* @param query Query - this may be modified to remove a
DatasetDescription.
* @param queryStringLog
- * @return {@link Dataset}
+ * @return Pair of {@link Dataset} and {@link Query}.
*/
- protected abstract DatasetGraph decideDataset(HttpAction action, Query
query, String queryStringLog) ;
+ protected abstract Pair<DatasetGraph, Query> decideDataset(HttpAction
action, Query query, String queryStringLog) ;
/** Ship the results to the remote caller.
* @param action
diff --git
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_QueryDataset.java
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_QueryDataset.java
index 668e563..8dd0ce7 100644
---
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_QueryDataset.java
+++
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_QueryDataset.java
@@ -18,6 +18,7 @@
package org.apache.jena.fuseki.servlets;
+import org.apache.jena.atlas.lib.Pair;
import org.apache.jena.query.Query ;
import org.apache.jena.sparql.core.DatasetDescription ;
import org.apache.jena.sparql.core.DatasetGraph ;
@@ -42,7 +43,7 @@ public class SPARQL_QueryDataset extends SPARQL_Query
* If the query has a dataset description.
*/
@Override
- protected DatasetGraph decideDataset(HttpAction action, Query query,
String queryStringLog) {
+ protected Pair<DatasetGraph, Query> decideDataset(HttpAction action, Query
query, String queryStringLog) {
DatasetGraph dsg = action.getActiveDSG() ;
DatasetDescription dsDesc = getDatasetDescription(action, query) ;
if ( dsDesc != null ) {
@@ -52,6 +53,6 @@ public class SPARQL_QueryDataset extends SPARQL_Query
query.getNamedGraphURIs().clear() ;
}
}
- return dsg ;
+ return Pair.create(dsg, query);
}
}
diff --git
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_QueryGeneral.java
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_QueryGeneral.java
index c31174e..677b619 100644
---
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_QueryGeneral.java
+++
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/SPARQL_QueryGeneral.java
@@ -23,6 +23,7 @@ import static java.lang.String.format ;
import java.util.List ;
import org.apache.jena.atlas.lib.InternalErrorException ;
+import org.apache.jena.atlas.lib.Pair;
import org.apache.jena.fuseki.server.DataService;
import org.apache.jena.fuseki.server.Operation;
import org.apache.jena.fuseki.system.GraphLoadUtils;
@@ -37,6 +38,11 @@ import org.apache.jena.sparql.core.DatasetGraph;
import org.apache.jena.sparql.core.DatasetGraphZero;
public class SPARQL_QueryGeneral extends SPARQL_Query {
+ // In order to use as much of the main SPARQL code as possible,
+ // this freestanding servlet mimics being a dataset service,
+ // and inserts the loaded dataset at decideDataset.
+ // ActionService understands this - the operation is null.
+
final static int MaxTriples = 100 * 1000 ;
public SPARQL_QueryGeneral() {
@@ -54,24 +60,28 @@ public class SPARQL_QueryGeneral extends SPARQL_Query {
return null ;
}
- /** SPARQL_QueryGeneral is a servlet to be called directly.
- * It declares it is own {@code Operation} to fit into {@link
ActionService#execCommonWorker}.
- * The Fuseki service handling continues;
- * {@link SPARQL_Query} will ask for a dataset which will return the
fixed, empty dataset.
- *
- */
+ /** SPARQL_QueryGeneral is a servlet to be called directly. */
@Override
protected Operation chooseOperation(HttpAction action, DataService
dataService) {
- return Operation.Query;
+ return null;
}
@Override
- protected DatasetGraph decideDataset(HttpAction action, Query query,
String queryStringLog) {
- DatasetDescription datasetDesc = getDatasetDescription(action, query) ;
- if ( datasetDesc == null )
+ protected Pair<DatasetGraph, Query> decideDataset(HttpAction action, Query
query, String queryStringLog) {
+ DatasetDescription datasetDesc = getDatasetDescription(action, query);
+ if ( datasetDesc == null ) {
//ServletOps.errorBadRequest("No dataset description in protocol
request or in the query string") ;
- return new DatasetGraphZero();
- return datasetFromDescriptionWeb(action, datasetDesc) ;
+ return Pair.create(new DatasetGraphZero(), query);
+ }
+
+ // These will have been taken care of by the "getDatasetDescription"
+ if ( query.hasDatasetDescription() ) {
+ // Don't modify input.
+ query = query.cloneQuery();
+ query.getNamedGraphURIs().clear();
+ query.getGraphURIs().clear();
+ }
+ return Pair.create(datasetFromDescriptionWeb(action, datasetDesc),
query) ;
}
/**
diff --git
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceRouter.java
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceRouter.java
index 6b8c279..671efe9 100644
---
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceRouter.java
+++
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServiceRouter.java
@@ -55,7 +55,7 @@ import org.apache.jena.riot.web.HttpNames;
public class ServiceRouter extends ActionService {
public ServiceRouter() {
- super();
+ super((action,
operation)->action.getServiceDispatchRegistry().findHandler(operation));
}
// These calls should not happen because ActionService calls
chooseOperation(),
diff --git
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/FusekiMain.java
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/FusekiMain.java
index 5d07b43..9ee5048 100644
---
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/FusekiMain.java
+++
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/FusekiMain.java
@@ -169,9 +169,8 @@ public class FusekiMain extends CmdARQ {
add(argPasswdFile, "--passwd=FILE", "Password file");
// put in the configuration file
// add(argRealm, "--realm=REALM", "Realm name");
-
-// add(argWithPing, "--ping", "Enable /$/ping");
-// add(argWithStats, "--stats", "Enable /$/stats");
+ add(argWithPing, "--ping", "Enable /$/ping");
+ add(argWithStats, "--stats", "Enable /$/stats");
super.modVersion.addClass(Fuseki.class);
}
diff --git
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/CustomService.java
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/CustomTestService.java
similarity index 98%
rename from
jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/CustomService.java
rename to
jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/CustomTestService.java
index 94eec39..6af6c25 100644
---
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/CustomService.java
+++
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/CustomTestService.java
@@ -26,7 +26,7 @@ import org.apache.jena.fuseki.servlets.ServletOps;
import org.apache.jena.riot.WebContent;
import org.apache.jena.web.HttpSC;
-public class CustomService extends ActionREST {
+public class CustomTestService extends ActionREST {
// do* -- the operations to accept
diff --git
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TC_Fuseki.java
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TC_Fuseki.java
index e0e2ba9..f3ad133 100644
---
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TC_Fuseki.java
+++
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TC_Fuseki.java
@@ -24,7 +24,7 @@ import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses( {
- TS_EmbeddedFuseki.class,
+ TS_FusekiMain.class,
TS_SecurityFuseki.class
})
public class TC_Fuseki {
diff --git
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_EmbeddedFuseki.java
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java
similarity index 82%
rename from
jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_EmbeddedFuseki.java
rename to
jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java
index c10c8d5..f49c9fd 100644
---
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_EmbeddedFuseki.java
+++
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java
@@ -32,20 +32,14 @@ import org.junit.runners.Suite.SuiteClasses ;
, TestFusekiTestServer.class
, TestFusekiTestAuth.class
, TestFusekiCustomOperation.class
+ , TestFusekiMainCmd.class
})
-public class TS_EmbeddedFuseki {
+public class TS_FusekiMain {
@BeforeClass public static void setupForFusekiServer() {
LogCtl.setLevel(Fuseki.serverLogName, "WARN");
LogCtl.setLevel(Fuseki.actionLogName, "WARN");
LogCtl.setLevel(Fuseki.requestLogName, "WARN");
LogCtl.setLevel(Fuseki.adminLogName, "WARN");
LogCtl.setLevel("org.eclipse.jetty", "WARN");
-
- // Shouldn't see these in the embedded server.
-// LogCtl.setLevel("org.apache.shiro", "WARN") ;
-// LogCtl.setLevel(Fuseki.configLogName, "WARN");
-
-// LogCtl.setLevel(Fuseki.builderLogName, "WARN");
-// LogCtl.setLevel(Fuseki.servletRequestLogName,"WARN");
}
}
diff --git
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiCustomOperation.java
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiCustomOperation.java
index 2431d82..0696140 100644
---
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiCustomOperation.java
+++
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiCustomOperation.java
@@ -35,12 +35,15 @@ import org.apache.jena.fuseki.build.FusekiBuilder;
import org.apache.jena.fuseki.server.DataService;
import org.apache.jena.fuseki.server.Operation;
import org.apache.jena.fuseki.servlets.ActionService;
+import org.apache.jena.fuseki.servlets.HttpAction;
import org.apache.jena.query.QueryExecution;
import org.apache.jena.rdfconnection.RDFConnection;
import org.apache.jena.rdfconnection.RDFConnectionFactory;
+import org.apache.jena.riot.WebContent;
import org.apache.jena.riot.web.HttpOp;
import org.apache.jena.sparql.core.DatasetGraph;
import org.apache.jena.sparql.core.DatasetGraphFactory;
+import org.apache.jena.web.HttpSC;
import org.junit.Test;
/** Test for adding a new operation */
@@ -49,7 +52,38 @@ public class TestFusekiCustomOperation {
private static final String contentType = "application/special";
private static final String endpointName = "special";
- private final ActionService customHandler = new CustomService();
+ private final ActionService customHandler = new CustomTestService() {
+ @Override
+ protected void doGet(HttpAction action) {
+ action.response.setStatus(HttpSC.OK_200);
+ try {
+
action.response.setContentType(WebContent.contentTypeTextPlain);
+ action.response.getOutputStream().println(" ** Hello world
(GET) **");
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ protected void doHead(HttpAction action) {
+ action.response.setStatus(HttpSC.OK_200);
+ action.response.setContentType(WebContent.contentTypeTextPlain);
+ }
+
+ @Override
+ protected void doPost(HttpAction action) {
+ action.response.setStatus(HttpSC.OK_200);
+ try {
+
action.response.setContentType(WebContent.contentTypeTextPlain);
+ action.response.getOutputStream().println(" ** Hello world
(POST) **");
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ };
+
private final int port = WebLib.choosePort();
private final String url = "http://localhost:"+port;
diff --git
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmd.java
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmd.java
new file mode 100644
index 0000000..3eeef96
--- /dev/null
+++
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmd.java
@@ -0,0 +1,85 @@
+/*
+ * 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.main;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+import org.apache.jena.atlas.json.JSON;
+import org.apache.jena.atlas.web.WebLib;
+import org.apache.jena.fuseki.main.cmds.FusekiMain;
+import org.apache.jena.query.ResultSetFormatter;
+import org.apache.jena.rdfconnection.RDFConnection;
+import org.apache.jena.rdfconnection.RDFConnectionFactory;
+import org.apache.jena.riot.web.HttpOp;
+import org.junit.After;
+import org.junit.Test;
+
+/** Test features */
+public class TestFusekiMainCmd {
+
+ // Fuseki Main server
+ private FusekiServer server = null;
+ private String serverURL = null;
+
+ private void server(String... cmdline) {
+ int port = WebLib.choosePort();
+
+ String[] a = Stream.concat(
+ Stream.of("--port="+port),
+ Arrays.stream(cmdline))
+ .toArray(String[]::new);
+
+ FusekiServer server = FusekiMain.build(a);
+ server.start();
+ serverURL = "http://localhost:"+port;
+ }
+
+ @After public void after() {
+ if ( server != null )
+ server.stop();
+ }
+
+ @Test public void general_01() {
+ server("--general=/q", "--empty");
+ String string = "SELECT * { VALUES ?x {1 2 3} }";
+ try ( RDFConnection conn =
RDFConnectionFactory.connect(serverURL+"/q", null, null) ) {
+ conn.queryResultSet(string, rs-> {
+ long count = ResultSetFormatter.consume(rs);
+ assertEquals(3,count);
+ });
+ }
+ }
+
+ @Test public void ping_01() {
+ server("--mem", "--ping", "/ds");
+ String x = HttpOp.execHttpGetString(serverURL+"/$/ping");
+ assertNotNull(x);
+ }
+
+ @Test public void stats_01() {
+ server("--mem", "--stats", "/ds");
+ String x = HttpOp.execHttpGetString(serverURL+"/$/stats");
+ assertNotNull(x);
+ JSON.parse(x);
+ }
+}
diff --git
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/SpecialService.java
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExampleService.java
similarity index 98%
rename from
jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/SpecialService.java
rename to
jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExampleService.java
index d7a00cc..990d2fc 100644
---
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/SpecialService.java
+++
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExampleService.java
@@ -27,7 +27,7 @@ import org.apache.jena.fuseki.servlets.ServletOps;
import org.apache.jena.riot.WebContent;
import org.apache.jena.web.HttpSC;
-public class SpecialService extends ActionREST {
+public class ExampleService extends ActionREST {
static { LogCtl.setLog4j(); }
@Override
diff --git
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExtendFuseki_AddService_1.java
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExtendFuseki_AddService_1.java
index 95dcbe9..7059e60 100644
---
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExtendFuseki_AddService_1.java
+++
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExtendFuseki_AddService_1.java
@@ -67,7 +67,7 @@ import org.apache.jena.web.HttpSC;
* .addOperation("/dataset", "endpoint", myOperation)
* .build();
* </pre>
- * @see SpecialService
+ * @see ExampleService
*/
public class ExtendFuseki_AddService_1 {
@@ -100,7 +100,7 @@ public class ExtendFuseki_AddService_1 {
// The handled for the new operation.
- ActionService customHandler = new SpecialService();
+ ActionService customHandler = new ExampleService();
FusekiServer server =
FusekiServer.create().port(PORT)
diff --git
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExtendFuseki_AddService_2.java
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExtendFuseki_AddService_2.java
index cbe868a..b6936fd 100644
---
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExtendFuseki_AddService_2.java
+++
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExtendFuseki_AddService_2.java
@@ -71,7 +71,7 @@ public class ExtendFuseki_AddService_2 {
FusekiBuilder.addServiceEP(dataService, Operation.Query,
queryEndpoint);
// The handled for the new operation.
- ActionService customHandler = new SpecialService();
+ ActionService customHandler = new ExampleService();
FusekiServer server =
FusekiServer.create().port(PORT)
diff --git
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExtendFuseki_AddService_3.java
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExtendFuseki_AddService_3.java
index cc1f7df..477d9c6 100644
---
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExtendFuseki_AddService_3.java
+++
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExtendFuseki_AddService_3.java
@@ -35,7 +35,7 @@ import org.apache.jena.util.FileUtils;
* This example show adding a custom operation to Fuseki, with dispatch by
{@code Content-Type}.
* <p>
* See {@link ExtendFuseki_AddService_1} fior a geenral description of the
routing process.
- * @see SpecialService
+ * @see ExampleService
*/
public class ExtendFuseki_AddService_3 {
@@ -64,7 +64,7 @@ public class ExtendFuseki_AddService_3 {
// The handled for the new operation.
- ActionService customHandler = new SpecialService();
+ ActionService customHandler = new ExampleService();
FusekiServer server =
FusekiServer.create().port(PORT)