This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new c758d2ba90 GH-1804: Configurable fuseki modules
new 93b80ef0c8 Merge pull request #1805 from afs/fuseki-modules
c758d2ba90 is described below
commit c758d2ba909ad431a4afe972b11ad26782f27566
Author: Andy Seaborne <[email protected]>
AuthorDate: Fri Mar 17 14:14:18 2023 +0000
GH-1804: Configurable fuseki modules
---
.../org/apache/jena/fuseki/main/FusekiServer.java | 58 +++++++++--
.../jena/fuseki/main/sys/FusekiModuleStep.java | 29 ++++--
.../apache/jena/fuseki/main/sys/FusekiModules.java | 80 +++++++--------
.../jena/fuseki/main/sys/FusekiModulesLoaded.java | 98 ++++++++++++++++++
.../jena/fuseki/main/sys/FusekiModulesSystem.java | 38 +++++++
.../apache/jena/fuseki/main/sys/InitFuseki.java | 2 +-
.../org/apache/jena/fuseki/main/ModuleForTest.java | 9 ++
.../apache/jena/fuseki/main/TestFusekiModules.java | 112 +++++++++++++++++----
.../main/examples/ExFusekiMain_3_FusekiModule.java | 17 +++-
.../ExFuseki_04_CustomOperation_Module.java | 13 ++-
10 files changed, 370 insertions(+), 86 deletions(-)
diff --git
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiServer.java
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiServer.java
index 59cd6c242e..aaf7ef631f 100644
---
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiServer.java
+++
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiServer.java
@@ -49,9 +49,7 @@ import org.apache.jena.fuseki.auth.AuthPolicy;
import org.apache.jena.fuseki.build.FusekiConfig;
import org.apache.jena.fuseki.ctl.*;
import org.apache.jena.fuseki.main.cmds.FusekiMain;
-import org.apache.jena.fuseki.main.sys.FusekiErrorHandler;
-import org.apache.jena.fuseki.main.sys.FusekiModuleStep;
-import org.apache.jena.fuseki.main.sys.JettyLib;
+import org.apache.jena.fuseki.main.sys.*;
import org.apache.jena.fuseki.metrics.MetricsProviderRegistry;
import org.apache.jena.fuseki.server.*;
import org.apache.jena.fuseki.servlets.*;
@@ -151,15 +149,18 @@ public class FusekiServer {
private int httpsPort;
private final String staticContentDir;
private final ServletContext servletContext;
+ private final FusekiModules modules;
private FusekiServer(int httpPort, int httpsPort, Server server,
String staticContentDir,
+ FusekiModules modules,
ServletContext fusekiServletContext) {
- this.server = server;
+ this.server = Objects.requireNonNull(server);
this.httpPort = httpPort;
this.httpsPort = httpsPort;
this.staticContentDir = staticContentDir;
- this.servletContext = fusekiServletContext;
+ this.servletContext = Objects.requireNonNull(fusekiServletContext);
+ this.modules = Objects.requireNonNull(modules);
}
/**
@@ -280,6 +281,13 @@ public class FusekiServer {
return staticContentDir;
}
+ /**
+ * Return the list of {@link FusekiModule}s for this server.
+ */
+ public FusekiModules getModules() {
+ return modules;
+ }
+
/**
* Start the server - the server continues to run after this call returns.
* To synchronise with the server stopping, call {@link #join}.
@@ -288,7 +296,6 @@ public class FusekiServer {
try {
FusekiModuleStep.serverBeforeStarting(this);
server.start();
- FusekiModuleStep.serverAfterStarting(this);
}
catch (IOException ex) {
if ( ex.getCause() instanceof
java.security.UnrecoverableKeyException )
@@ -303,6 +310,7 @@ public class FusekiServer {
throw new FusekiException(ex);
}
+ // Post-start completion. Find the ports.
Connector[] connectors = server.getServer().getConnectors();
if ( connectors.length == 0 )
serverLog.warn("Start Fuseki: No connectors");
@@ -318,6 +326,8 @@ public class FusekiServer {
}
});
+ FusekiModuleStep.serverAfterStarting(this);
+
if ( httpsPort > 0 && httpPort > 0 )
Fuseki.serverLog.info("Start Fuseki (http="+httpPort+"
https="+httpsPort+")");
else if ( httpsPort > 0 )
@@ -415,6 +425,10 @@ public class FusekiServer {
private List<Pair<String, Filter>> beforeFilters = new
ArrayList<>();
private List<Pair<String, Filter>> afterFilters = new
ArrayList<>();
+ // Modules to use to process the building of the server.
+ // The default (fusekiModules is null) is the system-wide modules.
+ private FusekiModules fusekiModules = null;
+
private String contextPath = "/";
private String staticContentDir = null;
private SecurityHandler securityHandler = null;
@@ -1037,6 +1051,26 @@ public class FusekiServer {
return this;
}
+ /**
+ * Set the {@link FusekiModule Fuseki Module} for a server.
+ * If no modules are added to a builder, then the system-wide default
set (found by loading FusekiModule
+ * via Java's {@link ServiceLoader} mechanism) is used.
+ * <p>Pass {@code null} to switch back the system-wide default set.
+ *
+ * @see FusekiModules
+ */
+ public Builder setModules(FusekiModules modules) {
+ fusekiModules = modules;
+ return this;
+ }
+
+ /**
+ * Return the current list of Fuseki modules in the builder.
+ */
+ public FusekiModules getFusekiModules() {
+ return fusekiModules;
+ }
+
/**
* Add an operation and handler to the server. This does not enable it
for any dataset.
* <p>
@@ -1192,9 +1226,13 @@ public class FusekiServer {
if ( serverHttpPort < 0 && serverHttpsPort < 0 )
serverHttpPort = DefaultServerPort;
+ FusekiModules modules = (fusekiModules == null)
+ ? FusekiModulesSystem.get()
+ : fusekiModules;
+
// FusekiModule call - final preparations.
Set<String> datasetNames = Set.copyOf(dataServices.keys());
- FusekiModuleStep.prepare(this, datasetNames, configModel);
+ FusekiModuleStep.prepare(modules, this, datasetNames, configModel);
// Freeze operation registry (builder may be reused).
OperationRegistry operationReg = new
OperationRegistry(operationRegistry);
@@ -1203,7 +1241,7 @@ public class FusekiServer {
DataAccessPointRegistry dapRegistry = buildStart();
// FusekiModule call - inspect the DataAccessPointRegistry.
- FusekiModuleStep.configured(this, dapRegistry, configModel);
+ FusekiModuleStep.configured(modules, this, dapRegistry,
configModel);
// Setup Prometheus metrics. This will become a module.
bindPrometheus(dapRegistry);
@@ -1228,7 +1266,7 @@ public class FusekiServer {
if ( jettyServerConfig != null ) {
Server server = jettyServer(handler, jettyServerConfig);
- return new FusekiServer(-1, -1, server, staticContentDir,
handler.getServletContext());
+ return new FusekiServer(-1, -1, server, staticContentDir,
modules, handler.getServletContext());
}
Server server;
@@ -1245,7 +1283,7 @@ public class FusekiServer {
if ( networkLoopback )
applyLocalhost(server);
- FusekiServer fusekiServer = new FusekiServer(httpPort,
httpsPort, server, staticContentDir, handler.getServletContext());
+ FusekiServer fusekiServer = new FusekiServer(httpPort,
httpsPort, server, staticContentDir, modules, handler.getServletContext());
FusekiModuleStep.server(fusekiServer);
return fusekiServer;
} finally {
diff --git
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModuleStep.java
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModuleStep.java
index 84223860ed..14623d6c04 100644
---
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModuleStep.java
+++
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModuleStep.java
@@ -26,42 +26,55 @@ import org.apache.jena.rdf.model.Model;
/** Call points for FusekiModule extensions */
public class FusekiModuleStep {
+
/**
* Call at the start of "build" step.
* The builder has been set according to the configuration.
* The "configModel" parameter is set if a configuration file was used
else it is null.
*/
+ public static void prepare(FusekiModules modules, FusekiServer.Builder
serverBuilder, Set<String> datasetNames, Model configModel) {
+ modules.forEach(module -> module.prepare(serverBuilder, datasetNames,
configModel));
+ }
+
+ /** @deprecated Use {@code prepare(FusekiModules, ...)}. */
+ @Deprecated
public static void prepare(FusekiServer.Builder serverBuilder, Set<String>
datasetNames, Model configModel) {
- FusekiModules.forEachModule(module -> module.prepare(serverBuilder,
datasetNames, configModel));
+ prepare(systemModules(), serverBuilder, datasetNames, configModel);
}
/**
* The DataAccessPointRegistry that will be used to build the server.
*
*/
+ public static void configured(FusekiModules modules, FusekiServer.Builder
serverBuilder, DataAccessPointRegistry dapRegistry, Model configModel) {
+ modules.forEach(module -> module.configured(serverBuilder,
dapRegistry, configModel));
+ }
+
+ /** @deprecated Use {@code configured(FusekiModules.loaded(), ...)}. */
+ @Deprecated
public static void configured(FusekiServer.Builder serverBuilder,
DataAccessPointRegistry dapRegistry, Model configModel) {
- FusekiModules.forEachModule(module -> module.configured(serverBuilder,
dapRegistry, configModel));
+ configured(systemModules(), serverBuilder, dapRegistry, configModel);
}
/**
* The outcome of the "build" step.
*/
public static void server(FusekiServer server) {
- FusekiModules.forEachModule(module -> module.server(server));
+ server.getModules().forEach(module -> module.server(server));
}
/**
* Called just before {@code server.start()} called.
*/
public static void serverBeforeStarting(FusekiServer server) {
- FusekiModules.forEachModule(module ->
module.serverBeforeStarting(server));
+ server.getModules().forEach(module ->
module.serverBeforeStarting(server));
}
/**
* Called just after {@code server.start()} called.
*/
public static void serverAfterStarting(FusekiServer server) {
- FusekiModules.forEachModule(module ->
module.serverAfterStarting(server));
+ server.getModules().forEach(module ->
module.serverAfterStarting(server));
}
/**
@@ -70,6 +83,10 @@ public class FusekiModuleStep {
* simply exits the JVM or is killed externally.
*/
public static void serverStopped(FusekiServer server) {
- FusekiModules.forEachModule(module -> module.serverStopped(server));
+ server.getModules().forEach(module -> module.serverStopped(server));
+ }
+
+ private static FusekiModules systemModules() {
+ return FusekiModulesSystem.get();
}
}
diff --git
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModules.java
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModules.java
index a1b9bd9093..20c6a100d8 100644
---
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModules.java
+++
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModules.java
@@ -18,67 +18,57 @@
package org.apache.jena.fuseki.main.sys;
-import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.function.Consumer;
-import org.apache.jena.base.module.Subsystem;
-
-/** Registry of modules */
+/**
+ * List of {@linkplain FusekiModule Fuseki modules}.
+ * This is the immutable collection of modules for a server.
+ * <p>
+ * @see FusekiModulesLoaded
+ */
public class FusekiModules {
- private static Object lock = new Object();
+ /** A Fuseki module with no members. */
+ public static final FusekiModules empty = FusekiModules.create();
- // Record of what is loaded.
- private static List<FusekiModule> registry = null;
-
- private static Subsystem<FusekiModule> subsystem = null;
+ /** Create a collection of Fuseki modules */
+ public static FusekiModules create(FusekiModule ... modules) {
+ return new FusekiModules(modules);
+ }
- public static void load() {
- if ( registry == null )
- reload();
+ /** Create a collection of Fuseki modules */
+ public static FusekiModules create(List<FusekiModule> modules) {
+ return new FusekiModules(modules);
}
- public static void reload() {
- registry = new ArrayList<>();
- subsystem = new Subsystem<FusekiModule>(FusekiModule.class);
- subsystem.initialize();
- synchronized(lock) {
- subsystem.forEach(registry::add);
- }
+ private final List<FusekiModule> modules;
+
+ private FusekiModules(FusekiModule ... modules) {
+ this.modules = List.of(Objects.requireNonNull(modules));
}
- /** Add a code module */
- public static void add(FusekiModule module) {
- synchronized(lock) {
- load();
- module.start();
- registry.add(module);
- }
+ private FusekiModules(List<FusekiModule> modules) {
+ this.modules = List.copyOf(Objects.requireNonNull(modules));
}
- /** Remove a code module */
- public static void remove(FusekiModule module) {
- synchronized(lock) {
- registry.remove(module);
- module.stop();
- }
+ /**
+ * Return an immutable list of modules.
+ */
+ public List<FusekiModule> asList() {
+ return List.copyOf(modules);
}
- /** Test whether a code module is registered. */
- public static boolean contains(FusekiModule module) {
- synchronized(lock) {
- return registry.contains(module);
- }
+ /**
+ * Apply an action to each module, in order, one at a time.
+ */
+ public void forEach(Consumer<FusekiModule> action) {
+ modules.forEach(action);
}
- /*package*/ static void forEachModule(Consumer<FusekiModule> action) {
- synchronized(lock) {
- if ( registry == null )
- load();
- if ( registry == null || registry.isEmpty() )
- return ;
- registry.forEach(action);
- }
+ /** Test whether a code module is registered. */
+ public boolean contains(FusekiModule module) {
+ return modules.contains(module);
}
}
diff --git
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModulesLoaded.java
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModulesLoaded.java
new file mode 100644
index 0000000000..142eaa6474
--- /dev/null
+++
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModulesLoaded.java
@@ -0,0 +1,98 @@
+/*
+ * 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.sys;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.jena.base.module.Subsystem;
+
+/** Control of fuseki modules loaded via ServiceLoader */
+public class FusekiModulesLoaded {
+
+ private static final Object lock = new Object();
+
+ // Record of what is loaded.
+ private static List<FusekiModule> loadedModules = null;
+
+ // Loaded modules as FusekiModules
+ private static FusekiModules loaded = null;
+
+ private static boolean enabled = true;
+
+ /** Enable/disable loaded modules. */
+ public static void enable(boolean setting) {
+ synchronized(lock) {
+ if ( setting ) {
+ if ( ! enabled )
+ reload();
+ } else {
+ // Clear.
+ loadedModules.forEach(FusekiModule::stop);
+ loadedModules = List.of();
+ loaded = FusekiModules.empty;
+ }
+ enabled = setting;
+ }
+ }
+
+ /* package */ static void init() {
+ load();
+ FusekiModulesSystem.set(loaded);
+ }
+
+ /** Whether the system loaded modules are enabled. */
+ public static boolean isEnabled() {
+ return enabled;
+ }
+
+ /** The system wide list of Fuseki modules. */
+ public static FusekiModules loaded() {
+ return loaded;
+ }
+
+ /** Load the the system wide Fuseki modules if it has not already been
loaded. */
+ public static void load() {
+ if ( ! enabled )
+ return;
+ if ( loadedModules == null )
+ reload();
+ }
+
+ /**
+ * Load and set system wide Fuseki modules.
+ */
+ public static void reload() {
+ synchronized(lock) {
+ List<FusekiModule> thisLoad = new ArrayList<>();
+ Subsystem<FusekiModule> subsystem = new
Subsystem<FusekiModule>(FusekiModule.class);
+ subsystem.initialize();
+ subsystem.forEach(thisLoad::add);
+ loadedModules = List.copyOf(thisLoad);
+ loaded = FusekiModules.create(loadedModules);
+ enabled = true;
+ }
+ }
+
+ /** Reload modules and set as the system modules. */
+ public static void resetSystem() {
+ reload();
+ FusekiModulesSystem.set(loaded);
+ }
+}
diff --git
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModulesSystem.java
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModulesSystem.java
new file mode 100644
index 0000000000..6959dfc3da
--- /dev/null
+++
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModulesSystem.java
@@ -0,0 +1,38 @@
+/*
+ * 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.sys;
+
+import java.util.Objects;
+
+public class FusekiModulesSystem {
+
+ // The immutable system-wide FusekiModules
+ // Used by default during a Fuseki server build cycle.
+ private static FusekiModules systemModules = FusekiModules.empty;
+
+ /** The current system-wide modules. */
+ public static FusekiModules get() {
+ return systemModules;
+ }
+
+ /** Set the system-wide modules. This will then ignore loaded modules. */
+ public static void set(FusekiModules modules) {
+ systemModules = Objects.requireNonNull(modules);
+ }
+}
diff --git
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/InitFuseki.java
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/InitFuseki.java
index 88889e6793..80651a26b4 100644
---
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/InitFuseki.java
+++
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/InitFuseki.java
@@ -56,7 +56,7 @@ public class InitFuseki implements JenaSubsystemLifecycle {
}
initialized = true;
JenaSystem.logLifecycle("Fuseki.init - start");
- FusekiModules.load();
+ FusekiModulesLoaded.init();
try {
Cmds.injectCmd("fuseki", a->FusekiMainCmd.main(a));
} catch (NoClassDefFoundError ex) {
diff --git
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/ModuleForTest.java
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/ModuleForTest.java
index c8472de788..8e95bb8c38 100644
---
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/ModuleForTest.java
+++
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/ModuleForTest.java
@@ -23,6 +23,7 @@ import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.jena.fuseki.main.sys.FusekiModule;
+import org.apache.jena.fuseki.server.DataAccessPointRegistry;
import org.apache.jena.rdf.model.Model;
public class ModuleForTest implements FusekiModule {
@@ -30,6 +31,7 @@ public class ModuleForTest implements FusekiModule {
public static ModuleForTest module = null;
public AtomicInteger countStart = new AtomicInteger(0);
+ public AtomicInteger countPrepared = new AtomicInteger(0);
public AtomicInteger countConfiguration = new AtomicInteger(0);
public AtomicInteger countServer = new AtomicInteger(0);
public AtomicInteger countServerBeforeStarting = new AtomicInteger(0);
@@ -49,6 +51,7 @@ public class ModuleForTest implements FusekiModule {
public void clearLifecycle() {
// Not countStart.
countConfiguration.set(0);
+ countPrepared.set(0);
countServer.set(0);
countServerBeforeStarting.set(0);
countServerAfterStarting.set(0);
@@ -61,9 +64,15 @@ public class ModuleForTest implements FusekiModule {
@Override
public void prepare(FusekiServer.Builder builder, Set<String>
datasetNames, Model configModel) {
+ countPrepared.incrementAndGet();
+ }
+
+ @Override
+ public void configured(FusekiServer.Builder serverBuilder,
DataAccessPointRegistry dapRegistry, Model configModel) {
countConfiguration.getAndIncrement();
}
+
// Built, not started, about to be returned to the builder caller
@Override public void server(FusekiServer server) {
countServer.getAndIncrement();
diff --git
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiModules.java
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiModules.java
index 363b47bf7b..0de5a3ecfc 100644
---
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiModules.java
+++
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiModules.java
@@ -19,8 +19,17 @@
package org.apache.jena.fuseki.main;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.jena.fuseki.main.sys.FusekiModule;
import org.apache.jena.fuseki.main.sys.FusekiModules;
+import org.apache.jena.fuseki.main.sys.FusekiModulesLoaded;
+import org.apache.jena.fuseki.main.sys.FusekiModulesSystem;
+import org.apache.jena.rdf.model.Model;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -32,16 +41,19 @@ public class TestFusekiModules {
// file ::
src/test/resources/META-INF/services/org.apache.jena.fuseki.main.sys.FusekiModule
// Module: ModuleForTest
+ private static FusekiModules system = null;
+
@BeforeClass public static void beforeClass() {
- FusekiModules.load();
+ system = FusekiModulesSystem.get();
+ FusekiModulesLoaded.resetSystem();
}
@Before public void beforeTest() {
ModuleForTest.module.clearLifecycle();
}
- @AfterClass public static void afterTest() {
- FusekiModules.remove(ModuleForTest.module);
+ @AfterClass public static void afterClass() {
+ FusekiModulesSystem.set(system);
}
@Test public void modules_0() {
@@ -51,35 +63,101 @@ public class TestFusekiModules {
assertEquals(0, module.countConfiguration.get());
}
+ @Test public void modules_1() {
+ boolean bIsEmpty1 = FusekiModulesLoaded.loaded().asList().isEmpty();
+ assertFalse(bIsEmpty1);
+
+ FusekiModulesLoaded.enable(false);
+
+ boolean bIsEmpty2 =
+ FusekiModulesLoaded.loaded().asList().isEmpty();
+ assertTrue(bIsEmpty2);
+
+ FusekiModulesLoaded.enable(true);
+
+ boolean bIsEmpty3 = FusekiModulesLoaded.loaded().asList().isEmpty();
+ assertFalse(bIsEmpty3);
+ }
+
+ @Test public void modules_2() {
+ boolean bIsEmpty1 = FusekiModulesLoaded.loaded().asList().isEmpty();
+ assertFalse(bIsEmpty1);
+ FusekiModulesLoaded.enable(false);
+ boolean bIsEmpty2 =
+ FusekiModulesLoaded.loaded().asList().isEmpty();
+ assertTrue(bIsEmpty2);
+ }
+
+
+
@Test public void lifecycle_1() {
+ FusekiModulesLoaded.resetSystem();
+
ModuleForTest module = findModule();
+
+ assertFalse(FusekiModulesSystem.get().asList().isEmpty());
+
FusekiServer.Builder builder = FusekiServer.create().port(0);
- assertEquals(1, module.countStart.get());
- assertEquals(0, module.countConfiguration.get());
- assertEquals(0, module.countServer.get());
- assertEquals(0, module.countServerBeforeStarting.get());
+ assertEquals("start:" , 1, module.countStart.get());
+ assertEquals("prepare:", 0, module.countPrepared.get());
+ assertEquals("configured:", 0, module.countConfiguration.get());
+ assertEquals("server: ", 0, module.countServer.get());
+ assertEquals("serverBefore: ", 0,
module.countServerBeforeStarting.get());
+ assertEquals("serverAfter: ", 0,
module.countServerAfterStarting.get());
FusekiServer server = builder.build();
- assertEquals(1, module.countStart.get());
- assertEquals(1, module.countConfiguration.get());
- assertEquals(1, module.countServer.get());
- assertEquals(0, module.countServerBeforeStarting.get());
- assertEquals(0, module.countServerAfterStarting.get());
+
+ assertFalse(server.getModules().asList().isEmpty());
+
+ assertEquals("start:" , 1, module.countStart.get());
+ assertEquals("prepare:", 1, module.countPrepared.getPlain());
+ assertEquals("configured:", 1, module.countConfiguration.get());
+ assertEquals("server: ", 1, module.countServer.get());
+ assertEquals("serverBefore: ", 0,
module.countServerBeforeStarting.get());
+ assertEquals("serverAfter: ", 0,
module.countServerAfterStarting.get());
server.start();
- assertEquals(1, module.countStart.get());
- assertEquals(1, module.countConfiguration.get());
- assertEquals(1, module.countServer.get());
- assertEquals(1, module.countServerBeforeStarting.get());
- assertEquals(1, module.countServerAfterStarting.get());
+ assertEquals("start:" , 1, module.countStart.get());
+ assertEquals("prepare:", 1, module.countPrepared.get());
+ assertEquals("configured:", 1, module.countConfiguration.get());
+ assertEquals("server: ", 1, module.countServer.get());
+ assertEquals("serverBefore: ", 1,
module.countServerBeforeStarting.get());
+ assertEquals("serverAfter: ", 1,
module.countServerAfterStarting.get());
server.stop();
}
+ @Test public void server_module_1() {
+ AtomicBoolean called1 = new AtomicBoolean(false);
+ AtomicBoolean called2 = new AtomicBoolean(false);
+ FusekiModule oneOff = new FusekiModule() {
+ @Override public String name() { return "Local"; }
+ @Override public void prepare(FusekiServer.Builder serverBuilder,
Set<String> datasetNames, Model configModel) {
+ called1.set(true);
+ }
+ @Override public void serverBeforeStarting(FusekiServer server) {
+ called2.set(true);
+ }
+ };
+
+ assertFalse(FusekiModulesLoaded.loaded().asList().contains(oneOff));
+
+ FusekiModules mods = FusekiModules.create(oneOff);
+ assertFalse(called1.get());
+ assertFalse(called2.get());
+ FusekiServer server =
FusekiServer.create().port(0).setModules(mods).build();
+ assertTrue(called1.get());
+ assertFalse(called2.get());
+ try {
+ server.start();
+ assertTrue(called2.get());
+ } finally { server.stop(); }
+ }
+
private ModuleForTest findModule() {
return ModuleForTest.module;
}
diff --git
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExFusekiMain_3_FusekiModule.java
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExFusekiMain_3_FusekiModule.java
index bbfbed77e4..737a690d4f 100644
---
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExFusekiMain_3_FusekiModule.java
+++
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExFusekiMain_3_FusekiModule.java
@@ -24,8 +24,9 @@ import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Set;
-import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
@@ -36,6 +37,7 @@ import org.apache.jena.atlas.io.IO;
import org.apache.jena.fuseki.main.FusekiServer;
import org.apache.jena.fuseki.main.sys.FusekiModule;
import org.apache.jena.fuseki.main.sys.FusekiModules;
+import org.apache.jena.fuseki.main.sys.FusekiModulesLoaded;
import org.apache.jena.fuseki.system.FusekiLogging;
import org.apache.jena.http.HttpEnv;
import org.apache.jena.rdf.model.Model;
@@ -55,13 +57,19 @@ public class ExFusekiMain_3_FusekiModule {
//
// The file is typically put into the jar by having
//
src/main/resources/META-INF/services/org.apache.jena.fuseki.main.sys.FusekiModule
+ // For this example, we add the module directly.
FusekiModule module = new FMod_ProvidePATCH();
- FusekiModules.add(module);
+
+ List<FusekiModule> modules = new ArrayList<>();
+ modules.addAll(FusekiModulesLoaded.loaded().asList());
+ modules.add(module);
+ FusekiModules fusekiModules = FusekiModules.create(modules);
// Create server.
FusekiServer server =
FusekiServer.create()
.port(0)
+ .setModules(fusekiModules)
.build()
.start();
int port = server.getPort();
@@ -77,10 +85,11 @@ public class ExFusekiMain_3_FusekiModule {
static class FMod_ProvidePATCH implements FusekiModule {
- private String modName = UUID.randomUUID().toString();
+ public FMod_ProvidePATCH() {}
+
@Override
public String name() {
- return modName;
+ return "ProvidePATCH";
}
@Override public void prepare(FusekiServer.Builder builder,
Set<String> datasetNames, Model configModel) {
diff --git
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExFuseki_04_CustomOperation_Module.java
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExFuseki_04_CustomOperation_Module.java
index e8ac062846..e913716f35 100644
---
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExFuseki_04_CustomOperation_Module.java
+++
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExFuseki_04_CustomOperation_Module.java
@@ -19,6 +19,7 @@
package org.apache.jena.fuseki.main.examples;
import java.io.IOException;
+import java.util.List;
import java.util.ServiceLoader;
import java.util.Set;
@@ -59,11 +60,13 @@ public class ExFuseki_04_CustomOperation_Module {
// Example usage.
public static void main(String...args) {
- // Imitate FusekiModule service loader behaviour.
- FusekiModules.add(new FMod_Custom());
+ FusekiModule fmodCustom = new FMod_Custom();
+
+ FusekiModules modules = FusekiModules.create(List.of(fmodCustom));
FusekiServer.create().port(3230)
.add("/ds", DatasetGraphFactory.createTxnMem())
+ .setModules(modules)
.build()
.start();
@@ -75,6 +78,10 @@ public class ExFuseki_04_CustomOperation_Module {
private Operation myOperation = null;
+ public FMod_Custom() {
+ myOperation = Operation.alloc("http://example/extra-service",
"extra-service", "Test");
+ }
+
@Override
public String name() {
return "Custom Operation Example";
@@ -82,9 +89,9 @@ public class ExFuseki_04_CustomOperation_Module {
@Override
public void start() {
+ // Only called if loaded via the ServiceLoader.
Fuseki.configLog.info("Add custom operation into global
registry.");
System.err.println("**** Fuseki extension ****");
- myOperation = Operation.alloc("http://example/extra-service",
"extra-service", "Test");
}
@Override