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

commit 61532032de1ee6d762bf996a4bc324cf39bcecc0
Author: Andy Seaborne <[email protected]>
AuthorDate: Mon Nov 25 16:02:10 2024 +0000

    Refactor command line server startup
---
 .../java/org/apache/jena/http/auth/AuthEnv.java    |  7 ++
 .../main/java/org/apache/jena/atlas/io/IOX.java    | 24 +++++++
 .../jena/base/module/SubsystemLifecycle.java       |  4 +-
 .../main/java/org/apache/jena/fuseki/Fuseki.java   |  3 +
 .../apache/jena/fuseki/system/FusekiLogging.java   |  9 ++-
 .../org/apache/jena/fuseki/main/FusekiServer.java  |  6 +-
 .../org/apache/jena/fuseki/main/cmds/DSGSetup.java | 40 +++++++----
 .../apache/jena/fuseki/main/cmds/FusekiMain.java   | 77 ++++++++--------------
 .../apache/jena/fuseki/main/cmds/ServerArgs.java   |  6 +-
 .../apache/jena/fuseki/main/cmds/SetupType.java    | 37 ++++-------
 .../jena/fuseki/main/sys/FusekiAutoModule.java     |  9 +++
 .../jena/fuseki/main/sys/FusekiAutoModules.java    |  8 ++-
 .../jena/fuseki/main/sys/FusekiBuildCycle.java     |  2 +-
 .../apache/jena/fuseki/main/sys/FusekiModule.java  |  6 +-
 .../fuseki/main/TestFusekiMainCmdArguments.java    | 16 +----
 .../main/TestFusekiMainCmdCustomArguments.java     |  2 +-
 .../java/org/apache/jena/rfc3986/URIScheme.java    |  2 +-
 17 files changed, 145 insertions(+), 113 deletions(-)

diff --git a/jena-arq/src/main/java/org/apache/jena/http/auth/AuthEnv.java 
b/jena-arq/src/main/java/org/apache/jena/http/auth/AuthEnv.java
index 828d122f21..2781ce4537 100644
--- a/jena-arq/src/main/java/org/apache/jena/http/auth/AuthEnv.java
+++ b/jena-arq/src/main/java/org/apache/jena/http/auth/AuthEnv.java
@@ -76,6 +76,13 @@ public class AuthEnv {
         return passwordRegistry.contains(location);
     }
 
+    /**
+     * Remove the registration for a URI endpoint.
+     */
+    public void unregisterUsernamePassword(String uri) {
+        unregisterUsernamePassword(URI.create(uri));
+    }
+
     /**
      * Remove the registration for a URI endpoint.
      */
diff --git a/jena-base/src/main/java/org/apache/jena/atlas/io/IOX.java 
b/jena-base/src/main/java/org/apache/jena/atlas/io/IOX.java
index ed78dbbb92..02b09e1bba 100644
--- a/jena-base/src/main/java/org/apache/jena/atlas/io/IOX.java
+++ b/jena-base/src/main/java/org/apache/jena/atlas/io/IOX.java
@@ -318,4 +318,28 @@ public class IOX {
         }
         return null;
     }
+
+    /**
+     * Check whether a file name points to a readable, regular file.
+     * Generate an exception if not.
+     */
+    public static void checkReadableFile(String file, Function<String, 
RuntimeException> exceptionMaker) {
+        Path path = Path.of(file);
+        checkReadableFile(path, exceptionMaker);
+    }
+
+    /**
+     * Check whether a file path points to a readable, regular file.
+     * Generate an exception if not.
+     */
+    public static void checkReadableFile(Path path, Function<String, 
RuntimeException> exceptionMaker) {
+        if ( ! Files.exists(path) )
+            throw exceptionMaker.apply("File not found: "+path);
+        if ( Files.isDirectory(path) )
+            throw exceptionMaker.apply("Is a directory: "+path);
+        if ( !Files.isRegularFile(path) )
+            throw exceptionMaker.apply("Not a regular file: "+path);
+        if ( !Files.isReadable(path) )
+            throw exceptionMaker.apply("Not readable: "+path);
+    }
 }
