diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/AssemblerUtils.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/AssemblerUtils.java index e67baddb971..c409626aa1d 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/AssemblerUtils.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/AssemblerUtils.java @@ -65,8 +65,8 @@ static public void init() initialized = true ; registerDataset(tDataset, new DatasetAssemblerGeneral()); registerDataset(tDatasetOne, new DatasetOneAssembler()); - registerDataset(tDatasetZero, new DatasetNullAssembler(tDatasetZero)); - registerDataset(tDatasetSink, new DatasetNullAssembler(tDatasetSink)); + registerDataset(tDatasetZero, new DatasetZeroAssembler()); + registerDataset(tDatasetSink, new DatasetSinkAssembler()); registerDataset(tMemoryDataset, new InMemDatasetAssembler()); registerDataset(tDatasetTxnMem, new InMemDatasetAssembler()); registerDataset(tDatasetView, new ViewDatasetAssembler()); diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetAssemblerGeneral.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetAssemblerGeneral.java index 4fa6653bfd5..399e6a34e09 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetAssemblerGeneral.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetAssemblerGeneral.java @@ -19,7 +19,6 @@ package org.apache.jena.sparql.core.assembler ; import java.util.List ; -import java.util.Map; import org.apache.jena.assembler.Assembler ; import org.apache.jena.atlas.logging.Log ; @@ -41,11 +40,6 @@ public static Resource getType() { public DatasetAssemblerGeneral() {} - @Override - public Map pool() { - return sharedDatasetPool; - } - @Override public DatasetGraph createDataset(Assembler a, Resource root) { // -------- Default graph diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetOneAssembler.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetOneAssembler.java index a9462e3a7cf..9b0dd68d72c 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetOneAssembler.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetOneAssembler.java @@ -19,7 +19,6 @@ package org.apache.jena.sparql.core.assembler; import java.util.List; -import java.util.Map; import org.apache.jena.assembler.Assembler; import org.apache.jena.assembler.exceptions.AssemblerException; @@ -51,11 +50,6 @@ public static Resource getType() { public DatasetOneAssembler() {} - @Override - public Map pool() { - return sharedDatasetPool; - } - @Override public DatasetGraph createDataset(Assembler a, Resource root) { // Can use ja:graph or ja:defaultGraph but not both. diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetNullAssembler.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetSinkAssembler.java similarity index 66% rename from jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetNullAssembler.java rename to jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetSinkAssembler.java index 4c0f0999295..86fe6f4a314 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetNullAssembler.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetSinkAssembler.java @@ -18,45 +18,29 @@ package org.apache.jena.sparql.core.assembler; -import java.util.Map; - import org.apache.jena.assembler.Assembler; -import org.apache.jena.atlas.lib.InternalErrorException; import org.apache.jena.rdf.model.Resource; import org.apache.jena.sparql.core.DatasetGraph; import org.apache.jena.sparql.core.DatasetGraphSink; import org.apache.jena.sparql.core.DatasetGraphZero; /** - * An assembler that creates datasets that do nothing, either a sink or a always empty one. + * An assembler that creates datasets that do nothing, either a sink or an always empty one. * @see DatasetGraphSink * @see DatasetGraphZero */ -public class DatasetNullAssembler extends NamedDatasetAssembler { +public class DatasetSinkAssembler extends NamedDatasetAssembler { - private final Resource tDataset; + public static Resource getType() { return DatasetAssemblerVocab.tDatasetSink; } - public DatasetNullAssembler(Resource tDataset) { - this.tDataset = tDataset; - } + public DatasetSinkAssembler() {} @Override public DatasetGraph createDataset(Assembler a, Resource root) { - DatasetGraph dsg; - if ( DatasetAssemblerVocab.tDatasetSink.equals(tDataset) ) - dsg = DatasetGraphSink.create(); - else if ( DatasetAssemblerVocab.tDatasetZero.equals(tDataset) ) - dsg = DatasetGraphZero.create(); - else - throw new InternalErrorException(); + DatasetGraph dsg = DatasetGraphSink.create(); AssemblerUtils.mergeContext(root, dsg.getContext()); return dsg; } - - @Override - public Map pool() { - return sharedDatasetPool; - } } diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetZeroAssembler.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetZeroAssembler.java new file mode 100644 index 00000000000..5421d8cf8ac --- /dev/null +++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/DatasetZeroAssembler.java @@ -0,0 +1,44 @@ +/* + * 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.sparql.core.assembler; + +import org.apache.jena.assembler.Assembler; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.sparql.core.DatasetGraph; +import org.apache.jena.sparql.core.DatasetGraphZero; + +/** + * An assembler that creates datasets that do nothing, either a sink or an always empty one. + * + * @see DatasetGraphZero + */ + +public class DatasetZeroAssembler extends NamedDatasetAssembler { + + public static Resource getType() { return DatasetAssemblerVocab.tDatasetZero; } + + public DatasetZeroAssembler() {} + + @Override + public DatasetGraph createDataset(Assembler a, Resource root) { + DatasetGraph dsg = DatasetGraphZero.create(); + AssemblerUtils.mergeContext(root, dsg.getContext()); + return dsg; + } +} diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/InMemDatasetAssembler.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/InMemDatasetAssembler.java index 21e80dc27fc..cdeb0d01ca3 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/InMemDatasetAssembler.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/InMemDatasetAssembler.java @@ -21,8 +21,6 @@ import static org.apache.jena.sparql.core.assembler.AssemblerUtils.loadData; import static org.apache.jena.sparql.core.assembler.AssemblerUtils.mergeContext; -import java.util.Map; - import org.apache.jena.assembler.Assembler; import org.apache.jena.query.Dataset; import org.apache.jena.rdf.model.Resource; @@ -39,11 +37,6 @@ public class InMemDatasetAssembler extends NamedDatasetAssembler { public InMemDatasetAssembler() {} - @Override - public Map pool() { - return sharedDatasetPool; - } - public static Resource getType() { return DatasetAssemblerVocab.tMemoryDataset ; } diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/NamedDatasetAssembler.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/NamedDatasetAssembler.java index 3b412ce6ce9..0547695f579 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/NamedDatasetAssembler.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/NamedDatasetAssembler.java @@ -49,6 +49,11 @@ public final DatasetGraph createNamedDataset(Assembler a, Resource root) { return createDataset(a, root); } - /** Shared {@link DatasetGraph} objects */ - public abstract Map pool(); + /** + * Shared {@link DatasetGraph} objects. + * Subclasses may override for a different policy, or return null for "don't pool". + * Pools only affect {@link #createNamedDataset} and then only when {@code ja:name} + * ({@code DatasetAssemblerVocab.pDatasetName}) is present. + */ + public Map pool() { return sharedDatasetPool; } } diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/ViewDatasetAssembler.java b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/ViewDatasetAssembler.java index 32bd4979669..2a74868b5d9 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/ViewDatasetAssembler.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/assembler/ViewDatasetAssembler.java @@ -18,8 +18,6 @@ package org.apache.jena.sparql.core.assembler; -import java.util.Map; - import org.apache.jena.assembler.Assembler; import org.apache.jena.rdf.model.Resource; import org.apache.jena.sparql.core.DatasetGraph; @@ -38,11 +36,6 @@ public class ViewDatasetAssembler extends NamedDatasetAssembler { public ViewDatasetAssembler() {} - @Override - public Map pool() { - return sharedDatasetPool; - } - @Override public DatasetGraph createDataset(Assembler a, Resource root) { DatasetGraph sub = createBaseDataset(root, DatasetAssemblerVocab.pDataset); diff --git a/jena-base/src/main/java/org/apache/jena/atlas/logging/LogCtl.java b/jena-base/src/main/java/org/apache/jena/atlas/logging/LogCtl.java index e721d3b7c23..36a81903946 100644 --- a/jena-base/src/main/java/org/apache/jena/atlas/logging/LogCtl.java +++ b/jena-base/src/main/java/org/apache/jena/atlas/logging/LogCtl.java @@ -38,10 +38,11 @@ * This needs access to log4j2 binaries including log4j-core, which is encapsulated in LogCtlLog4j2. */ public class LogCtl { - private static final boolean hasLog4j2 = hasClass("org.apache.logging.slf4j.Log4jLoggerFactory"); - private static final boolean hasLog4j1 = hasClass("org.slf4j.impl.Log4jLoggerFactory"); - private static final boolean hasJUL = hasClass("org.slf4j.impl.JDK14LoggerFactory"); + private static final boolean hasLog4j2 = hasClass("org.apache.logging.slf4j.Log4jLoggerFactory"); + private static final boolean hasLog4j1 = hasClass("org.slf4j.impl.Log4jLoggerFactory"); // JUL always present but needs slf4j adapter. + private static final boolean hasJUL = hasClass("org.slf4j.impl.JDK14LoggerFactory"); + private static final boolean hasLogback = hasClass("ch.qos.logback.core.LogbackException"); // Put per-logging system code in separate classes to avoid needing them on the classpath. private static boolean hasClass(String className) { @@ -83,67 +84,34 @@ public static String getLevel(String logger) { String s2 = getLevelLog4j2(logger); if ( s2 != null ) return s2; - // Always present. String s3 = getLevelJUL(logger); if ( s3 != null ) return s3; return null; } - static private String getLevelJUL(String logger) { - java.util.logging.Level level = java.util.logging.Logger.getLogger(logger).getLevel(); - if ( level == null ) + static private String getLevelLog4j2(String logger) { + if ( !hasLog4j2 ) return null; - if ( level == java.util.logging.Level.SEVERE ) - return "ERROR"; - return level.getName(); + return LogCtlLog4j2.getLoggerlevel(logger); } - static private String getLevelLog4j2(String logger) { - if ( !hasLog4j2 ) + static private String getLevelJUL(String logger) { + if ( ! hasJUL ) return null; - org.apache.logging.log4j.Level level = org.apache.logging.log4j.LogManager.getLogger(logger).getLevel(); - if ( level != null ) - return level.toString(); - return null; + return LogCtlJUL.getLevelJUL(logger); } private static void setLevelJUL(String logger, String levelName) { - java.util.logging.Level level = java.util.logging.Level.ALL; - if ( levelName == null ) - level = null; - else if ( levelName.equalsIgnoreCase("info") ) - level = java.util.logging.Level.INFO; - else if ( levelName.equalsIgnoreCase("debug") ) - level = java.util.logging.Level.FINE; - else if ( levelName.equalsIgnoreCase("warn") || levelName.equalsIgnoreCase("warning") ) - level = java.util.logging.Level.WARNING; - else if ( levelName.equalsIgnoreCase("error") || levelName.equalsIgnoreCase("severe") ) - level = java.util.logging.Level.SEVERE; - else if ( levelName.equalsIgnoreCase("OFF") ) - level = java.util.logging.Level.OFF; - java.util.logging.Logger.getLogger(logger).setLevel(level); + if ( ! hasJUL ) + return ; + LogCtlJUL.setLevelJUL(logger, levelName); } private static void setLevelLog4j2(String logger, String levelName) { if ( !hasLog4j2 ) return; - org.apache.logging.log4j.Level level = org.apache.logging.log4j.Level.ALL; - if ( levelName == null ) - level = null; - else if ( levelName.equalsIgnoreCase("info") ) - level = org.apache.logging.log4j.Level.INFO; - else if ( levelName.equalsIgnoreCase("debug") ) - level = org.apache.logging.log4j.Level.DEBUG; - else if ( levelName.equalsIgnoreCase("warn") || levelName.equalsIgnoreCase("warning") ) - level = org.apache.logging.log4j.Level.WARN; - else if ( levelName.equalsIgnoreCase("error") || levelName.equalsIgnoreCase("severe") ) - level = org.apache.logging.log4j.Level.ERROR; - else if ( levelName.equalsIgnoreCase("fatal") ) - level = org.apache.logging.log4j.Level.FATAL; - else if ( levelName.equalsIgnoreCase("OFF") ) - level = org.apache.logging.log4j.Level.OFF; - LogCtlLog4j2.setLoggerlevel(logger, level); + LogCtlLog4j2.setLoggerlevel(logger, levelName); } /** diff --git a/jena-base/src/main/java/org/apache/jena/atlas/logging/LogCtlJUL.java b/jena-base/src/main/java/org/apache/jena/atlas/logging/LogCtlJUL.java index 56611cd31c9..8870457ec3f 100644 --- a/jena-base/src/main/java/org/apache/jena/atlas/logging/LogCtlJUL.java +++ b/jena-base/src/main/java/org/apache/jena/atlas/logging/LogCtlJUL.java @@ -54,6 +54,32 @@ public class LogCtlJUL { private LogCtlJUL() {} + /*package*/ static String getLevelJUL(String logger) { + java.util.logging.Level level = java.util.logging.Logger.getLogger(logger).getLevel(); + if ( level == null ) + return null; + if ( level == java.util.logging.Level.SEVERE ) + return "ERROR"; + return level.getName(); + } + + /*package*/ static void setLevelJUL(String logger, String levelName) { + java.util.logging.Level level = java.util.logging.Level.ALL; + if ( levelName == null ) + level = null; + else if ( levelName.equalsIgnoreCase("info") ) + level = java.util.logging.Level.INFO; + else if ( levelName.equalsIgnoreCase("debug") ) + level = java.util.logging.Level.FINE; + else if ( levelName.equalsIgnoreCase("warn") || levelName.equalsIgnoreCase("warning") ) + level = java.util.logging.Level.WARNING; + else if ( levelName.equalsIgnoreCase("error") || levelName.equalsIgnoreCase("severe") ) + level = java.util.logging.Level.SEVERE; + else if ( levelName.equalsIgnoreCase("OFF") ) + level = java.util.logging.Level.OFF; + java.util.logging.Logger.getLogger(logger).setLevel(level); + } + /** * Reset java.util.logging - this overrides the previous configuration, if any. */ diff --git a/jena-base/src/main/java/org/apache/jena/atlas/logging/LogCtlLog4j2.java b/jena-base/src/main/java/org/apache/jena/atlas/logging/LogCtlLog4j2.java index fc976bc66b4..ff7a7081aca 100644 --- a/jena-base/src/main/java/org/apache/jena/atlas/logging/LogCtlLog4j2.java +++ b/jena-base/src/main/java/org/apache/jena/atlas/logging/LogCtlLog4j2.java @@ -52,10 +52,7 @@ public class LogCtlLog4j2 { /** Default log4j2 setup */ - public static String log4j2setup = String.join(log4jSetupSep(), - log4j2setupBase(), - log4j2setupJenaLib(), - log4j2setupFuseki()); + public static String log4j2setup = Log4j2Setup.log4j2setup(); /** * Reset logging for log4j2. @@ -82,7 +79,36 @@ public static void resetLogging(InputStream inputStream, SyntaxHint syntaxHint) reconfigureLog4j(config); } - /** Check logging level of a Logger */ + /** get logging level of a Logger as a string */ + /* package */ static String getLoggerlevel(String logger) { + Level level = org.apache.logging.log4j.LogManager.getLogger(logger).getLevel(); + if ( level != null ) + return level.toString(); + return null; + + } + + /** Set logging level of a Logger */ + /*package*/ static void setLoggerlevel(String logger, String levelName) { + org.apache.logging.log4j.Level level = org.apache.logging.log4j.Level.ALL; + if ( levelName == null ) + level = null; + else if ( levelName.equalsIgnoreCase("info") ) + level = org.apache.logging.log4j.Level.INFO; + else if ( levelName.equalsIgnoreCase("debug") ) + level = org.apache.logging.log4j.Level.DEBUG; + else if ( levelName.equalsIgnoreCase("warn") || levelName.equalsIgnoreCase("warning") ) + level = org.apache.logging.log4j.Level.WARN; + else if ( levelName.equalsIgnoreCase("error") || levelName.equalsIgnoreCase("severe") ) + level = org.apache.logging.log4j.Level.ERROR; + else if ( levelName.equalsIgnoreCase("fatal") ) + level = org.apache.logging.log4j.Level.FATAL; + else if ( levelName.equalsIgnoreCase("OFF") ) + level = org.apache.logging.log4j.Level.OFF; + LogCtlLog4j2.setLoggerlevel(logger, level); + } + + /** Set logging level of a Logger */ /*package*/ static void setLoggerlevel(String logger, Level level) { try { if ( !logger.equals("") ) @@ -94,7 +120,7 @@ public static void resetLogging(InputStream inputStream, SyntaxHint syntaxHint) } } - /** Check logging level of a Logger */ + /** Set logging level of a Logger */ /*package*/ static void setLoggerlevel(Logger logger, Level level) { try { org.apache.logging.log4j.core.config.Configurator.setLevel(logger, level); @@ -103,7 +129,6 @@ public static void resetLogging(InputStream inputStream, SyntaxHint syntaxHint) } } - /** * Enum for possible syntax of a Log4j configuration file. *

@@ -259,81 +284,93 @@ private static SyntaxHint determineSyntax(String filename) { return hint; } - /** Line separate/blank line for concatenating log4j syntax fragments. */ - private static String log4jSetupSep() { return "\n"; } + // Hide constants. + static class Log4j2Setup { + + private static String log4j2setup() { + return String.join(log4jSetupSep(), + log4j2setupBase(), + log4j2setupJenaLib(), + log4j2setupFuseki()); + } + + /** Line separate/blank line for concatenating log4j syntax fragments. */ + private static String log4jSetupSep() { return "\n"; } + + /** + * A basic logging setup. Time and level INFO. + */ + private static String log4j2setupBase() { + return """ + ## Log4j2 properties syntax. + status = error + name = JenaLoggingDft + + # filters = threshold + # filter.threshold.type = ThresholdFilter + # filter.threshold.level = ALL + + appender.console.type = Console + appender.console.name = OUT + appender.console.target = SYSTEM_OUT + appender.console.layout.type = PatternLayout + appender.console.layout.pattern = %d{HH:mm:ss} %-5p %-15c{1} :: %m%n + # appender.console.layout.pattern = [%d{yyyy-MM-dd HH:mm:ss}] %-5p %-15c{1} :: %m%n + + rootLogger.level = INFO + rootLogger.appenderRef.stdout.ref = OUT + """; + } + /** Default log4j fragment needed for Jena command line tools. */ + private static String log4j2setupJenaLib() { + return """ + logger.jena.name = org.apache.jena + logger.jena.level = INFO + + logger.arq-exec.name = org.apache.jena.arq.exec + logger.arq-exec.level = INFO + + logger.riot.name = org.apache.jena.riot + logger.riot.level = INFO + """; + } + /** Additional log4j fragment for Fuseki in case the general default is used with embedded Fuseki. */ + private static String log4j2setupFuseki() { + return """ + # Fuseki. In case this logging setup gets install for embedded Fuseki. + + logger.fuseki.name = org.apache.jena.fuseki + logger.fuseki.level = INFO + logger.fuseki-fuseki.name = org.apache.jena.fuseki.Fuseki + logger.fuseki-fuseki.level = INFO + + logger.fuseki-server.name = org.apache.jena.fuseki.Server + logger.fuseki-server.level = INFO + + logger.fuseki-config.name = org.apache.jena.fuseki.Config + logger.fuseki-config.level = INFO + + logger.fuseki-admin.name = org.apache.jena.fuseki.Admin + logger.fuseki-admin.level = INFO + + logger.jetty.name = org.eclipse.jetty + logger.jetty.level = WARN + + logger.shiro.name = org.apache.shiro + logger.shiro.level = WARN + + # This goes out in NCSA format + appender.plain.type = Console + appender.plain.name = PLAIN + appender.plain.layout.type = PatternLayout + appender.plain.layout.pattern = %m%n + + logger.fuseki-request.name = org.apache.jena.fuseki.Request + logger.fuseki-request.additivity = false + logger.fuseki-request.level = OFF + logger.fuseki-request.appenderRef.plain.ref = PLAIN + """; + } - /** - * A basic logging setup. Time and level INFO. - */ - private static String log4j2setupBase() { - return """ - ## Log4j2 properties syntax. - status = error - name = JenaLoggingDft - - # filters = threshold - # filter.threshold.type = ThresholdFilter - # filter.threshold.level = ALL - - appender.console.type = Console - appender.console.name = OUT - appender.console.target = SYSTEM_OUT - appender.console.layout.type = PatternLayout - appender.console.layout.pattern = %d{HH:mm:ss} %-5p %-15c{1} :: %m%n - # appender.console.layout.pattern = [%d{yyyy-MM-dd HH:mm:ss}] %-5p %-15c{1} :: %m%n - - rootLogger.level = INFO - rootLogger.appenderRef.stdout.ref = OUT - """; - } - /** Default log4j fragment needed for Jena command line tools. */ - private static String log4j2setupJenaLib() { - return """ - logger.jena.name = org.apache.jena - logger.jena.level = INFO - - logger.arq-exec.name = org.apache.jena.arq.exec - logger.arq-exec.level = INFO - - logger.riot.name = org.apache.jena.riot - logger.riot.level = INFO - """; - } - /** Additional log4j fragment for Fuseki in case the general default is used with embedded Fuseki. */ - private static String log4j2setupFuseki() { - return """ - # Fuseki. In case this logging setup gets install for embedded Fuseki. - - logger.fuseki.name = org.apache.jena.fuseki - logger.fuseki.level = INFO - logger.fuseki-fuseki.name = org.apache.jena.fuseki.Fuseki - logger.fuseki-fuseki.level = INFO - - logger.fuseki-server.name = org.apache.jena.fuseki.Server - logger.fuseki-server.level = INFO - - logger.fuseki-config.name = org.apache.jena.fuseki.Config - logger.fuseki-config.level = INFO - - logger.fuseki-admin.name = org.apache.jena.fuseki.Admin - logger.fuseki-admin.level = INFO - - logger.jetty.name = org.eclipse.jetty - logger.jetty.level = WARN - - logger.shiro.name = org.apache.shiro - logger.shiro.level = WARN - - # This goes out in NCSA format - appender.plain.type = Console - appender.plain.name = PLAIN - appender.plain.layout.type = PatternLayout - appender.plain.layout.pattern = %m%n - - logger.fuseki-request.name = org.apache.jena.fuseki.Request - logger.fuseki-request.additivity = false - logger.fuseki-request.level = OFF - logger.fuseki-request.appenderRef.plain.ref = PLAIN - """; } } 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 a7ffa72ac99..22528e97904 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 @@ -26,51 +26,44 @@ import org.apache.jena.atlas.lib.DateTimeUtils; import org.apache.jena.atlas.lib.Version; +import org.apache.jena.fuseki.system.FusekiCore; import org.apache.jena.query.ARQ; import org.apache.jena.riot.system.stream.LocatorFTP; import org.apache.jena.riot.system.stream.LocatorHTTP; import org.apache.jena.riot.system.stream.StreamManager; import org.apache.jena.sparql.util.Context; -import org.apache.jena.sparql.util.MappingRegistry; -import org.apache.jena.sys.JenaSystem; -import org.apache.jena.tdb1.TDB1; -import org.apache.jena.tdb1.transaction.TransactionManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Fuseki { // General fixed constants. - // See also FusekiServer for the naming on the filesystem /** Path as package name */ - static public String PATH = "org.apache.jena.fuseki"; + static public final String PATH = "org.apache.jena.fuseki"; /** a unique IRI for the Fuseki namespace */ - static public String FusekiIRI = "http://jena.apache.org/Fuseki"; + static public final String FusekiIRI = "http://jena.apache.org/Fuseki"; /** * a unique IRI including the symbol notation for which properties should be * appended */ - static public String FusekiSymbolIRI = "http://jena.apache.org/fuseki#"; + static public final String FusekiSymbolIRI = "http://jena.apache.org/fuseki#"; /** Default location of the pages for the Fuseki UI */ - static public String PagesStatic = "pages"; + static public final String PagesStatic = "pages"; /** Dummy base URi string for parsing SPARQL Query and Update requests */ - static public final String BaseParserSPARQL = "http://server/unset-base/"; + static public final String BaseParserSPARQL = "http://server/unset-base/"; /** Dummy base URi string for parsing SPARQL Query and Update requests */ - static public final String BaseUpload = "http://server/unset-base/"; - - /** Add CORS header */ - static public final boolean CORS_ENABLED = false; + static public final String BaseUpload = "http://server/unset-base/"; /** The name of the Fuseki server.*/ - static public final String NAME = "Apache Jena Fuseki"; + static public final String NAME = "Apache Jena Fuseki"; /** Version of this Fuseki instance */ - static public final String VERSION = Version.versionForClass(Fuseki.class).orElse(""); + static public final String VERSION = Version.versionForClass(Fuseki.class).orElse(""); /** Supporting Graph Store Protocol direct naming. *

@@ -107,6 +100,12 @@ public class Fuseki { public static boolean outputJettyServerHeader = developmentMode; public static boolean outputFusekiServerHeader = developmentMode; + /** + * Initialize is class. + * See also {@link FusekiCore} for Fuseki core initialization. + */ + public static void initConsts() {} + /** An identifier for the HTTP Fuseki server instance */ static public final String serverHttpName = NAME + " (" + VERSION + ")"; @@ -175,6 +174,7 @@ public class Fuseki { public static final String attrNameRegistry = "org.apache.jena.fuseki:DataAccessPointRegistry"; public static final String attrOperationRegistry = "org.apache.jena.fuseki:OperationRegistry"; public static final String attrAuthorizationService = "org.apache.jena.fuseki:AuthorizationService"; + public static final String attrFusekiServer = "org.apache.jena.fuseki:Server"; public static void setVerbose(ServletContext cxt, boolean verbose) { cxt.setAttribute(attrVerbose, Boolean.valueOf(verbose)); @@ -205,8 +205,6 @@ public static boolean getVerbose(ServletContext cxt) { // HTTP response header inserted to aid tracking. public static String FusekiRequestIdHeader = "Fuseki-Request-Id"; - private static boolean initialized = false; - // Server start time and uptime. private static final long startMillis = System.currentTimeMillis(); // Hide server locale @@ -231,26 +229,6 @@ public static String serverStartedAt() { return startDateTime; } - /** - * Initialize an instance of the Fuseki server stack. - * This is not done via Jena's initialization mechanism - * but done explicitly to give more control. - * Touching this class causes this to happen - * (see static block at the end of this class). - */ - public synchronized static void init() { - if ( initialized ) - return; - initialized = true; - JenaSystem.init(); - MappingRegistry.addPrefixMapping("fuseki", FusekiSymbolIRI); - - TDB1.setOptimizerWarningFlag(false); - // Don't use TDB1 batch commits. - // This can be slower, but it less memory hungry and more predictable. - TransactionManager.QueueBatchSize = 0; - } - /** * Get server global {@link org.apache.jena.sparql.util.Context}. * diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiConfig.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiConfig.java index db6de6c5de8..39057fe4899 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiConfig.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/build/FusekiConfig.java @@ -95,8 +95,6 @@ public class FusekiConfig { Operation.GSP_RW, Operation.Patch); - static { Fuseki.init(); } - /** Convenience operation to populate a {@link DataService} with the conventional default services. */ public static DataService.Builder populateStdServices(DataService.Builder dataServiceBuilder, boolean allowUpdate) { Set endpoints = new HashSet<>(); @@ -322,9 +320,6 @@ public static List servicesAndDatasets(Model model) { // ---- Services // Server to services. RowSet rs = BuildLib.query("SELECT * { ?s fu:services [ list:member ?service ] }", configuration, "s", server); - - List services = rs.stream().map(b->b.get("service")).toList(); - List accessPoints = new ArrayList<>(); // If none, look for services by type. diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/ActionStatsText.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/ActionStatsText.java index 0ff5559b4b9..a1e6b4c4a42 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/ActionStatsText.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/ctl/ActionStatsText.java @@ -38,12 +38,12 @@ public class ActionStatsText extends ActionCtl @Override public void validate(HttpAction action) { - switch(action.getMethod() ) { + switch(action.getRequestMethod() ) { case HttpNames.METHOD_GET: case HttpNames.METHOD_POST: return; default: - ServletOps.errorMethodNotAllowed(action.getMethod()); + ServletOps.errorMethodNotAllowed(action.getRequestMethod()); } } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataAccessPointRegistry.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataAccessPointRegistry.java index b6d41f31da7..02307d3e7e6 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataAccessPointRegistry.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/DataAccessPointRegistry.java @@ -27,6 +27,7 @@ import org.apache.jena.atlas.logging.Log; import org.apache.jena.fuseki.Fuseki; import org.apache.jena.fuseki.FusekiException; +import org.apache.jena.fuseki.servlets.HttpAction; /** * Registry of (dataset name, {@link DataAccessPoint}). @@ -59,7 +60,7 @@ public void register(DataAccessPoint accessPt) { */ public List accessPoints() { List accessPoints = new ArrayList<>(size()); - // Make a copy for safety. + // Copy for safety. forEach((_name, accessPoint) -> accessPoints.add(accessPoint)); return accessPoints; } @@ -90,7 +91,14 @@ public void print(String string) { }); } - // The server DataAccessPointRegistry is held in the ServletContext for the server. + /** The server DataAccessPointRegistry is held in the ServletContext. + *

+ * Reload may change this object for another one. Therefore, code should obtain the + * DataAccessPointRegistry once per operation. + *

+ * Each request, has a stable {@link HttpAction#getDataAccessPointRegistry()}. + *

Getting the {@link DataAccessPointRegistry} is atomic. + */ public static DataAccessPointRegistry get(ServletContext cxt) { DataAccessPointRegistry registry = (DataAccessPointRegistry)cxt.getAttribute(Fuseki.attrNameRegistry); if ( registry == null ) @@ -98,6 +106,10 @@ public static DataAccessPointRegistry get(ServletContext cxt) { return registry; } + /** + * Set or change the {@link DataAccessPointRegistry}. + * This is atomic. (In Jetty, it is backed by a ConcurrentHashMap). + */ public static void set(ServletContext cxt, DataAccessPointRegistry registry) { cxt.setAttribute(Fuseki.attrNameRegistry, registry); } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Dispatcher.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Dispatcher.java index a93c3cc3ac3..8ceac84ea15 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Dispatcher.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/server/Dispatcher.java @@ -388,11 +388,11 @@ private static Operation mapGSP(HttpAction action, Operation operation, Endpoint } else if ( GSP_RW.equals(operation) ) { // If asking for GSP_RW, but only GSP_R is available ... // ... if OPTIONS, use GSP_R. - if ( action.getMethod().equals(HttpNames.METHOD_OPTIONS) && epSet.contains(GSP_R) ) + if ( action.getRequestMethod().equals(HttpNames.METHOD_OPTIONS) && epSet.contains(GSP_R) ) return GSP_R; // ... else 405 if ( epSet.contains(GSP_R) ) - ServletOps.errorMethodNotAllowed(action.getMethod()); + ServletOps.errorMethodNotAllowed(action.getRequestMethod()); } } return operation; diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionLib.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionLib.java index a65dbcba997..8081749642e 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionLib.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionLib.java @@ -401,8 +401,6 @@ public static void setCommonHeadersForOptions(HttpAction action) { } private static void setCommonHeadersForOptions(HttpServletResponse httpResponse) { - if ( Fuseki.CORS_ENABLED ) - httpResponse.setHeader(HttpNames.hAccessControlAllowHeaders, "X-Requested-With, Content-Type, Authorization"); setCommonHeaders(httpResponse); } @@ -411,8 +409,6 @@ public static void setCommonHeaders(HttpAction action) { } private static void setCommonHeaders(HttpServletResponse httpResponse) { - if ( Fuseki.CORS_ENABLED ) - httpResponse.setHeader(HttpNames.hAccessControlAllowOrigin, "*"); if ( Fuseki.outputFusekiServerHeader ) httpResponse.setHeader(HttpNames.hServer, Fuseki.serverHttpName); } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionProcessor.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionProcessor.java index caad104ec4c..44085722aae 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionProcessor.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ActionProcessor.java @@ -29,7 +29,7 @@ public interface ActionProcessor { * @param action HTTP Action */ public default void process(HttpAction action) { - switch ( action.getMethod() ) { + switch ( action.getRequestMethod() ) { case METHOD_GET -> execGet(action); case METHOD_POST -> execPost(action); case METHOD_PATCH -> execPatch(action); @@ -38,7 +38,7 @@ public default void process(HttpAction action) { case METHOD_HEAD -> execHead(action); case METHOD_OPTIONS-> execOptions(action); case METHOD_TRACE -> execTrace(action); - default -> execAny(action.getMethod(), action); + default -> execAny(action.getRequestMethod(), action); } } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/BaseActionREST.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/BaseActionREST.java index b8ff4c3cdc2..2797d09337e 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/BaseActionREST.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/BaseActionREST.java @@ -46,6 +46,6 @@ public class BaseActionREST extends ActionREST { public void validate(HttpAction action) { } private void notSupported(HttpAction action) { - ServletOps.errorMethodNotAllowed(action.getMethod()+" "+action.getDatasetName()); + ServletOps.errorMethodNotAllowed(action.getRequestMethod()+" "+action.getDatasetName()); } } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/FusekiFilter.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/FusekiFilter.java index 86412a8c75d..ec91f1f9a02 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/FusekiFilter.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/FusekiFilter.java @@ -34,7 +34,7 @@ * for any service. */ public class FusekiFilter implements Filter { - private static Logger log = Fuseki.serverLog; + private static final Logger LOG = Fuseki.serverLog; @Override public void init(FilterConfig filterConfig) {} @@ -50,7 +50,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha if ( handled ) return; } catch (Throwable ex) { - log.info("Filter: unexpected exception: "+ex.getMessage(),ex); + LOG.info("Filter: unexpected exception: "+ex.getMessage(),ex); } // Not found - continue. diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java index ef3935646e5..9e35cd3310e 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/HttpAction.java @@ -316,6 +316,7 @@ public void begin(TxnType txnType) { transactional.begin(txnType); activeDSG = dsg; if ( dataService != null ) + // Paired with finishTxn in end() dataService.startTxn(txnType); startActionTxn(); } @@ -491,6 +492,7 @@ private void finishActionTxn() { // ---- public void commit() { +//dataService.finishTxn(); if ( transactional != null ) transactional.commit(); endInternal(); @@ -616,6 +618,8 @@ public String toString() { // ---- Request - response abstraction. + /** @deprecated Use {@link #getRequestMethod}. */ + @Deprecated(since="5.1.0", forRemoval=true) public String getMethod() { return request.getMethod(); } public HttpServletRequest getRequest() { return request; } diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java index 74da22ed832..23a09da8a08 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/ServletOps.java @@ -248,11 +248,11 @@ public static void errorForbidden(String msg) { } public static void error(int statusCode) { - throw new ActionErrorException(statusCode, null, null); + throw actionErrorException(statusCode, null, null); } public static void error(int statusCode, String string) { - throw new ActionErrorException(statusCode, string, null); + throw actionErrorException(statusCode, string, null); } public static void errorOccurred(String message) { @@ -266,7 +266,12 @@ public static void errorOccurred(Throwable ex) { public static void errorOccurred(String message, Throwable ex) { if ( ex instanceof ActionErrorException actionErr ) throw actionErr; - throw new ActionErrorException(HttpSC.INTERNAL_SERVER_ERROR_500, message, ex); + throw actionErrorException(HttpSC.INTERNAL_SERVER_ERROR_500, message, ex); + /* Does not return */ + } + + private static ActionErrorException actionErrorException(int statusCode, String message, Throwable ex) { + return new ActionErrorException(statusCode, message, ex); } public static String formatForLog(String string) { diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/UploadRDF.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/UploadRDF.java index 24de0d7b94e..0a9af3cf765 100644 --- a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/UploadRDF.java +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/servlets/UploadRDF.java @@ -54,7 +54,7 @@ public class UploadRDF extends ActionREST { @Override protected void doPatch(HttpAction action) { unsupported(action); } private void unsupported(HttpAction action) { - ServletOps.errorMethodNotAllowed(action.getMethod()); + ServletOps.errorMethodNotAllowed(action.getRequestMethod()); } @Override diff --git a/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/FusekiCore.java b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/FusekiCore.java new file mode 100644 index 00000000000..ff52228d964 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-core/src/main/java/org/apache/jena/fuseki/system/FusekiCore.java @@ -0,0 +1,61 @@ +/* + * 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.system; + +import org.apache.jena.fuseki.Fuseki; +import org.apache.jena.sparql.util.MappingRegistry; +import org.apache.jena.sys.JenaSystem; +import org.apache.jena.tdb1.TDB1; +import org.apache.jena.tdb1.transaction.TransactionManager; + +/** + * Fuseki core initialization. + *

+ * Initialize an instance of the Fuseki server core code. + * This is not done via Jena's initialization mechanism + * but done explicitly to give control. + *

+ * It is done after Jena initializes. + *

+ * {@code InitFusekiMain} is the code for Jena's initialization mechanism. + * It calls this class. + */ +public class FusekiCore { + + private static boolean initialized = false; + + public synchronized static void init() { + if ( initialized ) + return; + + // Avoid re-entrancy. + initialized = true; + + JenaSystem.init(); + // Touch the Fuseki class to make sure statics get initialized. + Fuseki.initConsts(); + MappingRegistry.addPrefixMapping("fuseki", Fuseki.FusekiSymbolIRI); + + // TDB1 + TDB1.setOptimizerWarningFlag(false); + // Don't use TDB1 batch commits. + // This can be slower, but it less memory hungry and more predictable. + TransactionManager.QueueBatchSize = 0; + } +} 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 fb8fee87fee..5c9f74f7d30 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 @@ -34,7 +34,7 @@ /** * FusekiLogging. *

- * This applies to Fuseki run from the command line and embedded. + * This applies to Fuseki run from the command line, as a combined jar and as an embedded server. *

* This does not apply to Fuseki running in Tomcat where it uses the * servlet 3.0 mechanism described in @@ -49,10 +49,9 @@ public class FusekiLogging // Set logging. // 1/ Use system property log4j2.configurationFile if defined. - // 2/ Use file:log4j2.properties if exists + // 2/ Use file:log4j2.properties if exists [Jena extension] // 3/ Use log4j2.properties on the classpath. - // 4/ Use org/apache/jena/fuseki/log4j2.properties on the classpath. - // 5/ Use built in string + // 4/ Use built in string /** * Places for the log4j properties file at (3). diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiLib.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiLib.java index 0b0d152525d..d385d468bb4 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiLib.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/FusekiLib.java @@ -21,20 +21,24 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; +import jakarta.servlet.ServletContext; +import org.apache.jena.atlas.logging.Log; +import org.apache.jena.fuseki.Fuseki; import org.apache.jena.fuseki.access.AccessCtl_AllowGET; import org.apache.jena.fuseki.access.AccessCtl_Deny; import org.apache.jena.fuseki.access.AccessCtl_GSP_R; import org.apache.jena.fuseki.access.AccessCtl_SPARQL_QueryDataset; -import org.apache.jena.fuseki.server.DataAccessPointRegistry; -import org.apache.jena.fuseki.server.Endpoint; -import org.apache.jena.fuseki.server.Operation; +import org.apache.jena.fuseki.build.FusekiConfig; +import org.apache.jena.fuseki.server.*; import org.apache.jena.fuseki.servlets.ActionService; import org.apache.jena.fuseki.servlets.GSP_RW; import org.apache.jena.fuseki.servlets.HttpAction; +import org.apache.jena.rdf.model.Model; import org.apache.jena.riot.WebContent; /** Actions on and about a {@link FusekiServer} */ @@ -52,6 +56,38 @@ public static Collection names(FusekiServer server) { return names; } + /** + * Process a configuration mode to find the DataServices and reset the server + * {@link DataAccessPointRegistry}. The only server-level setting processed is + * the {@code fuseki:services} list; other settings are ignored. + */ + public static void reload(FusekiServer server, Model configuration) { + // See also FusekiServer.applyDatabaseSetup + // prepareDataServices(dapRegistry, operationReg); + // OperationRegistry.set(servletContext, operationReg); + // DataAccessPointRegistry.set(servletContext, dapRegistry); + DataAccessPointRegistry newRegistry = new DataAccessPointRegistry(); + OperationRegistry operationRegistry = server.getOperationRegistry(); + + try { + List newDAPs = FusekiConfig.servicesAndDatasets(configuration.getGraph()); + newDAPs.forEach(dap->newRegistry.register(dap)); + FusekiServer.Builder.prepareDataServices(newRegistry, operationRegistry); + // Reload : switch DataAccessPointRegistry + setDataAccessPointRegistry(server, newRegistry); + } catch (RuntimeException ex) { + Log.error(Fuseki.serverLog, "Failed to load a new configuration", ex); + } + } + + public static void setDataAccessPointRegistry(FusekiServer server, DataAccessPointRegistry newRegistry) { + Objects.requireNonNull(server, "server"); + Objects.requireNonNull(newRegistry, "newRegistry"); + ServletContext cxt = server.getServletContext(); + // This is atomic (in Jetty, it is backed by a ConcurrentHashMap). + DataAccessPointRegistry.set(cxt, newRegistry); + } + /** * Return a {@code FusekiServer.Builder} setup for data access control. */ @@ -82,7 +118,6 @@ public static FusekiServer.Builder fusekiBuilderAccessCtl(FusekiServer.Builder b public static void modifyForAccessCtl(DataAccessPointRegistry dapRegistry, Function determineUser) { dapRegistry.forEach((name, dap) -> { dap.getDataService().forEachEndpoint(ep->{ - Operation op = ep.getOperation(); modifyForAccessCtl(ep, determineUser); }); }); 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 40b968e9f2d..079ff9a4374 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 @@ -28,7 +28,6 @@ import java.util.function.Function; import java.util.function.Predicate; - import jakarta.servlet.Filter; import jakarta.servlet.ServletContext; import jakarta.servlet.http.HttpServlet; @@ -40,6 +39,8 @@ import org.apache.jena.atlas.lib.IRILib; import org.apache.jena.atlas.lib.Pair; import org.apache.jena.atlas.lib.Registry; +import org.apache.jena.atlas.logging.FmtLog; +import org.apache.jena.atlas.logging.Log; import org.apache.jena.atlas.web.AuthScheme; import org.apache.jena.fuseki.Fuseki; import org.apache.jena.fuseki.FusekiConfigException; @@ -57,11 +58,12 @@ import org.apache.jena.graph.Graph; import org.apache.jena.graph.Node; import org.apache.jena.query.Dataset; -import org.apache.jena.rdf.model.*; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.Resource; import org.apache.jena.sparql.core.DatasetGraph; import org.apache.jena.sparql.core.assembler.AssemblerUtils; import org.apache.jena.sparql.util.Context; -import org.apache.jena.sys.JenaSystem; import org.apache.jena.system.G; import org.apache.jena.system.RDFDataException; import org.apache.jena.web.HttpSC; @@ -110,7 +112,9 @@ */ public class FusekiServer { - static { JenaSystem.init(); } + static { + InitFusekiMain.init(); + } /** * Construct a Fuseki server from command line arguments. @@ -143,8 +147,20 @@ public static Builder create() { * dispatches to an operation, and an operation maps to an implementation. This is a * specialised operation - normal use is the operation {@link #create()}. */ - public static Builder create(OperationRegistry serviceDispatchRegistry) { - return new Builder(serviceDispatchRegistry); + public static Builder create(OperationRegistry operationRegistry) { + return new Builder(operationRegistry); + } + + /** + * Return the {@code FusekiServer} associated with a {@link ServletContext}. + *

+ * This will return null if the {@link ServletContext} is not from a FusekiServer. + */ + public static FusekiServer get(ServletContext cxt) { + FusekiServer server = (FusekiServer)cxt.getAttribute(Fuseki.attrFusekiServer); + if ( server == null ) + Log.warn(Fuseki.serverLog, "No FusekiServer resgiterd in ServletContext"); + return server; } /** @@ -162,18 +178,24 @@ public static Builder create(OperationRegistry serviceDispatchRegistry) { private int httpsPort; private final String staticContentDir; private final ServletContext servletContext; + private final String configFilename; private final FusekiModules modules; private FusekiServer(int httpPort, int httpsPort, Server server, String staticContentDir, FusekiModules modules, + String configFilename, ServletContext fusekiServletContext) { this.server = Objects.requireNonNull(server); this.httpPort = httpPort; this.httpsPort = httpsPort; this.staticContentDir = staticContentDir; this.servletContext = Objects.requireNonNull(fusekiServletContext); + this.configFilename = configFilename; this.modules = Objects.requireNonNull(modules); + + // So servlets can find the server. + servletContext.setAttribute(Fuseki.attrFusekiServer, this); } /** @@ -301,6 +323,14 @@ public FusekiModules getModules() { return modules; } + /** + * Return the filename of the configuration file. + * Returns null if configuration was by APIs and there is no such file was used. + */ + public String getConfigFilename() { + return configFilename; + } + /** * Start the server - the server continues to run after this call returns. * To synchronise with the server stopping, call {@link #join}. @@ -410,6 +440,9 @@ public static class Builder { private boolean withTasks = false; private String jettyServerConfig = null; + + // Record calls to parseConfigFile. + private String configFileName = null; private Model configModel = null; private Map corsInitParams = null; @@ -775,12 +808,34 @@ public Builder add(String name, DataService dataService) { /** * Configure using a Fuseki services/datasets assembler file. *

- * The application is responsible for ensuring a correct classpath. For example, - * including a dependency on {@code jena-text} if the configuration file includes - * a text index. + * The configuration file is processed in this call so that subsequent + * builder operations can refer to data services created by this call. + *

+ * The calling application is responsible for ensuring a correct classpath. + * For example, including a dependency on {@code jena-text} if the + * configuration file includes a text index. + */ + public Builder parseConfigFile(Path filename) { + requireNonNull(filename, "filename"); + parseConfigFile(filename.toString()); + return this; + } + + /** + * Configure using a Fuseki services/datasets assembler file. + *

+ * The configuration file is processed in this call so that subsequent + * builder operations can refer to data services created by this call. + *

+ * The calling application is responsible for ensuring a correct classpath. + * For example, including a dependency on {@code jena-text} if the + * configuration file includes a text index. */ public Builder parseConfigFile(String filename) { requireNonNull(filename, "filename"); + if ( configFileName != null ) + FmtLog.warn(Fuseki.configLog, "Multiple configuration files"); + this.configFileName = filename; Model model = AssemblerUtils.readAssemblerFile(filename); parseConfig(model); return this; @@ -1347,16 +1402,20 @@ public FusekiServer build() { boolean hasFusekiSecurityHandler = applySecurityHandler(handler); // Prepare the DataAccessPointRegistry. // Put it in the servlet context. - // This would be the reload operation. - applyDatabaseSetup(handler, dapRegistry, operationReg); + applyDatabaseSetup(handler.getServletContext(), dapRegistry, operationReg); // Must be after the DataAccessPointRegistry is in the servlet context. if ( hasFusekiSecurityHandler ) applyAccessControl(handler, dapRegistry); if ( jettyServerConfig != null ) { + // Jetty server configuration provided. Server server = jettyServer(handler, jettyServerConfig); - return new FusekiServer(-1, -1, server, staticContentDir, modules, handler.getServletContext()); + return new FusekiServer(-1, -1, server, + staticContentDir, + modules, + configFileName, + handler.getServletContext()); } Server server; @@ -1381,7 +1440,11 @@ public FusekiServer build() { if ( networkLoopback ) applyLocalhost(server); - FusekiServer fusekiServer = new FusekiServer(httpPort, httpsPort, server, staticContentDir, modules, handler.getServletContext()); + FusekiServer fusekiServer = new FusekiServer(httpPort, httpsPort, server, + staticContentDir, + modules, + configFileName, + handler.getServletContext()); FusekiModuleStep.server(fusekiServer); return fusekiServer; } finally { @@ -1422,7 +1485,21 @@ private ServletContextHandler buildFusekiServerContext() { return handler; } - private static void prepareDataServices(DataAccessPointRegistry dapRegistry, OperationRegistry operationReg) { + /** + * Setup up a {@link ServlectContext} by setting attributes for + * {@link DataAccessPointRegistry} and {@link OperationRegistry}. + */ + private static void applyDatabaseSetup(ServletContext servletContext, + DataAccessPointRegistry dapRegistry, + OperationRegistry operationReg) { + // Final wiring up of DataAccessPointRegistry + // See also FusekiLib.reload() + prepareDataServices(dapRegistry, operationReg); + OperationRegistry.set(servletContext, operationReg); + DataAccessPointRegistry.set(servletContext, dapRegistry); + } + + /*package*/ static void prepareDataServices(DataAccessPointRegistry dapRegistry, OperationRegistry operationReg) { dapRegistry.forEach((name, dap) -> { // Override for graph-level access control. if ( DataAccessCtl.isAccessControlled(dap.getDataService().getDataset()) ) { @@ -1441,21 +1518,6 @@ private static void prepareDataServices(DataAccessPointRegistry dapRegistry, Ope }); } - /** - * Given a ServletContextHandler, set the servlet attributes for - * {@link DataAccessPointRegistry} and {@link OperationRegistry}. - */ - private static void applyDatabaseSetup(ServletContextHandler handler, - DataAccessPointRegistry dapRegistry, - OperationRegistry operationReg) { - // Final wiring up of DataAccessPointRegistry - prepareDataServices(dapRegistry, operationReg); - - ServletContext cxt = handler.getServletContext(); - OperationRegistry.set(cxt, operationReg); - DataAccessPointRegistry.set(cxt, dapRegistry); - } - private ConstraintSecurityHandler buildSecurityHandler() { UserStore userStore = JettySecurityLib.makeUserStore(passwordFile); return JettySecurityLib.makeSecurityHandler(realm, userStore, authScheme); diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/JettyServer.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/JettyServer.java index 80641c76f6d..fb65a1044f2 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/JettyServer.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/JettyServer.java @@ -393,6 +393,7 @@ private void adjustForFuseki(ServletContext cxt) { try { Fuseki.setVerbose(cxt, verbose); OperationRegistry.set(cxt, OperationRegistry.createEmpty()); + // Empty DataAccessPointRegistry, no nulls! DataAccessPointRegistry.set(cxt, new DataAccessPointRegistry()); } catch (NoClassDefFoundError err) { LOG.info("Fuseki classes not found"); 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 c6832a8d940..82c63ae4f05 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 @@ -42,6 +42,7 @@ import org.apache.jena.fuseki.main.sys.FusekiAutoModules; import org.apache.jena.fuseki.main.sys.FusekiModules; import org.apache.jena.fuseki.main.sys.FusekiServerArgsCustomiser; +import org.apache.jena.fuseki.main.sys.InitFusekiMain; import org.apache.jena.fuseki.server.DataAccessPoint; import org.apache.jena.fuseki.server.DataAccessPointRegistry; import org.apache.jena.fuseki.server.FusekiCoreInfo; @@ -157,6 +158,7 @@ public static FusekiServer build(String... args) { */ public static void run(String... argv) { JenaSystem.init(); + InitFusekiMain.init(); new FusekiMain(argv).mainRun(); } diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/mgt/ActionReload.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/mgt/ActionReload.java new file mode 100644 index 00000000000..410afb976f7 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/mgt/ActionReload.java @@ -0,0 +1,66 @@ +/* + * 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.mgt; + +import org.apache.jena.atlas.logging.FmtLog; +import org.apache.jena.fuseki.Fuseki; +import org.apache.jena.fuseki.ctl.ActionCtl; +import org.apache.jena.fuseki.main.FusekiLib; +import org.apache.jena.fuseki.main.FusekiServer; +import org.apache.jena.fuseki.servlets.HttpAction; +import org.apache.jena.fuseki.servlets.ServletOps; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.riot.RDFParser; +import org.apache.jena.riot.web.HttpNames; + +/** + * Administration action to reload the server's dataset configuration. + *

+ * This is done by reading the configuration file which may have changed since server startup. + *

+ * If the server does not have a configuration file (e.g. command line or programmatic configuration) + */ +public class ActionReload extends ActionCtl { + + @Override + public void validate(HttpAction action) { + if ( action.getRequestMethod() != HttpNames.METHOD_POST ) { + ServletOps.errorMethodNotAllowed(action.getRequestMethod()); + } + } + + @Override + public void execute(HttpAction action) { + FusekiServer server = FusekiServer.get(action.getRequest().getServletContext()); + if ( server == null ) { + ServletOps.errorOccurred("Failed to find the server for this action"); + return; + } + + String configFilename = server.getConfigFilename(); + if ( configFilename == null ) { + FmtLog.warn(Fuseki.serverLog, "[%d] Server does not have an associated configuration file", action.id); + ServletOps.errorBadRequest("Server does not have an associated configuration file"); + return; + } + Model model = RDFParser.source(configFilename).toModel(); + FmtLog.info(Fuseki.serverLog, "[%d] Reload configuration", action.id); + FusekiLib.reload(server, model); + } +} 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 59b57e64657..45e05577d3c 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 @@ -26,17 +26,19 @@ import org.apache.jena.atlas.lib.Lib; import org.apache.jena.atlas.lib.Version; import org.apache.jena.atlas.logging.FmtLog; -import org.apache.jena.fuseki.Fuseki; import org.apache.jena.fuseki.FusekiConfigException; import org.apache.jena.fuseki.main.FusekiServer; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Management of {@link FusekiAutoModule automatically loaded modules} found via {@link ServiceLoader}. */ public class FusekiAutoModules { - private static final Logger LOG = Fuseki.serverLog; + // Separate from Fuseki.serverLog; + private static final Logger LOG = LoggerFactory.getLogger(FusekiAutoModules.class); + private static final Object lock = new Object(); public static final String logLoadingProperty = "fuseki.logLoading"; @@ -173,7 +175,7 @@ private void discoveryWarnLegacy() { try { ServiceLoader newServiceLoader = ServiceLoader.load(moduleClass, this.getClass().getClassLoader()); newServiceLoader.stream().forEach(provider->{ - FmtLog.warn(FusekiAutoModules.class, "Ignored: \"%s\" : legacy use of interface FusekiModule which has changed to FusekiAutoModule", provider.type().getSimpleName()); + FmtLog.warn(LOG, "Ignored: \"%s\" : legacy use of interface FusekiModule which has changed to FusekiAutoModule", provider.type().getSimpleName()); }); } catch (ServiceConfigurationError ex) { // Ignore - we were only checking. @@ -218,7 +220,7 @@ private FusekiModules load() { String name = m.name(); if ( name == null ) name = m.getClass().getSimpleName(); - FmtLog.info(LOG, "Module: %s (%s)", + FmtLog.debug(LOG, "Module: %s (%s)", name, Version.versionForClass(m.getClass()).orElse("unknown")); }); diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiLifecycle.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiLifecycle.java index 70ddbb3973a..365346715a3 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiLifecycle.java +++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/FusekiLifecycle.java @@ -24,7 +24,7 @@ * A {@link SubsystemLifecycle} for Fuseki. * This lifecycle is run after Jena system initialization. * Jena system initialization includes system initialization of Fuseki itself - * in {@link InitFuseki}. + * in {@link InitFusekiMain}. * This lifecycle is for extensions to an initialized Fuseki server * and is used via {@link FusekiAutoModule}. */ 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 7735c187b47..1a320f5d21c 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 @@ -77,7 +77,7 @@ public static void serverStopped(FusekiServer server) { } /** - * Sever reload. + * Server reload. * Return true if reload happened, else false. * @see FusekiBuildCycle#serverConfirmReload * @see FusekiBuildCycle#serverReload 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/InitFusekiMain.java similarity index 83% rename from jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/InitFuseki.java rename to jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/main/sys/InitFusekiMain.java index ef6259d065f..b61ab50a254 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/InitFusekiMain.java @@ -20,6 +20,7 @@ import org.apache.jena.cmd.Cmds; import org.apache.jena.fuseki.main.cmds.FusekiMainCmd; +import org.apache.jena.fuseki.system.FusekiCore; import org.apache.jena.sys.JenaSubsystemLifecycle; import org.apache.jena.sys.JenaSystem; @@ -28,7 +29,7 @@ * Level 101 - called during Jena system initialization * and after Jena itself has initialized. */ -public class InitFuseki implements JenaSubsystemLifecycle { +public class InitFusekiMain implements JenaSubsystemLifecycle { private static volatile boolean initialized = false; @@ -45,7 +46,8 @@ public static void init() { if ( initialized ) { return; } - synchronized (InitFuseki.class) { + + synchronized (InitFusekiMain.class) { if ( initialized ) { JenaSystem.logLifecycle("Fuseki.init - skip"); return; @@ -53,7 +55,12 @@ public static void init() { initialized = true; JenaSystem.logLifecycle("Fuseki.init - start"); + // Ensure core constants are initialized first. + FusekiCore.init(); FusekiModules.init(); + + // Leave until known to be needed FusekiServer build with no specific FusekikModules given. + // FusekiModulesCtl.setup(); try { Cmds.injectCmd("fuseki", a->FusekiMainCmd.main(a)); } catch (NoClassDefFoundError ex) { diff --git a/jena-fuseki2/jena-fuseki-main/src/main/resources/META-INF/services/org.apache.jena.sys.JenaSubsystemLifecycle b/jena-fuseki2/jena-fuseki-main/src/main/resources/META-INF/services/org.apache.jena.sys.JenaSubsystemLifecycle index 892450f9114..d6287470161 100644 --- a/jena-fuseki2/jena-fuseki-main/src/main/resources/META-INF/services/org.apache.jena.sys.JenaSubsystemLifecycle +++ b/jena-fuseki2/jena-fuseki-main/src/main/resources/META-INF/services/org.apache.jena.sys.JenaSubsystemLifecycle @@ -1 +1 @@ -org.apache.jena.fuseki.main.sys.InitFuseki +org.apache.jena.fuseki.main.sys.InitFusekiMain diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/CustomTestService.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/CustomTestService.java index a7b8cdbf18f..4fc40a60c22 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/CustomTestService.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/CustomTestService.java @@ -76,6 +76,6 @@ protected void doPost(HttpAction action) { public void validate(HttpAction action) { } private void notSupported(HttpAction action) { - ServletOps.errorMethodNotAllowed(action.getMethod()+" "+action.getDatasetName()); + ServletOps.errorMethodNotAllowed(action.getRequestMethod()+" "+action.getDatasetName()); } } diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java index e0fa22d5e82..2a982b95427 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TS_FusekiMain.java @@ -55,9 +55,11 @@ , TestFusekiCustomScriptFunc.class , PrefixesServiceTests.class - , TestMetrics.class , TestFusekiShaclValidation.class + + , TestFusekiMainAdmin.class + }) public class TS_FusekiMain {} diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainAdmin.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainAdmin.java new file mode 100644 index 00000000000..57af3a985ec --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiMainAdmin.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.fuseki.main; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; + +import org.apache.jena.atlas.io.IOX; +import org.apache.jena.atlas.logging.LogCtl; +import org.apache.jena.fuseki.Fuseki; +import org.apache.jena.fuseki.main.mgt.ActionReload; +import org.apache.jena.http.HttpOp; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.riot.RDFParser; +import org.apache.jena.sparql.core.DatasetGraph; +import org.apache.jena.sparql.core.DatasetGraphFactory; +import org.apache.jena.sparql.engine.http.QueryExceptionHTTP; +import org.apache.jena.sparql.exec.QueryExec; +import org.apache.jena.sparql.exec.RowSetOps; +import org.apache.jena.sparql.exec.http.QueryExecHTTP; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; + +public class TestFusekiMainAdmin { + + private static Path fConfigServer = Path.of("target/config-reload.ttl"); + private static Path DIR = Path.of("testing/Config/"); + private static Path fConfig1 = DIR.resolve("reload-config1.ttl"); + private static Path fConfig2 = DIR.resolve("reload-config2.ttl"); + + @Before public void before() { + // Initial state + copyFile(fConfig1, fConfigServer); + } + + @AfterClass public static void after() { + try { + Files.delete(fConfigServer); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + + @Test public void serverReload_1() { + FusekiServer server = server(fConfigServer); + try { + server.start(); + + serverBeforeReload(server); + + // Change configuration file. + copyFile(fConfig2, fConfigServer); + Model newConfig = RDFParser.source(fConfigServer).toModel(); + + // Reload operation on the server + HttpOp.httpPost("http://localhost:"+server.getPort()+"/$/reload"); + + serverAfterReload(server); + } + finally { server.stop(); } + } + + @Test public void serverReload_2() { + FusekiServer server = serverNoConfigFile(); + try { + server.start(); + + serverBeforeReload(server); + + // Change configuration file. + // Error! + copyFile(fConfig2, fConfigServer); + Model newConfig = RDFParser.source(fConfigServer).toModel(); + + LogCtl.withLevel(Fuseki.serverLog, "ERROR", ()-> + // Poke server - Operation denied - no configuration file. + FusekiTestLib.expect400(()->HttpOp.httpPost("http://localhost:"+server.getPort()+"/$/reload")) + ); + + // No change + serverBeforeReload(server); + } + finally { server.stop(); } + } + + private static void copyFile(Path pathSrc, Path pathDest) { + try { + Files.copy(pathSrc, pathDest, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException ex) { throw IOX.exception(ex); } + } + + private static void serverBeforeReload(FusekiServer server) { + String URL = "http://localhost:"+server.getPort()+"/$/ping"; + String x = HttpOp.httpGetString(URL); + query(server, "/ds", "SELECT * { }", 200); + query(server, "/dataset2", "SELECT * { ?s ?p ?o }", 404); + query(server, "/zero", "SELECT * { }", 404); + query(server, "/codedsg", "SELECT * { }", 200); + } + + private static void serverAfterReload(FusekiServer server) { + String URL = "http://localhost:"+server.getPort()+"/$/ping"; + String x = HttpOp.httpGetString(URL); + query(server, "/ds", "SELECT * { }", 404); + query(server, "/dataset2", "SELECT * { ?s ?p ?o }", 200); + query(server, "/zero", "SELECT * { }", 404); + // Replaced. + query(server, "/codedsg", "SELECT * { }", 404); + } + + private static void query(FusekiServer server, String datasetName, String queryString, int expectedStatusCode) { + QueryExec qExec = QueryExecHTTP.service(server.datasetURL(datasetName)).query(queryString).build(); + try { + RowSetOps.consume(qExec.select()); + assertEquals(datasetName, expectedStatusCode, 200); + } catch (QueryExceptionHTTP ex) { + assertEquals(datasetName, expectedStatusCode, ex.getStatusCode()); + } + } + + private static FusekiServer serverNoConfigFile() { + DatasetGraph dsg = DatasetGraphFactory.createTxnMem(); + FusekiServer server = FusekiServer.create().port(0) + // .verbose(true) + .addServlet("/$/reload", new ActionReload()) + .add("/ds", dsg) + .add("/codedsg", dsg) + .build(); + return server; + } + + + private static FusekiServer server(Path fConfig) { + DatasetGraph dsg = DatasetGraphFactory.createTxnMem(); + FusekiServer server = FusekiServer.create().port(0) + // .verbose(true) + .addServlet("/$/reload", new ActionReload()) + .parseConfigFile(fConfig) + .add("/codedsg", dsg) + .build(); + return server; + } +} 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 8a223165193..c31c8b0c9b3 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 @@ -339,7 +339,7 @@ public void test_error_argConfigFile_wrongFormat() { List arguments = List.of("--file=testing/Config/invalid.ttl", "/dataset"); String expectedMessage = "Failed to load file: testing/Config/invalid.ttl"; // when, then - LogCtl.withLevel(SysRIOT.getLogger(), "fatal", + LogCtl.withLevel(SysRIOT.getLogger(), "FATAL", ()-> testForCmdException(arguments, expectedMessage) ); } @@ -459,7 +459,6 @@ private void testForCmdException(List arguments, String expectedMessage) assertEquals("Expecting correct message", expectedMessage, actual.getMessage()); } - private static String[] buildCmdLineArguments(List listArgs) { return listArgs.toArray(new String[0]); } diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiServerBuild.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiServerBuild.java index cefa3ae31d3..611ca3a80e0 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiServerBuild.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestFusekiServerBuild.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.util.function.Consumer; +import jakarta.servlet.ServletContext; import org.apache.jena.atlas.iterator.Iter; import org.apache.jena.atlas.logging.Log; import org.apache.jena.atlas.logging.LogCtl; @@ -60,9 +61,13 @@ public class TestFusekiServerBuild { @Test public void fuseki_build_1() { FusekiServer server = FusekiServer.create().port(3456).build(); - // Not started. Port not assigned. assertTrue(server.getHttpPort() == 3456 ); assertTrue(server.getHttpsPort() == -1 ); + + ServletContext cxt = server.getServletContext(); + FusekiServer server2 = FusekiServer.get(cxt); + assertNotNull(server2); + assertEquals(server, server2); } @Test public void fuseki_build_2() { diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestPlainServer.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestPlainServer.java index 7aec058fa89..424cda10070 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestPlainServer.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/TestPlainServer.java @@ -109,7 +109,7 @@ public static void afterClass() { } @Test public void plainFile3() { - String x = HttpOp.httpGetString(serverURL+"/file-top.txt"); + String x = HttpOp.httpGetString(serverURL+"/exists.txt"); assertNotNull(x); assertTrue(x.contains("CONTENT")); } diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/access/AbstractTestFusekiSecurityAssembler.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/access/AbstractTestFusekiSecurityAssembler.java index 5d823fad799..ade33038b79 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/access/AbstractTestFusekiSecurityAssembler.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/access/AbstractTestFusekiSecurityAssembler.java @@ -36,6 +36,7 @@ import org.apache.jena.fuseki.Fuseki; import org.apache.jena.fuseki.main.FusekiLib; import org.apache.jena.fuseki.main.FusekiServer; +import org.apache.jena.fuseki.main.sys.InitFusekiMain; import org.apache.jena.graph.Node; import org.apache.jena.query.Dataset; import org.apache.jena.query.QuerySolution; @@ -46,7 +47,6 @@ import org.apache.jena.sparql.core.DatasetGraph; import org.apache.jena.sparql.core.Quad; import org.apache.jena.sparql.sse.SSE; -import org.apache.jena.sys.JenaSystem; import org.apache.jena.system.Txn; import org.junit.AfterClass; import org.junit.Before; @@ -63,7 +63,7 @@ */ public abstract class AbstractTestFusekiSecurityAssembler { - static { JenaSystem.init(); } + static { InitFusekiMain.init(); } static final String DIR = "testing/Access/"; private final String assemblerFile; diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/DemoService.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/DemoService.java index b83273b7648..6db9b378cab 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/DemoService.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/DemoService.java @@ -79,6 +79,6 @@ protected void doPost(HttpAction action) { public void validate(HttpAction action) { } private void notSupported(HttpAction action) { - ServletOps.errorMethodNotAllowed(action.getMethod()+" "+action.getActionURI()); + ServletOps.errorMethodNotAllowed(action.getRequestMethod()+" "+action.getActionURI()); } } diff --git a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExFuseki_04_CustomOperation_Inline.java b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExFuseki_04_CustomOperation_Inline.java index fce39ffd2de..38aef337da9 100644 --- a/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExFuseki_04_CustomOperation_Inline.java +++ b/jena-fuseki2/jena-fuseki-main/src/test/java/org/apache/jena/fuseki/main/examples/ExFuseki_04_CustomOperation_Inline.java @@ -25,6 +25,7 @@ import org.apache.jena.fuseki.build.FusekiExt; import org.apache.jena.fuseki.main.FusekiServer; import org.apache.jena.fuseki.main.sys.FusekiModule; +import org.apache.jena.fuseki.main.sys.InitFusekiMain; import org.apache.jena.fuseki.server.Operation; import org.apache.jena.fuseki.servlets.ActionService; import org.apache.jena.fuseki.servlets.HttpAction; @@ -32,7 +33,6 @@ import org.apache.jena.http.HttpOp; import org.apache.jena.riot.WebContent; import org.apache.jena.sparql.core.DatasetGraphFactory; -import org.apache.jena.sys.JenaSystem; import org.apache.jena.web.HttpSC; /** @@ -46,8 +46,8 @@ public class ExFuseki_04_CustomOperation_Inline { static { - JenaSystem.init(); FusekiLogging.setLogging(); + InitFusekiMain.init(); } public static void main(String...args) { 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 b9429c34233..e4791698b5a 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 @@ -27,6 +27,7 @@ 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.InitFusekiMain; import org.apache.jena.fuseki.server.Operation; import org.apache.jena.fuseki.servlets.ActionService; import org.apache.jena.fuseki.servlets.HttpAction; @@ -35,7 +36,6 @@ import org.apache.jena.rdf.model.Model; import org.apache.jena.riot.WebContent; import org.apache.jena.sparql.core.DatasetGraphFactory; -import org.apache.jena.sys.JenaSystem; import org.apache.jena.web.HttpSC; /** @@ -48,8 +48,8 @@ public class ExFuseki_04_CustomOperation_Module { static { - JenaSystem.init(); FusekiLogging.setLogging(); + InitFusekiMain.init(); } // Example usage. diff --git a/jena-fuseki2/jena-fuseki-main/testing/Config/reload-config1.ttl b/jena-fuseki2/jena-fuseki-main/testing/Config/reload-config1.ttl new file mode 100644 index 00000000000..3e916dbfe87 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/testing/Config/reload-config1.ttl @@ -0,0 +1,16 @@ +PREFIX : <#> +PREFIX fuseki: +PREFIX rdf: +PREFIX rdfs: +PREFIX ja: + +:service rdf:type fuseki:Service ; + fuseki:name "ds" ; + fuseki:endpoint [ fuseki:operation fuseki:query ; ] ; + fuseki:endpoint [ fuseki:operation fuseki:update ; ] ; + fuseki:endpoint [ fuseki:operation fuseki:gsp-rw ; ] ; + fuseki:endpoint [ fuseki:operation fuseki:patch ; ] ; + fuseki:dataset :dataset ; +. + +:dataset rdf:type ja:MemoryDataset . diff --git a/jena-fuseki2/jena-fuseki-main/testing/Config/reload-config2.ttl b/jena-fuseki2/jena-fuseki-main/testing/Config/reload-config2.ttl new file mode 100644 index 00000000000..bad6403a748 --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/testing/Config/reload-config2.ttl @@ -0,0 +1,25 @@ +PREFIX : <#> +PREFIX fuseki: +PREFIX rdf: +PREFIX rdfs: +PREFIX ja: + +:service rdf:type fuseki:Service ; + fuseki:name "dataset2" ; + fuseki:endpoint [ fuseki:operation fuseki:query ; ] ; + fuseki:endpoint [ fuseki:operation fuseki:update ; ] ; + fuseki:endpoint [ fuseki:operation fuseki:gsp-rw ; ] ; + fuseki:endpoint [ fuseki:operation fuseki:patch ; ] ; + fuseki:dataset :dataset ; +. + +:dataset rdf:type ja:MemoryDataset ; + #ja:data "data.trig"; +. + +:service2 rdf:type fuseki:Service ; + fuseki:name "null" ; + ## No operations. + ## Always empty dataset. + fuseki:dataset [ rdf:type ja:RDFDatasetZero ] ; + . diff --git a/jena-fuseki2/jena-fuseki-main/testing/Files/exists.txt b/jena-fuseki2/jena-fuseki-main/testing/Files/exists.txt new file mode 100644 index 00000000000..4c5132ec87e --- /dev/null +++ b/jena-fuseki2/jena-fuseki-main/testing/Files/exists.txt @@ -0,0 +1,2 @@ +This file is used by the plain server static resource tests. +CONTENT diff --git a/jena-fuseki2/jena-fuseki-main/testing/Files/file-top.txt b/jena-fuseki2/jena-fuseki-main/testing/Files/file-top.txt deleted file mode 100644 index a980c835bc0..00000000000 --- a/jena-fuseki2/jena-fuseki-main/testing/Files/file-top.txt +++ /dev/null @@ -1,2 +0,0 @@ -# Licensed under the terms of http://www.apache.org/licenses/LICENSE-2.0 -CONTENT diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/FusekiWebappCmd.java b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/FusekiWebappCmd.java index 040c5591f5d..c64d136184d 100644 --- a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/FusekiWebappCmd.java +++ b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/FusekiWebappCmd.java @@ -31,6 +31,7 @@ import org.apache.jena.fuseki.Fuseki; import org.apache.jena.fuseki.FusekiException; import org.apache.jena.fuseki.mgt.Template; +import org.apache.jena.fuseki.system.FusekiCore; import org.apache.jena.fuseki.system.FusekiLogging; import org.apache.jena.fuseki.webapp.FusekiEnv; import org.apache.jena.fuseki.webapp.FusekiServerListener; @@ -96,7 +97,7 @@ static class FusekiCmdInner extends CmdARQ { static public void innerMain(String... argv) { JenaSystem.init(); // Do explicitly so it happens after subsystem initialization. - Fuseki.init(); + FusekiCore.init(); new FusekiCmdInner(argv).mainRun(); } diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/JettyFusekiWebapp.java b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/JettyFusekiWebapp.java index 02578d5a3a3..2af9efbebd3 100644 --- a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/JettyFusekiWebapp.java +++ b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/cmd/JettyFusekiWebapp.java @@ -31,7 +31,9 @@ import org.apache.jena.fuseki.FusekiException; import org.apache.jena.fuseki.server.DataAccessPointRegistry; import org.apache.jena.fuseki.server.FusekiCoreInfo; +import org.apache.jena.fuseki.system.FusekiCore; import org.apache.jena.fuseki.webapp.FusekiEnv; +import org.apache.jena.sys.JenaSystem; import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping; import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler; @@ -59,7 +61,10 @@ public class JettyFusekiWebapp { // This class is becoming less important - it now sets up a Jetty server for in-process use // either for the command line in development // and in testing but not direct webapp deployments. - static { Fuseki.init(); } + static { + JenaSystem.init(); + FusekiCore.init(); + } public static JettyFusekiWebapp instance = null; diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/webapp/FusekiServerEnvironmentInit.java b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/webapp/FusekiServerEnvironmentInit.java index db676f05527..85b5e5ad838 100644 --- a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/webapp/FusekiServerEnvironmentInit.java +++ b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/webapp/FusekiServerEnvironmentInit.java @@ -22,6 +22,7 @@ import jakarta.servlet.ServletContextListener; import org.apache.jena.fuseki.system.FusekiLogging; +import org.apache.jena.fuseki.system.FusekiCore; import org.apache.jena.sys.JenaSystem; /** Setup the environment and logging. @@ -49,6 +50,8 @@ public void contextInitialized(ServletContextEvent sce) { } } JenaSystem.init(); + FusekiCore.init(); + } @Override diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/webapp/FusekiWebapp.java b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/webapp/FusekiWebapp.java index cfe6d697314..7eaa7006e57 100644 --- a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/webapp/FusekiWebapp.java +++ b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/webapp/FusekiWebapp.java @@ -46,6 +46,7 @@ import org.apache.jena.fuseki.server.DataService; import org.apache.jena.fuseki.servlets.HttpAction; import org.apache.jena.fuseki.servlets.ServletOps; +import org.apache.jena.fuseki.system.FusekiCore; import org.apache.jena.graph.Graph; import org.apache.jena.rdf.model.*; import org.apache.jena.rdfs.RDFSFactory; @@ -55,6 +56,7 @@ import org.apache.jena.riot.RDFParser; import org.apache.jena.sparql.core.DatasetGraph; import org.apache.jena.sparql.core.assembler.AssemblerUtils; +import org.apache.jena.sys.JenaSystem; public class FusekiWebapp { @@ -122,7 +124,8 @@ public class FusekiWebapp Path FUSEKI_HOME = FusekiEnv.FUSEKI_HOME; Path FUSEKI_BASE = FusekiEnv.FUSEKI_BASE; - Fuseki.init(); + JenaSystem.init(); + FusekiCore.init(); Fuseki.configLog.info("FUSEKI_HOME="+ ((FUSEKI_HOME==null) ? "unset" : FUSEKI_HOME.toString())); Fuseki.configLog.info("FUSEKI_BASE="+FUSEKI_BASE.toString()); diff --git a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/webapp/ShiroEnvironmentLoader.java b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/webapp/ShiroEnvironmentLoader.java index 30e4dd0b653..389a9946fcc 100644 --- a/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/webapp/ShiroEnvironmentLoader.java +++ b/jena-fuseki2/jena-fuseki-webapp/src/main/java/org/apache/jena/fuseki/webapp/ShiroEnvironmentLoader.java @@ -26,7 +26,9 @@ import jakarta.servlet.ServletContextListener; import org.apache.jena.fuseki.Fuseki; +import org.apache.jena.fuseki.system.FusekiCore; import org.apache.jena.irix.IRIs; +import org.apache.jena.sys.JenaSystem; import org.apache.shiro.lang.io.ResourceUtils; import org.apache.shiro.web.env.EnvironmentLoader; import org.apache.shiro.web.env.ResourceBasedWebEnvironment; @@ -86,8 +88,9 @@ protected void customizeEnvironment(WebEnvironment environment) { /** Look for a Shiro ini file, or return null */ private static String huntForShiroIni(String[] locations) { + JenaSystem.init(); + FusekiCore.init(); FusekiEnv.setEnvironment(); - Fuseki.init(); for ( String loc : locations ) { // If file:, look for that file. // If a relative name without scheme, look in FUSEKI_BASE, FUSEKI_HOME, webapp. diff --git a/jena-fuseki2/jena-fuseki-webapp/src/test/java/org/apache/jena/fuseki/ServerCtl.java b/jena-fuseki2/jena-fuseki-webapp/src/test/java/org/apache/jena/fuseki/ServerCtl.java index 39838f9ed84..0a573f9c719 100644 --- a/jena-fuseki2/jena-fuseki-webapp/src/test/java/org/apache/jena/fuseki/ServerCtl.java +++ b/jena-fuseki2/jena-fuseki-webapp/src/test/java/org/apache/jena/fuseki/ServerCtl.java @@ -30,6 +30,7 @@ import org.apache.jena.fuseki.cmd.FusekiArgs; import org.apache.jena.fuseki.cmd.JettyFusekiWebapp; import org.apache.jena.fuseki.cmd.JettyServerConfig; +import org.apache.jena.fuseki.system.FusekiCore; import org.apache.jena.fuseki.webapp.FusekiEnv; import org.apache.jena.fuseki.webapp.FusekiServerListener; import org.apache.jena.fuseki.webapp.FusekiWebapp; @@ -37,6 +38,7 @@ import org.apache.jena.sparql.core.DatasetGraphFactory; import org.apache.jena.sparql.modify.request.Target; import org.apache.jena.sparql.modify.request.UpdateDrop; +import org.apache.jena.sys.JenaSystem; import org.apache.jena.system.Txn; import org.apache.jena.update.Update; import org.apache.jena.update.UpdateExecutionFactory; @@ -83,7 +85,10 @@ * */ public class ServerCtl { - static { Fuseki.init(); } + static { + JenaSystem.init(); + FusekiCore.init(); + } /* Cut&Paste versions: