diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/FusekiServerCmd.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/FusekiServerCmd.java index 2c61c0ed09b..2a12ca2a17e 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/FusekiServerCmd.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/cmds/FusekiServerCmd.java @@ -18,7 +18,7 @@ package org.apache.jena.fuseki.main.cmds; -import org.apache.jena.fuseki.run.FusekiModServer; +import org.apache.jena.fuseki.mod.FusekiModServer; import org.apache.jena.fuseki.system.FusekiLogging; /** Fuseki command that runs a Fuseki server with the admin UI. diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/ActionBackupList.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/ActionBackupList.java index 1e52a65b696..f7d0fc446a0 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/ActionBackupList.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/ActionBackupList.java @@ -66,11 +66,11 @@ public void execute(HttpAction action) { }; private JsonValue description(HttpAction action) { - if ( ! Files.isDirectory(FusekiApp.dirBackups) ) - ServletOps.errorOccurred(format("[%d] Backup area '%s' is not a directory", action.id, FusekiApp.dirBackups)); + if ( ! Files.isDirectory(FusekiServerCtl.dirBackups) ) + ServletOps.errorOccurred(format("[%d] Backup area '%s' is not a directory", action.id, FusekiServerCtl.dirBackups)); List paths = new ArrayList<>(); - try (DirectoryStream stream = Files.newDirectoryStream(FusekiApp.dirBackups, filterVisibleFiles)) { + try (DirectoryStream stream = Files.newDirectoryStream(FusekiServerCtl.dirBackups, filterVisibleFiles)) { stream.forEach(paths::add); } catch (IOException ex) { action.log.error(format("[%d] Backup file list :: IOException :: %s", action.id, ex.getMessage())); diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java index 7630b8c6f02..ba1e95a3302 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/ActionDatasets.java @@ -140,7 +140,7 @@ else if ( WebContent.isMultiPartForm(ct) ) // ---- // Keep a persistent copy immediately. This is not used for // anything other than being "for the record". - systemFileCopy = FusekiApp.dirSystemFileArea.resolve(uuid.toString()).toString(); + systemFileCopy = FusekiServerCtl.dirSystemFileArea.resolve(uuid.toString()).toString(); try ( OutputStream outCopy = IO.openOutputFile(systemFileCopy) ) { RDFDataMgr.write(outCopy, descriptionModel, Lang.TURTLE); } @@ -186,8 +186,8 @@ else if ( WebContent.isMultiPartForm(ct) ) action.log.info(format("[%d] Create database : name = %s", action.id, datasetPath)); - configFile = FusekiApp.generateConfigurationFilename(datasetPath); - List existing = FusekiApp.existingConfigurationFile(datasetPath); + configFile = FusekiServerCtl.generateConfigurationFilename(datasetPath); + List existing = FusekiServerCtl.existingConfigurationFile(datasetPath); if ( ! existing.isEmpty() ) ServletOps.error(HttpSC.CONFLICT_409, "Configuration file for '"+datasetPath+"' already exists"); @@ -318,7 +318,7 @@ protected void execDeleteItem(HttpAction action) { // Find the configuration. String filename = name.startsWith("/") ? name.substring(1) : name; - List configurationFiles = FusekiApp.existingConfigurationFile(filename); + List configurationFiles = FusekiServerCtl.existingConfigurationFile(filename); if ( configurationFiles.isEmpty() ) { // ---- Unmanaged @@ -363,7 +363,7 @@ protected void execDeleteItem(HttpAction action) { // Delete databases created by the UI, or the admin operation, which are // in predictable, unshared location on disk. // There may not be any database files, the in-memory case. - Path pDatabase = FusekiApp.dirDatabases.resolve(filename); + Path pDatabase = FusekiServerCtl.dirDatabases.resolve(filename); if ( Files.exists(pDatabase)) { try { if ( Files.isSymbolicLink(pDatabase)) { @@ -411,7 +411,7 @@ private static void assemblerFromForm(HttpAction action, StreamRDF dest) { params.put(Template.NAME, dbName.substring(1)); else params.put(Template.NAME, dbName); - FusekiApp.addGlobals(params); + FusekiServerCtl.addGlobals(params); //action.log.info(format("[%d] Create database : name = %s, type = %s", action.id, dbName, dbType )); diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/Backup.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/Backup.java index 70ea5f51563..ea661c7ae6a 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/Backup.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/Backup.java @@ -54,7 +54,7 @@ public static String chooseFileName(String dsName) { String timestamp = DateTimeUtils.nowAsString("yyyy-MM-dd_HH-mm-ss"); String filename = ds + "_" + timestamp; - filename = FusekiApp.dirBackups.resolve(filename).toString(); + filename = FusekiServerCtl.dirBackups.resolve(filename).toString(); return filename; } diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/FusekiApp.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/FusekiServerCtl.java similarity index 77% rename from jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/FusekiApp.java rename to jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/FusekiServerCtl.java index d6cd0dc5708..37101571224 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/FusekiApp.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/FusekiServerCtl.java @@ -56,24 +56,33 @@ import org.apache.jena.sparql.core.assembler.AssemblerUtils; import org.apache.jena.system.G; -public class FusekiApp { +public class FusekiServerCtl { + /** + * Root of the varying files in this deployment. Often $PWD/run. + * This location must be writable. + */ + public static Path FUSEKI_BASE = null; + + public static final String DFT_SHIRO_INI = "shiro.ini"; + public static final String envFusekiBase = "FUSEKI_BASE"; + public static final String envFusekiShiro = "FUSEKI_SHIRO"; + // Relative names of directories in the FUSEKI_BASE area. - public static final String databasesLocationBase = "databases"; + private static final String databasesLocationBase = "databases"; // Place to put Lucene text and spatial indexes. - //private static final String databaseIndexesDir = "indexes"; + private static final String databaseIndexesDir = "text_indexes"; - public static final String backupDirNameBase = "backups"; - public static final String configDirNameBase = "configuration"; - public static final String logsNameBase = "logs"; - public static final String systemFileAreaBase = "system_files"; - public static final String templatesNameBase = "templates"; - public static final String DFT_SHIRO_INI = "shiro.ini"; - public static final String DFT_CONFIG = "config.ttl"; + private static final String backupDirNameBase = "backups"; + private static final String configDirNameBase = "configuration"; + private static final String logsNameBase = "logs"; + private static final String systemFileAreaBase = "system_files"; + private static final String templatesNameBase = "templates"; + private static final String DFT_CONFIG = "config.ttl"; - private static int BaseFusekiAutoModuleLevel = 500; - public static int levelFModAdmin = BaseFusekiAutoModuleLevel; - public static int levelFModUI = BaseFusekiAutoModuleLevel+10; - public static int levelFModShiro = BaseFusekiAutoModuleLevel+20; + private static int BaseFusekiAutoModuleLevel = 500; + public static int levelFModAdmin = BaseFusekiAutoModuleLevel; + public static int levelFModUI = BaseFusekiAutoModuleLevel+10; + public static int levelFModShiro = BaseFusekiAutoModuleLevel+20; /** Directory for TDB databases - this is known to the assembler templates */ @@ -88,9 +97,6 @@ public class FusekiApp { /** Directory for assembler files */ public static Path dirLogs = null; -// /** Directory for system database */ -// public static Path dirSystemDatabase = null; - /** Directory for files uploaded (e.g upload assembler descriptions); not data uploads. */ public static Path dirSystemFileArea = null; @@ -101,24 +107,51 @@ public class FusekiApp { // Marks the end of successful initialization. /*package*/static boolean serverInitialized = false; - - -// /** +// /** OLD // * Root of the Fuseki installation for fixed files. // * This may be null (e.g. running inside a web application container) // */ // public static Path FUSEKI_HOME = null; - /** - * Root of the varying files in this deployment. Often $PWD/run. - * This must be writable. - */ - public static Path FUSEKI_BASE = set_FUSEKI_BASE(); + // Too much is done with statics, assuming one server+admin process + // At the moment, it is one setup happening at a time. + // Once created, it is independent. + // Better, less statics, more FusekiServerApp instance object. + // Current limitation: FUSEKI_BASE is static and set in + // FusekiApp.java line 275 + // ArgModuleAdmin.java line 61 + // FMod_Admin.java line 117 + // FMod_UI.java line 133 + // Template.java line 27 + // ActionDadasets uses addGlobals. + + // Default - "run" in the current directory. + public static final String dftFusekiBase = "run"; + + public FusekiServerCtl(String location) { + if ( location == null ) { + FUSEKI_BASE = null; + return; + } + FUSEKI_BASE = Path.of(location); + } - public static String envFusekiBase = "FUSEKI_BASE"; - public static String envFusekiShiro = "FUSEKI_SHIRO"; + public Path setup() { + // Set the location of the BASE area + setFusekiBase(); + // Ensure the BASE area exists on disk. + setBaseAreaOnDisk(); + // Format the BASE area. + ensureBaseArea(FUSEKI_BASE); + return FUSEKI_BASE; + } - private static Path set_FUSEKI_BASE() { + private void setFusekiBase() { + if ( FUSEKI_BASE == null ) + FUSEKI_BASE = select_FUSEKI_BASE(); + } + + private Path select_FUSEKI_BASE() { // Does not guarantee existence Path setting = null; if ( FUSEKI_BASE == null ) @@ -127,20 +160,14 @@ private static Path set_FUSEKI_BASE() { return setting; } - private static Path calc_FUSEKI_BASE() { + private Path calc_FUSEKI_BASE() { String valueFusekiBase = getenv("FUSEKI_BASE"); if ( valueFusekiBase == null ) valueFusekiBase = dftFusekiBase; return Path.of(valueFusekiBase); } - // Default - "run" in the current directory. - public static final String dftFusekiBase = "run"; - - static void setEnvironment() { - if ( FUSEKI_BASE == null ) - FUSEKI_BASE = set_FUSEKI_BASE(); - + private void setBaseAreaOnDisk() { FmtLog.info(Fuseki.configLog, "FUSEKI_BASE=%s", FUSEKI_BASE); if ( ! Files.exists(FUSEKI_BASE) ) { try { @@ -152,96 +179,44 @@ static void setEnvironment() { // Further checks in ensureBaseArea } - public static Path setup() { - // Command line arguments "--base" ... - setEnvironment(); - // Format the BASE area. - FusekiApp.ensureBaseArea(FUSEKI_BASE); - return FUSEKI_BASE; - } - /** * Create directories if found to be missing. */ - public static void ensureBaseArea(Path FUSEKI_BASE) { - if ( Files.exists(FUSEKI_BASE) ) { - if ( ! Files.isDirectory(FUSEKI_BASE) ) - throw new FusekiConfigException("FUSEKI_BASE is not a directory: "+FUSEKI_BASE); - if ( ! Files.isWritable(FUSEKI_BASE) ) - throw new FusekiConfigException("FUSEKI_BASE is not writable: "+FUSEKI_BASE); + private void ensureBaseArea(Path baseArea) { + if ( Files.exists(baseArea) ) { + if ( ! Files.isDirectory(baseArea) ) + throw new FusekiConfigException("FUSEKI_BASE is not a directory: "+baseArea); + if ( ! Files.isWritable(baseArea) ) + throw new FusekiConfigException("FUSEKI_BASE is not writable: "+baseArea); } else { - ensureDir(FUSEKI_BASE); + ensureDir(baseArea); } // Ensure FUSEKI_BASE has the assumed directories. - dirTemplates = writeableDirectory(FUSEKI_BASE, templatesNameBase); - dirDatabases = writeableDirectory(FUSEKI_BASE, databasesLocationBase); - dirBackups = writeableDirectory(FUSEKI_BASE, backupDirNameBase); - dirConfiguration = writeableDirectory(FUSEKI_BASE, configDirNameBase); - dirLogs = writeableDirectory(FUSEKI_BASE, logsNameBase); - dirSystemFileArea = writeableDirectory(FUSEKI_BASE, systemFileAreaBase); + dirTemplates = writeableDirectory(baseArea, templatesNameBase); + dirDatabases = writeableDirectory(baseArea, databasesLocationBase); + dirBackups = writeableDirectory(baseArea, backupDirNameBase); + dirConfiguration = writeableDirectory(baseArea, configDirNameBase); + dirLogs = writeableDirectory(baseArea, logsNameBase); + dirSystemFileArea = writeableDirectory(baseArea, systemFileAreaBase); // ---- Initialize with files. // // Copy missing files into FUSEKI_BASE // Interacts with FMod_Shiro. - if ( Lib.getenv(FusekiApp.envFusekiShiro) == null ) { - copyFileIfMissing(null, DFT_SHIRO_INI, FUSEKI_BASE); - System.setProperty(FusekiApp.envFusekiShiro, FUSEKI_BASE.resolve(DFT_SHIRO_INI).toString()); + if ( Lib.getenv(FusekiServerCtl.envFusekiShiro) == null ) { + copyFileIfMissing(null, DFT_SHIRO_INI, baseArea); + System.setProperty(FusekiServerCtl.envFusekiShiro, baseArea.resolve(DFT_SHIRO_INI).toString()); } - copyFileIfMissing(null, DFT_CONFIG, FUSEKI_BASE); + copyFileIfMissing(null, DFT_CONFIG, baseArea); for ( String n : Template.templateNames ) { - copyFileIfMissing(null, n, FUSEKI_BASE); + copyFileIfMissing(null, n, baseArea); } serverInitialized = true; } - /** Copy a file from src to dst under name fn. - * If src is null, try as a classpath resource - * @param src Source directory, or null meaning use java resource. - * @param fn File name, a relative path. - * @param dst Destination directory. - * - */ - private static void copyFileIfMissing(Path src, String fn, Path dst) { - // fn may be a path. - Path dstFile = dst.resolve(fn); - if ( Files.exists(dstFile) ) - return; - if ( src != null ) { - Path srcFile = src.resolve(fn); - if ( ! Files.exists(dstFile) ) - throw new FusekiConfigException("File not found: "+srcFile); - try { - IOX.safeWrite(dstFile, output->Files.copy(srcFile, output)); - } catch (RuntimeIOException e) { - throw new FusekiConfigException("Failed to copy file "+srcFile+" to "+dstFile, e); - } - } else { - copyFileFromResource(fn, dstFile); - } - } - - private static void copyFileFromResource(String fn, Path dstFile) { - try { - // Get from the file from area "org/apache/jena/fuseki/server" - String absName = "org/apache/jena/fuseki/server/"+fn; - InputStream input = FusekiApp.class - // Else prepends classname as path - .getClassLoader() - .getResourceAsStream(absName); - - if ( input == null ) - throw new FusekiConfigException("Failed to find resource '"+absName+"'"); - IOX.safeWrite(dstFile, (output)-> input.transferTo(output)); - } - catch (RuntimeException e) { - throw new FusekiConfigException("Failed to copy "+fn+" to "+dstFile, e); - } - } - private static List processServerConfigFile(String configFilename) { if ( ! FileOps.exists(configFilename) ) { Fuseki.configLog.warn("Configuration file '" + configFilename+"' does not exist"); @@ -255,7 +230,7 @@ private static List processServerConfigFile(String configFilena return x; } - private static DataAccessPoint configFromTemplate(String templateFile, String datasetPath, + private DataAccessPoint configFromTemplate(String templateFile, String datasetPath, boolean allowUpdate, Map params) { // ---- Setup if ( params == null ) { @@ -308,6 +283,50 @@ public static void addGlobals(Map params) { // params.put("FUSEKI_HOME", pathStringOrElse(FusekiAppEnv.FUSEKI_HOME, "unset")); } + /** Copy a file from src to dst under name fn. + * If src is null, try as a classpath resource + * @param src Source directory, or null meaning use java resource. + * @param fn File name, a relative path. + * @param dst Destination directory. + * + */ + private static void copyFileIfMissing(Path src, String fn, Path dst) { + // fn may be a path. + Path dstFile = dst.resolve(fn); + if ( Files.exists(dstFile) ) + return; + if ( src != null ) { + Path srcFile = src.resolve(fn); + if ( ! Files.exists(dstFile) ) + throw new FusekiConfigException("File not found: "+srcFile); + try { + IOX.safeWrite(dstFile, output->Files.copy(srcFile, output)); + } catch (RuntimeIOException e) { + throw new FusekiConfigException("Failed to copy file "+srcFile+" to "+dstFile, e); + } + } else { + copyFileFromResource(fn, dstFile); + } + } + + private static void copyFileFromResource(String fn, Path dstFile) { + try { + // Get from the file from area "org/apache/jena/fuseki/server" + String absName = "org/apache/jena/fuseki/server/"+fn; + InputStream input = FusekiServerCtl.class + // Else prepends classname as path + .getClassLoader() + .getResourceAsStream(absName); + + if ( input == null ) + throw new FusekiConfigException("Failed to find resource '"+absName+"'"); + IOX.safeWrite(dstFile, (output)-> input.transferTo(output)); + } + catch (RuntimeException e) { + throw new FusekiConfigException("Failed to copy "+fn+" to "+dstFile, e); + } + } + private static String pathStringOrElse(Path path, String dft) { if ( path == null ) return dft; @@ -405,7 +424,7 @@ public static String generateConfigurationFilename(String dsName) { // Without "/" if ( filename.startsWith("/")) filename = filename.substring(1); - Path p = FusekiApp.dirConfiguration.resolve(filename+".ttl"); + Path p = FusekiServerCtl.dirConfiguration.resolve(filename+".ttl"); return p.toString(); } @@ -413,12 +432,12 @@ public static String generateConfigurationFilename(String dsName) { public static List existingConfigurationFile(String baseFilename) { try { List paths = new ArrayList<>(); - try (DirectoryStream stream = Files.newDirectoryStream(FusekiApp.dirConfiguration, baseFilename+".*") ) { - stream.forEach((p)-> paths.add(FusekiApp.dirConfiguration.resolve(p).toString() )); + try (DirectoryStream stream = Files.newDirectoryStream(FusekiServerCtl.dirConfiguration, baseFilename+".*") ) { + stream.forEach((p)-> paths.add(FusekiServerCtl.dirConfiguration.resolve(p).toString() )); } return paths; } catch (IOException ex) { - throw new InternalErrorException("Failed to read configuration directory "+FusekiApp.dirConfiguration); + throw new InternalErrorException("Failed to read configuration directory "+FusekiServerCtl.dirConfiguration); } } diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/ServerMgtConst.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/ServerMgtConst.java index 056b161470c..c67aa547d14 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/ServerMgtConst.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/ServerMgtConst.java @@ -20,7 +20,7 @@ /** * Various constants used in the management API functions and JSON responses in the - * webapp/full server. + * Fuseki server app. */ public class ServerMgtConst { public static final String opDatasets = "datasets"; diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/Template.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/Template.java index 2ef63652b8e..1266fb3faf4 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/Template.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mgt/Template.java @@ -24,7 +24,7 @@ public class Template { public static Path getPath(String templateName) { - return FusekiApp.FUSEKI_BASE.resolve(templateName); + return FusekiServerCtl.FUSEKI_BASE.resolve(templateName); } public static final String templateDir = "templates"; diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/FusekiModServer.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/FusekiModServer.java new file mode 100644 index 00000000000..e1c9c95368f --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/FusekiModServer.java @@ -0,0 +1,102 @@ +/* + * 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.mod; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.jena.atlas.lib.FileOps; +import org.apache.jena.fuseki.main.FusekiServer; +import org.apache.jena.fuseki.main.cmds.FusekiMain; +import org.apache.jena.fuseki.main.sys.FusekiModule; +import org.apache.jena.fuseki.main.sys.FusekiModules; +import org.apache.jena.fuseki.mod.admin.FMod_Admin; +import org.apache.jena.fuseki.mod.prometheus.FMod_Prometheus; +import org.apache.jena.fuseki.mod.shiro.FMod_Shiro; +import org.apache.jena.fuseki.mod.ui.FMod_UI; + +public class FusekiModServer { + + // TODO Move to org.apache.jena.fuseki.main.cmds + public static void main(String... args) { + runAsync(args).join(); + } + + public static FusekiServer runAsync(String... args) { + return construct(args).start(); + } + + public static FusekiServer construct(String... args) { + // Order: FMod_Admin before FMod_Shiro + // These modules may have state that is carried across the build steps. + FusekiModule fmodShiro = FMod_Shiro.create(); + FusekiModule fmodAdmin = FMod_Admin.create(); + + FusekiModules serverModules = FusekiModules.create( fmodAdmin + , FMod_UI.get() + , fmodShiro + , FMod_Prometheus.get() ); + serverModules.forEach(FusekiMain::addCustomiser); + + System.setProperty("FUSEKI_BASE", "run"); + FileOps.ensureDir("run"); + + // Adjust args. + List argList = Arrays.asList(args); + // Ensure "--empty", "--modules=true" + // Better: moded startup - i.e. setting defaults. + + if ( ! containsArg(argList, "--?empty") ) { + System.err.println("No --empty"); + } + + if ( ! containsArg(argList, "--?modules(=.*)?") ) { + System.err.println("No --modules"); + } + + if ( args.length == 0 ) { + String [] defaultArgs = { "--port=3030" + , "--empty" + , "--modules=true" + }; + args = defaultArgs; + } else { + List argsList = new ArrayList(Arrays.asList(args)); + if ( ! containsArg(argList, "--?empty") ) + argsList.add(0, "--empty"); // addFirst in java21 + if ( ! containsArg(argList, "--?modules") ) + argsList.add(0, "--modules=true"); + args = argsList.toArray(args); + } + + FusekiModules modules = serverModules; + FusekiModules.setSystemDefault(modules); + FusekiServer server = FusekiServer.construct(args); + return server; + } + + private static boolean containsArg(List argList, String argRegex) { + //Pattern pattern = Pattern.compile(argRegex); + + return argList.stream().anyMatch(arg->{ + return arg.matches(argRegex); + }); + } +} diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/admin/ArgModuleAdmin.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/admin/ArgModuleAdmin.java index 6cb3ed0b4e5..f1b9d6c751d 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/admin/ArgModuleAdmin.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/admin/ArgModuleAdmin.java @@ -26,7 +26,7 @@ import org.apache.jena.cmd.CmdArgModule; import org.apache.jena.cmd.CmdGeneral; import org.apache.jena.fuseki.FusekiConfigException; -import org.apache.jena.fuseki.mgt.FusekiApp; +import org.apache.jena.fuseki.mgt.FusekiServerCtl; public class ArgModuleAdmin implements ArgModuleGeneral { // Add a static of "extra command" @@ -58,7 +58,7 @@ public void processArgs(CmdArgModule cmdLine) { if ( ! Files.isWritable(directory) ) throw new FusekiConfigException("Not writable: "+dirStr); - FusekiApp.FUSEKI_BASE = directory; + FusekiServerCtl.FUSEKI_BASE = directory; } @Override diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/admin/FMod_Admin.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/admin/FMod_Admin.java index c48bd290bb3..d4ea62e6612 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/admin/FMod_Admin.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/admin/FMod_Admin.java @@ -38,7 +38,7 @@ import org.apache.jena.fuseki.mgt.ActionBackup; import org.apache.jena.fuseki.mgt.ActionBackupList; import org.apache.jena.fuseki.mgt.ActionDatasets; -import org.apache.jena.fuseki.mgt.FusekiApp; +import org.apache.jena.fuseki.mgt.FusekiServerCtl; import org.apache.jena.fuseki.server.DataAccessPoint; import org.apache.jena.rdf.model.Model; import org.slf4j.Logger; @@ -80,8 +80,8 @@ public void serverArgsModify(CmdGeneral fusekiCmd, ServerArgs serverArgs) { ArgModuleGeneral argModule = new ArgModuleGeneral() { @Override public void registerWith(CmdGeneral cmdLine) { - cmdLine.add(argAdmin, "--admin", "Enable server admin with user:password"); - cmdLine.add(argAdminArea,"--adminRun", "Directory for server configuration"); +// cmdLine.add(argAdmin, "--admin", "Enable server admin with user:password"); +// cmdLine.add(argAdminArea,"--adminRun", "Directory for server configuration"); } @Override public void processArgs(CmdArgModule cmdLine) {} @@ -101,6 +101,7 @@ public void serverArgsPrepare(CmdGeneral fusekiCmd, ServerArgs serverArgs) { if ( dirStr != null ) directory = Path.of(dirStr); + // Phase 2 if ( admin.equals("localhost") ) {} else { String pwFile = admin; @@ -113,7 +114,7 @@ public void serverArgsPrepare(CmdGeneral fusekiCmd, ServerArgs serverArgs) { if ( ! Files.isWritable(directory) ) throw new FusekiConfigException("Not writable: "+dirStr); } - FusekiApp.FUSEKI_BASE = directory; + FusekiServerCtl.FUSEKI_BASE = directory; } // @Override @@ -124,28 +125,26 @@ public void serverArgsPrepare(CmdGeneral fusekiCmd, ServerArgs serverArgs) { @Override public void prepare(FusekiServer.Builder builder, Set datasetNames, Model configModel) { - // Unpack + // Ensure the work area is setup - // XXX Do better! - FusekiApp.FUSEKI_BASE = null; - -// FusekiApp fusekiApp = new FusekiApp(); -// //fusekiApp.init(); -// String fusekiApp.FUSEKI_BASE - - Path path = FusekiApp.setup(); + Path path; + synchronized(FusekiServerCtl.class) { + // Temporary - one at a time because FUSEKI_BASE is static. + FusekiServerCtl app = new FusekiServerCtl(null); + path = app.setup(); + } FmtLog.info(LOG, "Fuseki Admin: %s", path); // Shiro. - Path shiroIni = path.resolve(FusekiApp.DFT_SHIRO_INI); + Path shiroIni = path.resolve(FusekiServerCtl.DFT_SHIRO_INI); if ( Files.exists(shiroIni) ) { - System.setProperty(FusekiApp.envFusekiShiro, shiroIni.toString()); + System.setProperty(FusekiServerCtl.envFusekiShiro, shiroIni.toString()); } else { FmtLog.info(LOG, "No shiro.ini: dir=%s", path); } - String configDir = FusekiApp.dirConfiguration.toString(); + String configDir = FusekiServerCtl.dirConfiguration.toString(); List directoryDatabases = FusekiConfig.readConfigurationDirectory(configDir); if ( directoryDatabases.isEmpty() ) diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FMod_Shiro.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FMod_Shiro.java index e70a44d58d4..bd58001d7fc 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FMod_Shiro.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FMod_Shiro.java @@ -34,7 +34,7 @@ import org.apache.jena.fuseki.main.FusekiServer; import org.apache.jena.fuseki.main.cmds.ServerArgs; import org.apache.jena.fuseki.main.sys.FusekiModule; -import org.apache.jena.fuseki.mgt.FusekiApp; +import org.apache.jena.fuseki.mgt.FusekiServerCtl; import org.apache.jena.rdf.model.Model; import org.apache.shiro.web.servlet.ShiroFilter; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; @@ -122,7 +122,7 @@ public void serverArgsPrepare(CmdGeneral fusekiCmd, ServerArgs serverArgs) { public void prepare(FusekiServer.Builder serverBuilder, Set datasetNames, Model configModel) { if ( shiroFile == null ) { // Environment variable: FUSEKI_SHIRO - shiroFile = Lib.getenv(FusekiApp.envFusekiShiro); + shiroFile = Lib.getenv(FusekiServerCtl.envFusekiShiro); } if ( shiroFile == null ) { diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/ui/FMod_UI.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/ui/FMod_UI.java index a46ec343aa5..51ad0fa32da 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/ui/FMod_UI.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/ui/FMod_UI.java @@ -34,7 +34,7 @@ import org.apache.jena.fuseki.main.FusekiServer; import org.apache.jena.fuseki.main.cmds.ServerArgs; import org.apache.jena.fuseki.main.sys.FusekiModule; -import org.apache.jena.fuseki.mgt.FusekiApp; +import org.apache.jena.fuseki.mgt.FusekiServerCtl; import org.apache.jena.fuseki.validation.DataValidator; import org.apache.jena.fuseki.validation.IRIValidator; import org.apache.jena.fuseki.validation.QueryValidator; @@ -130,7 +130,7 @@ private String findFusekiApp() { // 2:: $FUSEKI_BASE/webapp // If the FUSEKI_BASE does not exists, it is created later in FMod_admin.prepare // and does not include Fuseki app. - String x = fromPath(FusekiApp.FUSEKI_BASE, directoryNameUI); + String x = fromPath(FusekiServerCtl.FUSEKI_BASE, directoryNameUI); if ( x != null ) { LOG.info("Fuseki UI - path resource: "+x); return x; diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/TestFusekiServer.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/TestFusekiServer.java index e0a6b2392df..c9d11ed6919 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/TestFusekiServer.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/TestFusekiServer.java @@ -23,7 +23,6 @@ import org.junit.jupiter.api.Test; import org.apache.jena.fuseki.main.FusekiServer; -import org.apache.jena.fuseki.run.FusekiModServer; /** * Test for the whole Fuseki server, not components. diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/admin/TestAdmin.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/admin/TestAdmin.java index df0f6bafddd..396b14b2890 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/admin/TestAdmin.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/admin/TestAdmin.java @@ -56,7 +56,7 @@ import org.apache.jena.fuseki.ctl.JsonConstCtl; import org.apache.jena.fuseki.main.FusekiServer; import org.apache.jena.fuseki.main.sys.FusekiModules; -import org.apache.jena.fuseki.mgt.FusekiApp; +import org.apache.jena.fuseki.mgt.FusekiServerCtl; import org.apache.jena.fuseki.mgt.ServerMgtConst; import org.apache.jena.fuseki.server.ServerConst; import org.apache.jena.fuseki.test.HttpTest; @@ -121,7 +121,7 @@ private FusekiServer createServerForTest() { server.stop(); serverURL = null; // Clearup FMod_Shiro. - System.getProperties().remove(FusekiApp.envFusekiShiro); + System.getProperties().remove(FusekiServerCtl.envFusekiShiro); } protected String urlRoot() { diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/admin/TestTemplateAddDataset.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/admin/TestTemplateAddDataset.java index 975876095dc..9743802dcfa 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/admin/TestTemplateAddDataset.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/admin/TestTemplateAddDataset.java @@ -36,7 +36,7 @@ import org.apache.jena.fuseki.Fuseki; import org.apache.jena.fuseki.main.FusekiServer; import org.apache.jena.fuseki.main.sys.FusekiModules; -import org.apache.jena.fuseki.mgt.FusekiApp; +import org.apache.jena.fuseki.mgt.FusekiServerCtl; import org.apache.jena.http.HttpOp; import org.apache.jena.query.QueryExecution; import org.apache.jena.rdfconnection.RDFConnection; @@ -85,7 +85,7 @@ private static FusekiServer createServerForTest() { server.stop(); serverURL = null; // Clearup FMod_Shiro. - System.getProperties().remove(FusekiApp.envFusekiShiro); + System.getProperties().remove(FusekiServerCtl.envFusekiShiro); } protected String urlRoot() { @@ -143,7 +143,7 @@ private void testAddDelete(String dbName, String dbType, boolean alreadyExists, int x1 = count(conn); assertEquals(1, x1); - Path pathDB = FusekiApp.dirDatabases.resolve(dbName); + Path pathDB = FusekiServerCtl.dirDatabases.resolve(dbName); if ( hasFiles ) assertTrue(Files.exists(pathDB)); diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/shiro/TestModShiro.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/shiro/TestModShiro.java index dafc636f78d..48f064f6a74 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/shiro/TestModShiro.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/mod/shiro/TestModShiro.java @@ -37,7 +37,7 @@ import org.apache.jena.fuseki.main.cmds.FusekiMain; import org.apache.jena.fuseki.main.sys.FusekiModule; import org.apache.jena.fuseki.main.sys.FusekiModules; -import org.apache.jena.fuseki.mgt.FusekiApp; +import org.apache.jena.fuseki.mgt.FusekiServerCtl; import org.apache.jena.fuseki.system.FusekiLogging; import org.apache.jena.graph.Graph; import org.apache.jena.http.HttpEnv; @@ -62,7 +62,7 @@ public class TestModShiro { } @BeforeEach void before() { - System.getProperties().remove(FusekiApp.envFusekiShiro); + System.getProperties().remove(FusekiServerCtl.envFusekiShiro); AuthEnv.get().clearAuthEnv(); } @@ -71,7 +71,7 @@ public class TestModShiro { } @AfterAll static void afterAll() { - System.getProperties().remove(FusekiApp.envFusekiShiro); + System.getProperties().remove(FusekiServerCtl.envFusekiShiro); } private String unlocalhost(FusekiServer server, String dataset) { @@ -83,7 +83,7 @@ private String unlocalhost(FusekiServer server, String dataset) { /** Builder for a server with Shiro */ private FusekiServer.Builder serverBuilderWithShiro(String filename) { - System.getProperties().setProperty(FusekiApp.envFusekiShiro, filename); + System.getProperties().setProperty(FusekiServerCtl.envFusekiShiro, filename); FusekiModules modules = FusekiModules.create(FMod_Shiro.create()); return FusekiServer.create() .port(0)