diff --git 
a/jena-base/src/main/java/org/apache/jena/base/module/SubsystemLifecycle.java 
b/jena-base/src/main/java/org/apache/jena/base/module/SubsystemLifecycle.java
index 703dd6cd6f..3b92d8d9cc 100644
--- 
a/jena-base/src/main/java/org/apache/jena/base/module/SubsystemLifecycle.java
+++ 
b/jena-base/src/main/java/org/apache/jena/base/module/SubsystemLifecycle.java
@@ -34,8 +34,8 @@ public interface SubsystemLifecycle {
     public void stop();
 
     /**
-     * Provide a marker as to the level to order initialization, 10,20,30,... 
See
-     * {@link Subsystem} for details.
+     * Provide a marker as to the level to order initialization, 10,20,30,...
+     * See {@link Subsystem} for details.
      */
     default public int level() {
         return 9999;
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/Fuseki.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/Fuseki.java
index a7ffa72ac9..bd7c26431c 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/Fuseki.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/Fuseki.java
@@ -116,6 +116,9 @@ public class Fuseki {
     /** Instance of log for operations */
     public static final Logger        actionLog         = 
LoggerFactory.getLogger(actionLogName);
 
+    /** Instance of log for operations : alternative variable name */
+    public static final Logger        fusekiLog         = 
LoggerFactory.getLogger(actionLogName);
+
     /** Logger name for standard webserver log file request log */
     public static final String        requestLogName    = PATH + ".Request";
 
diff --git 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/FusekiLogging.java
 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/FusekiLogging.java
index fb8fee87fe..7448f19a01 100644
--- 
a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/FusekiLogging.java
+++ 
b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/FusekiLogging.java
@@ -81,7 +81,7 @@ public class FusekiLogging
             logLogging("Old system property used '%s'", logLoggingPropertyAlt);
             return x.equalsIgnoreCase("true");
         }
-        x = Lib.getenv("FUSEKI_LOGLOGGING", logLoggingProperty);
+        x = Lib.getenv(logLoggingProperty, envLogLoggingProperty);
         return x != null && x.equalsIgnoreCase("true");
     }
 
@@ -137,11 +137,16 @@ public class FusekiLogging
         }
 
         logLogging("Setup");
+
+        // NB Search for a file before looking on the classpath.
+        // This allows the file to override any built-in logging configuration.
+        // However, in tests, this means a development file "log4j2.properties"
+        // may get picked up.
+
         // Look for a log4j2.properties file in the current working directory
         // and a place (e.g. FUSEKI_BASE in the webapp/full server) for easy 
customization.
         String fn1 = "log4j2.properties";
         String fn2 = null;
-
         if ( extraDir != null )
             fn2 = extraDir.resolve("log4j2.properties").toString();
         if ( attempt(fn1) ) return;
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 40b968e9f2..9ed7ef42b0 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
@@ -520,6 +520,11 @@ public class FusekiServer {
         /** Set the location (filing system directory) to serve static files 
from. */
         public Builder staticFileBase(String directory) {
             requireNonNull(directory, "directory");
+            if ( directory.startsWith("jar:") ) {
+                // jetty resource
+                this.staticContentDir = directory;
+                return this;
+            }
             if ( ! FileOps.exists(directory) )
                 Fuseki.configLog.warn("File area not found: "+directory);
             // Resolve path.
@@ -837,7 +842,6 @@ public class FusekiServer {
             x.forEach(dap->addDataAccessPoint(dap));
         }
 
-
         /** Add a {@link DataAccessPoint} as a builder. */
         private Builder addDataAccessPoint(DataAccessPoint dap) {
             if ( isRegistered(dap.getName()) )
diff --git 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/DSGSetup.java
 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/DSGSetup.java
index 763d33af7a..c55296c6ab 100644
--- 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/DSGSetup.java
+++ 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/DSGSetup.java
@@ -27,7 +27,9 @@ import org.apache.jena.atlas.io.IO;
 import org.apache.jena.atlas.lib.FileOps;
 import org.apache.jena.cmd.CmdException;
 import org.apache.jena.fuseki.system.spot.TDBOps;
+import org.apache.jena.graph.Graph;
 import org.apache.jena.query.Dataset;
+import org.apache.jena.rdfs.RDFSFactory;
 import org.apache.jena.riot.Lang;
 import org.apache.jena.riot.RDFDataMgr;
 import org.apache.jena.riot.RDFLanguages;
@@ -40,9 +42,16 @@ import org.slf4j.Logger;
 
 /**
  * Various ways to build a dataset from command line arguments.
+ *
+ * @implNote
+ * This code is extracted so as to keep {@link FusekiMain} more manageable.
  */
 
 /*package*/ class DSGSetup {
+    // Each setup* should set ensure
+    //   serverArgs.datasetDescription
+    //   serverArgs.dataset
+    // are set on exit.
 
     /**
      * Given a path name and a preference of TDB1/TDB2 for new databases, 
return
@@ -71,27 +80,28 @@ import org.slf4j.Logger;
         if ( TDBOps.isTDB1(directory) ) {
             setupTDB1(log, directory, serverArgs);
             return;
-        } else if ( TDBOps.isTDB2(directory) ) {
+        }
+        if ( TDBOps.isTDB2(directory) ) {
             setupTDB2(log, directory, serverArgs);
             return;
-        } else
-            throw new CmdException("Directory not a database: " + directory);
+        }
+        throw new CmdException("Directory not a database: " + directory);
     }
 
     private static void setupTDB1(Logger log, String directory, ServerArgs 
serverArgs) {
         serverArgs.datasetDescription = "TDB1 dataset: location="+directory;
-        serverArgs.dsg = TDB1Factory.createDatasetGraph(directory);
+        serverArgs.dataset = TDB1Factory.createDatasetGraph(directory);
     }
 
     private static void setupTDB2(Logger log, String directory, ServerArgs 
serverArgs) {
         serverArgs.datasetDescription = "TDB2 dataset: location="+directory;
-        serverArgs.dsg = DatabaseMgr.connectDatasetGraph(directory);
+        serverArgs.dataset = DatabaseMgr.connectDatasetGraph(directory);
     }
 
     /*package*/ static void setupMemTDB(Logger log, boolean useTDB2, 
ServerArgs serverArgs) {
         String tag = useTDB2 ? "TDB2" : "TDB1";
         serverArgs.datasetDescription = tag+" dataset in-memory";
-        serverArgs.dsg = useTDB2
+        serverArgs.dataset = useTDB2
             ? DatabaseMgr.createDatasetGraph()
             : TDB1Factory.createDatasetGraph();
         serverArgs.allowUpdate = true;
@@ -99,13 +109,13 @@ import org.slf4j.Logger;
 
     /*package*/ static void setupMem(Logger log, ServerArgs serverArgs) {
         serverArgs.datasetDescription = "in-memory";
-        serverArgs.dsg = DatasetGraphFactory.createTxnMem();
+        serverArgs.dataset = DatasetGraphFactory.createTxnMem();
         serverArgs.allowUpdate = true;
     }
 
     /*package*/ static void setupFile(Logger log, List<String> filenames, 
ServerArgs serverArgs) {
         serverArgs.datasetDescription = "in-memory, with files loaded";
-        serverArgs.dsg = DatasetGraphFactory.createTxnMem();
+        serverArgs.dataset = DatasetGraphFactory.createTxnMem();
 
         for ( String filename : filenames ) {
             String pathname = filename;
@@ -118,21 +128,27 @@ import org.slf4j.Logger;
             Lang language = RDFLanguages.filenameToLang(filename);
             if ( language == null )
                 throw new CmdException("Cannot guess language for file: " + 
filename);
-            Txn.executeWrite(serverArgs.dsg,  ()-> {
+            Txn.executeWrite(serverArgs.dataset,  ()-> {
                 try {
                     log.info("Dataset: in-memory: load file: " + filename);
-                    RDFDataMgr.read(serverArgs.dsg, filename);
+                    RDFDataMgr.read(serverArgs.dataset, filename);
                 } catch (RiotException ex) {
                     throw new CmdException("Failed to load file: " + filename);
                 }
             });
         }
-
     }
 
     public static void setupAssembler(Logger log, ModDatasetAssembler 
modDataset, ServerArgs serverArgs) {
         serverArgs.datasetDescription = "Assembler: "+ 
modDataset.getAssemblerFile();
         Dataset ds = modDataset.createDataset();
-        serverArgs.dsg = ds.asDatasetGraph();
+        serverArgs.dataset = ds.asDatasetGraph();
+    }
+
+    public static void setupRDFS(Logger serverlog, Graph rdfsSchemaGraph, 
ServerArgs serverArgs) {
+        serverArgs.datasetDescription = (serverArgs.datasetDescription == null)
+                ? "RDFS"
+                : serverArgs.datasetDescription+ " (with RDFS)";
+        serverArgs.dataset = RDFSFactory.datasetRDFS(serverArgs.dataset, 
rdfsSchemaGraph);
     }
 }
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 c6832a8d94..b7a754cd64 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
@@ -19,10 +19,9 @@
 package org.apache.jena.fuseki.main.cmds;
 
 import static arq.cmdline.ModAssembler.assemblerDescDecl;
-import static org.apache.jena.fuseki.main.cmds.FusekiMain.SetupType.*;
+import static org.apache.jena.fuseki.main.cmds.SetupType.*;
 
 import java.net.BindException;
-import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.List;
 import java.util.Objects;
@@ -31,8 +30,8 @@ import java.util.function.Consumer;
 import arq.cmdline.CmdARQ;
 import arq.cmdline.ModDatasetAssembler;
 import org.apache.jena.assembler.exceptions.AssemblerException;
+import org.apache.jena.atlas.io.IOX;
 import org.apache.jena.atlas.lib.FileOps;
-import org.apache.jena.atlas.logging.FmtLog;
 import org.apache.jena.atlas.web.AuthScheme;
 import org.apache.jena.cmd.*;
 import org.apache.jena.fuseki.Fuseki;
@@ -51,7 +50,6 @@ 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.query.ARQ;
-import org.apache.jena.rdfs.RDFSFactory;
 import org.apache.jena.riot.RDFDataMgr;
 import org.apache.jena.riot.RDFParser;
 import org.apache.jena.sys.JenaSystem;
@@ -318,15 +316,6 @@ public class FusekiMain extends CmdARQ {
         return getCommandName() + " " + argUsage;
     }
 
-    // Command line DSG
-    enum SetupType { UNSET,
-                   MEM, FILE, TDB, MEMTDB,  // Datasets on the command line
-                   CONF,                    // Configuration file.
-                   ASSEM,                   // Assembler for a datasets. 
Legacy.
-                   NONE,                   // Explicitly no dataset or 
configurtion file.
-                   SPARQLer                 // SPARQler mode
-    }
-
     @Override
     protected void processModulesAndArgs() {
         Logger log = Fuseki.serverLog;
@@ -338,8 +327,6 @@ public class FusekiMain extends CmdARQ {
     }
 
     private void processStdArguments(Logger log) {
-        // Allow, but not require, no dataset or configuration
-        boolean allowEmpty = serverArgs.allowEmpty;
 
         // ---- Definition type
         int numDefinitions = 0;
@@ -380,7 +367,7 @@ public class FusekiMain extends CmdARQ {
 
         // ---- Validation
 
-        if ( setup == UNSET && allowEmpty )
+        if ( setup == UNSET && serverArgs.allowEmpty )
             setup = NONE;
 
         // Starting empty.
@@ -398,10 +385,9 @@ public class FusekiMain extends CmdARQ {
         if ( ! startEmpty && numDefinitions == 0 )
             throw new CmdException("No dataset or configuration specified on 
the command line");
 
-        // Configuration file OR dataset
-
+        // Configuration file OR command line dataset
         if ( contains(argConfig) ) {
-            // Invalid combination: --conf + service name.
+            // Invalid combination: --conf + arguments related to command line 
setup.
             if ( ! getPositional().isEmpty() )
                 throw new CmdException("Can't have both a configuration file 
and a service name");
             if ( contains(argRDFS) )
@@ -421,14 +407,16 @@ public class FusekiMain extends CmdARQ {
                 serverArgs.datasetPath = 
DataAccessPoint.canonical(getPositionalArg(0));
         }
 
-        serverArgs.datasetDescription = "<unset>";
-
         // ---- check: Invalid: --update + --conf
         if ( contains(argUpdate) && contains(argConfig) )
             throw new CmdException("--update and a configuration file does not 
make sense (control using the configuration file only)");
         boolean allowUpdate = contains(argUpdate);
         serverArgs.allowUpdate = allowUpdate;
 
+        // -- Record the choice.
+        serverArgs.setup = setup;
+        serverArgs.datasetDescription = "<unset>";
+
         // ---- Dataset
         // A server has one of the command line dataset setups or a 
configuration file,
         // or "--empty" or "--sparqler"
@@ -485,9 +473,7 @@ public class FusekiMain extends CmdARQ {
             String rdfsVocab = getValue(argRDFS);
             if ( !FileOps.exists(rdfsVocab) )
                 throw new CmdException("No such file for RDFS: "+rdfsVocab);
-            serverArgs.rdfsGraph = RDFDataMgr.loadGraph(rdfsVocab);
-            serverArgs.datasetDescription = serverArgs.datasetDescription+ " 
(with RDFS)";
-            serverArgs.dsg = RDFSFactory.datasetRDFS(serverArgs.dsg, 
serverArgs.rdfsGraph);
+            serverArgs.rdfsSchemaGraph = RDFDataMgr.loadGraph(rdfsVocab);
         }
 
         // ---- Misc features.
@@ -643,6 +629,7 @@ public class FusekiMain extends CmdARQ {
     @Override
     protected void exec() {
         // Arguments have been processed to set serverArgs
+        // Check for command line or config setup.
         try {
             Logger log = Fuseki.serverLog;
             FusekiMainInfo.logServerCode(log);
@@ -681,20 +668,14 @@ public class FusekiMain extends CmdARQ {
      */
     private FusekiServer makeServer(ServerArgs serverArgs) {
         FusekiServer.Builder builder = FusekiServer.create();
-        return buildServer(builder, serverArgs);
-    }
-
-    /**
-     * Process {@link ServerArgs} and build a server.
-     * The server has not been started.
-     */
-    private FusekiServer buildServer(FusekiServer.Builder builder, ServerArgs 
serverArgs) {
         applyServerArgs(builder, serverArgs);
         return builder.build();
     }
 
     /** Apply {@link ServerArgs} to a {@link FusekiServer.Builder}. */
     private void applyServerArgs(FusekiServer.Builder builder, ServerArgs 
serverArgs) {
+        boolean commandLineSetup = ( serverArgs.dataset != null || 
serverArgs.dsgMaker != null );
+
         if ( serverArgs.jettyConfigFile != null )
             builder.jettyServerConfig(serverArgs.jettyConfigFile);
         builder.port(serverArgs.port);
@@ -714,6 +695,10 @@ public class FusekiMain extends CmdARQ {
         }
 
         // Apply argument for the database services
+        // if not empty
+        //   If there is a config model - use that (ignore command line 
dataset)
+        //   If there is a config file - load and use that (ignore command 
line dataset)
+        //   Command line.
         if ( ! serverArgs.startEmpty ) {
             if (serverArgs.serverConfigModel != null ) {
                 // -- Customiser has already set the configuration model
@@ -721,32 +706,35 @@ public class FusekiMain extends CmdARQ {
                 serverArgs.datasetDescription = "Configuration: provided";
             } else if ( serverArgs.serverConfigFile != null ) {
                 // -- Configuration file.
-                // if there is a configuration file, read it.
                 String file = serverArgs.serverConfigFile;
                 if ( file.startsWith("file:") )
                     file = file.substring("file:".length());
                 Path path = Path.of(file);
-                if ( ! Files.exists(path) )
-                    throw new CmdException("File not found: "+file);
-                if ( Files.isDirectory(path) )
-                    throw new CmdException("Is a directory: "+file);
+                IOX.checkReadableFile(file, msg->new CmdException(msg));
                 serverArgs.datasetDescription = "Configuration: 
"+path.toAbsolutePath();
                 serverArgs.serverConfigModel = 
RDFParser.source(path).toModel();
                 // ... and perform server configuration
                 builder.parseConfig(serverArgs.serverConfigModel);
             } else {
+                // No serverConfigFile, no serverConfigModel.
                 // -- A dataset setup by command line arguments.
                 if ( serverArgs.datasetPath == null )
                     throw new CmdException("No URL path name for the dataset");
                 // The dataset setup by command line arguments.
                 // A customizer may have set the dataset.
-                if ( serverArgs.dsg == null )
+                if ( serverArgs.dataset == null ) {
+                    // The dsgMaker should set serverArgs.dataset and 
serverArgs.datasetDescription
                     serverArgs.dsgMaker.accept(serverArgs);
-                // Should have been set somehow by this point.
-                if ( serverArgs.dsg == null )
+                }
+                // This should have been set somehow by this point.
+                if ( serverArgs.dataset == null )
                     // Internal error: should have happened during checking 
earlier.
                     throw new CmdException("Failed to set the dataset 
service");
-                builder.add(serverArgs.datasetPath, serverArgs.dsg, 
serverArgs.allowUpdate);
+                // RDFS -- Command line - add RDFS
+                if ( serverArgs.rdfsSchemaGraph != null ) {
+                    DSGSetup.setupRDFS(Fuseki.serverLog, 
serverArgs.rdfsSchemaGraph, serverArgs);
+                }
+                builder.add(serverArgs.datasetPath, serverArgs.dataset, 
serverArgs.allowUpdate);
             }
         }
 
@@ -795,13 +783,6 @@ public class FusekiMain extends CmdARQ {
         if ( super.isQuiet() )
             return;
 
-        if ( serverArgs.startEmpty ) {
-            FmtLog.info(log, "No SPARQL dataset services");
-        } else {
-            if ( serverArgs.datasetPath == null && 
serverArgs.serverConfigModel == null )
-                log.error("No dataset path or server configuration file");
-        }
-
         DataAccessPointRegistry dapRegistry = 
DataAccessPointRegistry.get(server.getServletContext());
         if ( serverArgs.datasetPath != null ) {
             if ( dapRegistry.size() != 1 )
diff --git 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/ServerArgs.java
 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/ServerArgs.java
index 930147ca36..d627adddc9 100644
--- 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/ServerArgs.java
+++ 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/ServerArgs.java
@@ -65,10 +65,11 @@ public class ServerArgs {
     public boolean withCompact            = false;
 
     // Either a dataset setup from the command line (delayed creation of the 
dataset) ...
+    // The consumer should set the "dataset" field and the description field.
     public Consumer<ServerArgs> dsgMaker  = null;
-    public DatasetGraph dsg               = null;
+    public DatasetGraph dataset           = null;
     /** RDFS dataset - only when dataset is defined on the command line. */
-    public Graph rdfsGraph                = null;
+    public Graph rdfsSchemaGraph          = null;
 
     // ... or configuration file.
     public String serverConfigFile        = null;
@@ -76,6 +77,7 @@ public class ServerArgs {
 
     /** Allow no datasets without it being an error. This is not an argument. 
*/
     public boolean allowEmpty             = false;
+    public SetupType setup                = SetupType.UNSET;
     /** Start without a dataset or configuration (this is {@code --empty}) */
     public boolean startEmpty             = false;
 
diff --git 
a/jena-base/src/main/java/org/apache/jena/base/module/SubsystemLifecycle.java 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/SetupType.java
similarity index 52%
copy from 
jena-base/src/main/java/org/apache/jena/base/module/SubsystemLifecycle.java
copy to 
jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/SetupType.java
index 703dd6cd6f..9a84afb54b 100644
--- 
a/jena-base/src/main/java/org/apache/jena/base/module/SubsystemLifecycle.java
+++ 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/SetupType.java
@@ -1,4 +1,4 @@
-/**
+/*
  * 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
@@ -16,29 +16,14 @@
  * limitations under the License.
  */
 
-package org.apache.jena.base.module;
-
-/** Lifecycle interface for modules and subsystems. */
-public interface SubsystemLifecycle {
-
-    /**
-     * start - a module should be ready to operate when this returns.
-     */
-    public void start();
-
-    /**
-     * stop - a module should have performed any shutdown operations by the 
time this
-     * returns. Caution: code must be prepared to operate without assuming this
-     * called. Abrupt termination of the JVM is always possible.
-     */
-    public void stop();
-
-    /**
-     * Provide a marker as to the level to order initialization, 10,20,30,... 
See
-     * {@link Subsystem} for details.
-     */
-    default public int level() {
-        return 9999;
-    }
-}
+package org.apache.jena.fuseki.main.cmds;
 
+// Command line DSG
+public enum SetupType {
+    UNSET,
+    MEM, FILE, TDB, MEMTDB,  // Datasets on the command line
+    CONF,                    // Configuration file.
+    ASSEM,                   // Assembler for a datasets. Legacy.
+    NONE,                    // Explicitly no dataset or configuration file.
+    SPARQLer                 // SPARQler mode
+}
\ No newline at end of file
diff --git 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiAutoModule.java
 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiAutoModule.java
index 1b43f5c69e..426d417bf4 100644
--- 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiAutoModule.java
+++ 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiAutoModule.java
@@ -79,6 +79,15 @@ public interface FusekiAutoModule extends FusekiModule, 
FusekiLifecycle {
     @Override
     public default void stop() {}
 
+    /**
+     * Level for ordering calling all loaded {@code FusekiAutoModule}.
+     * Levels 0-999 are reserved and should not be used except by system 
FusekiAutoModule
+     */
+    @Override
+    public default int level() {
+        return 9999;
+    }
+
     // ---- Build cycle
 
     /** {@inheritDoc} */
diff --git 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiAutoModules.java
 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiAutoModules.java
index 59b57e6465..5c94e9841b 100644
--- 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiAutoModules.java
+++ 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiAutoModules.java
@@ -218,9 +218,11 @@ public class FusekiAutoModules {
                 String name = m.name();
                 if ( name == null )
                     name = m.getClass().getSimpleName();
-                FmtLog.info(LOG, "Module: %s (%s)",
-                                 name,
-                                 
Version.versionForClass(m.getClass()).orElse("unknown"));
+                String verStr = 
Version.versionForClass(m.getClass()).orElse(null);
+                if ( verStr == null )
+                    FmtLog.info(LOG, "Module: %s", name);
+                else
+                    FmtLog.info(LOG, "Module: %s (%s)", name, verStr);
             });
 
             return FusekiModules.create(fmods);
diff --git 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiBuildCycle.java
 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiBuildCycle.java
index 9263a8b6a8..33f865b3b1 100644
--- 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiBuildCycle.java
+++ 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiBuildCycle.java
@@ -43,7 +43,7 @@ import org.apache.jena.rdf.model.Model;
  */
 public interface FusekiBuildCycle {
     /**
-     * Display name to identify this module.
+     * A display name to identify this module.
      */
     public String name();
 
diff --git 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModule.java
 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModule.java
index 63196f2b31..f18cafc23b 100644
--- 
a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModule.java
+++ 
b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiModule.java
@@ -60,8 +60,12 @@ public interface FusekiModule extends 
FusekiServerArgsCustomiser, FusekiBuildCyc
     // Gather all interface method together.
     // Inherited javadoc.
 
+    /**
+     * {@inheritDoc}
+     * <p>This defaults to the Java simple class name of module.
+     */
     @Override
-    public String name();
+    public default String name() { return null; }
 
     // ---- Build cycle
 
diff --git 
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmdArguments.java
 
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmdArguments.java
index 8a22316519..f8afce0dc1 100644
--- 
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmdArguments.java
+++ 
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmdArguments.java
@@ -281,8 +281,8 @@ public class TestFusekiMainCmdArguments {
     @Test
     public void test_error_configFile_directory() {
         // given
-        List<String> arguments = List.of("--config=testing/");
-        String expectedMessage = "Is a directory: testing/";
+        List<String> arguments = List.of("--config=testing");
+        String expectedMessage = "Is a directory: testing";
         // when, then
         testForCmdException(arguments, expectedMessage);
     }
@@ -323,7 +323,6 @@ public class TestFusekiMainCmdArguments {
         testForCmdException(arguments, expectedMessage);
     }
 
-
     @Test
     public void test_error_argConfigFile_UnrecognisedFileType() {
         // given
@@ -362,7 +361,6 @@ public class TestFusekiMainCmdArguments {
         testForCmdException(arguments, expectedMessage);
     }
 
-
     @Test
     public void test_error_incorrectContextPath() {
         // given
@@ -447,19 +445,11 @@ public class TestFusekiMainCmdArguments {
 
     private void testForCmdException(List<String> arguments, String 
expectedMessage) {
         // when
-        Throwable actual = null;
-        try {
-            buildServer(buildCmdLineArguments(arguments));
-        } catch (Exception e) {
-            actual = e;
-        }
+        CmdException actual = assertThrows(CmdException.class, 
()->buildServer(buildCmdLineArguments(arguments)));
         // then
-        assertNotNull(actual);
-        assertTrue("Expecting correct exception", (actual instanceof 
CmdException));
         assertEquals("Expecting correct message", expectedMessage, 
actual.getMessage());
     }
 
-
     private static String[] buildCmdLineArguments(List<String> listArgs) {
         return listArgs.toArray(new String[0]);
     }
diff --git 
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmdCustomArguments.java
 
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmdCustomArguments.java
index 2527fee741..e2708b153d 100644
--- 
a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmdCustomArguments.java
+++ 
b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainCmdCustomArguments.java
@@ -246,7 +246,7 @@ public class TestFusekiMainCmdCustomArguments {
             if ( argSeen ) {
                 serverArgs.serverConfigModel = fixedModel;
                 notedServerConfigModel = fixedModel;
-                serverArgs.dsg = null;
+                serverArgs.dataset = null;
             }
         }
 
diff --git a/jena-iri3986/src/main/java/org/apache/jena/rfc3986/URIScheme.java 
b/jena-iri3986/src/main/java/org/apache/jena/rfc3986/URIScheme.java
index e63e76fb84..db6f7f2ae3 100644
--- a/jena-iri3986/src/main/java/org/apache/jena/rfc3986/URIScheme.java
+++ b/jena-iri3986/src/main/java/org/apache/jena/rfc3986/URIScheme.java
@@ -109,7 +109,7 @@ public enum URIScheme {
         };
     }
 
-    /** Scheme name */
+    /** Scheme name; no ':' */
     public String getSchemeName() {
         return schemeName;
     }

Reply via email to