diff --git a/exist-core/src/main/java/org/exist/backup/xquery/BackupModule.java b/exist-core/src/main/java/org/exist/backup/xquery/BackupModule.java index f86d74dd085..d8b0114a468 100644 --- a/exist-core/src/main/java/org/exist/backup/xquery/BackupModule.java +++ b/exist-core/src/main/java/org/exist/backup/xquery/BackupModule.java @@ -75,4 +75,8 @@ public String getReleaseVersion() return( RELEASED_IN_VERSION ); } + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return BackupModule.class; } + } } diff --git a/exist-core/src/main/java/org/exist/indexing/IndexFactory.java b/exist-core/src/main/java/org/exist/indexing/IndexFactory.java new file mode 100644 index 00000000000..283ba4ab476 --- /dev/null +++ b/exist-core/src/main/java/org/exist/indexing/IndexFactory.java @@ -0,0 +1,42 @@ +/* + * eXist-db Open Source Native XML Database + * Copyright (C) 2001 The eXist-db Authors + * + * info@exist-db.org + * http://www.exist-db.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.indexing; + +/** + * SPI for index module auto-discovery via {@code ServiceLoader}. + * + *

Register implementations in + * {@code META-INF/services/org.exist.indexing.IndexFactory}. + * A conf.xml {@code } entry with the same id takes precedence; + * an entry with {@code enabled="no"} suppresses the SPI-registered module.

+ */ +public interface IndexFactory { + + /** + * The default conf.xml {@code id} for this index (e.g. {@code "lucene-index"}). + * Used as the key in the index registry and to match conf.xml override entries. + */ + String getDefaultId(); + + /** The concrete {@link AbstractIndex} subclass to instantiate. */ + Class getIndexClass(); +} diff --git a/exist-core/src/main/java/org/exist/indexing/IndexManager.java b/exist-core/src/main/java/org/exist/indexing/IndexManager.java index 786af20cd21..ca74af5be35 100644 --- a/exist-core/src/main/java/org/exist/indexing/IndexManager.java +++ b/exist-core/src/main/java/org/exist/indexing/IndexManager.java @@ -124,10 +124,7 @@ public void prepare(final BrokerPool brokerPool) throws BrokerPoolServiceExcepti // check if a structural index was configured. If not, create one based on default settings. AbstractIndex structural = (AbstractIndex) indexers.get(StructuralIndex.STRUCTURAL_INDEX_ID); if (structural == null) { - structural = initIndex(pool, StructuralIndex.STRUCTURAL_INDEX_ID, null, dataDir, StructuralIndex.DEFAULT_CLASS); - if (structural != null) { - structural.setName(StructuralIndex.STRUCTURAL_INDEX_ID); - } + initIndex(pool, StructuralIndex.STRUCTURAL_INDEX_ID, null, dataDir, StructuralIndex.DEFAULT_CLASS); } } catch(final DatabaseConfigurationException e) { throw new BrokerPoolServiceException(e); @@ -145,6 +142,9 @@ private AbstractIndex initIndex(final BrokerPool pool, final String id, final El } final AbstractIndex index = (AbstractIndex) clazz.newInstance(); index.configure(pool, dataDir, config); + if (index.getIndexName() == null && id != null && !id.isBlank()) { + index.setName(id); + } index.open(); indexers.put(id, index); if (LOG.isInfoEnabled()) { diff --git a/exist-core/src/main/java/org/exist/storage/vector/VectorStoreServiceImpl.java b/exist-core/src/main/java/org/exist/storage/vector/VectorStoreServiceImpl.java index c75264de60d..7410368d16b 100644 --- a/exist-core/src/main/java/org/exist/storage/vector/VectorStoreServiceImpl.java +++ b/exist-core/src/main/java/org/exist/storage/vector/VectorStoreServiceImpl.java @@ -55,6 +55,18 @@ public void configure(final Configuration configuration) throws BrokerPoolServic if (dataDir == null) { throw new BrokerPoolServiceException("Could not determine " + BrokerPool.PROPERTY_DATA_DIR + " from the configuration"); } + configureVectorModelRegistry(configuration); + } + + private static void configureVectorModelRegistry(final Configuration configuration) { + try { + final Class registryClass = Class.forName("org.exist.vector.ModelRegistry"); + registryClass.getMethod("configure", Configuration.class).invoke(null, configuration); + } catch (final ClassNotFoundException e) { + LOG.debug("Vector extension not present; vector model registry not configured"); + } catch (final ReflectiveOperationException e) { + LOG.warn("Failed to configure vector model registry: {}", e.getMessage(), e); + } } @Override diff --git a/exist-core/src/main/java/org/exist/util/Configuration.java b/exist-core/src/main/java/org/exist/util/Configuration.java index bbead109e73..84b8cb27484 100644 --- a/exist-core/src/main/java/org/exist/util/Configuration.java +++ b/exist-core/src/main/java/org/exist/util/Configuration.java @@ -36,6 +36,7 @@ import org.exist.storage.lock.LockTable; import org.exist.util.io.ContentFilePool; import org.exist.xquery.Expression; +import org.exist.xquery.ModuleFactory; import org.exist.xquery.PerformanceStats; import org.exist.xquery.XQueryWatchDog; import org.w3c.dom.Document; @@ -50,6 +51,7 @@ import org.xml.sax.XMLReader; import org.exist.Indexer; +import org.exist.indexing.IndexFactory; import org.exist.indexing.IndexManager; import org.exist.dom.memtree.SAXAdapter; import org.exist.scheduler.JobConfig; @@ -76,9 +78,12 @@ import java.util.Locale; import java.util.HashMap; import java.util.Map; +import java.util.HashSet; import java.util.Map.Entry; import java.util.Optional; import java.util.Properties; +import java.util.ServiceLoader; +import java.util.Set; import java.util.function.Function; import javax.annotation.Nullable; @@ -232,6 +237,7 @@ public class Configuration implements ErrorHandler { public static final String BINARY_CACHE_CLASS_PROPERTY = "binary.cache.class"; + public static final String PROPERTY_VECTOR_MODELS = "vector.models"; private static final String PRP_DETAILS = "{}: {}"; private static final Logger LOG = LogManager.getLogger(Configuration.class); //Logger private static final String XQUERY_CONFIGURATION_ELEMENT_NAME = "xquery"; @@ -376,6 +382,8 @@ public Configuration(@Nullable String configFilename, Optional existHomeDi configureElement(doc, XMLReaderObjectFactory.CONFIGURATION_ELEMENT_NAME, element -> configureValidation(existHomePath, element)); // RPC server configureElement(doc, "rpc-server", this::configureRpcServer); + // Vector model registry + configureElement(doc, "vector-models", this::configureVectorModels); } catch (final SAXException | IOException | ParserConfigurationException e) { LOG.error("error while reading config file: {}", configFilename, e); throw new DatabaseConfigurationException(e.getMessage(), e); @@ -573,6 +581,18 @@ private void loadModuleClasses(final Element xquery, // add the standard function module modulesClassMap.put(XPATH_FUNCTIONS_NS, org.exist.xquery.functions.fn.FnModule.class); + // SPI-discovered modules: any JAR on the classpath that provides a ModuleFactory + // implementation in META-INF/services/org.exist.xquery.ModuleFactory is auto-registered. + // conf.xml entries processed below can override or suppress these entries. + ServiceLoader.load(ModuleFactory.class, Configuration.class.getClassLoader()) + .forEach(factory -> { + final String uri = factory.getNamespaceURI(); + if (!modulesClassMap.containsKey(uri)) { + modulesClassMap.put(uri, factory.getModuleClass()); + LOG.debug("Auto-registered module '{}' via ModuleFactory SPI", uri); + } + }); + // add other modules specified in configuration configureElement(xquery, XQUERY_BUILTIN_MODULES_CONFIGURATION_MODULES_ELEMENT_NAME, builtIn -> { @@ -591,6 +611,13 @@ private void loadModuleClasses(final Element xquery, throw (new DatabaseConfigurationException("element 'module' requires an attribute 'uri'")); } + // enabled="no" disables the module; also suppresses any SPI-discovered entry + if ("no".equalsIgnoreCase(elem.getAttribute("enabled"))) { + LOG.debug("Module '{}' is disabled via enabled=\"no\", skipping", uri); + modulesClassMap.remove(uri); + continue; + } + final String clazz = elem.getAttribute(BUILT_IN_MODULE_CLASS_ATTRIBUTE); final String source = elem.getAttribute(BUILT_IN_MODULE_SOURCE_ATTRIBUTE); // either class or source attribute must be present @@ -836,6 +863,12 @@ private void configureScheduler(final Element scheduler) { } private void addJobToList(final List jobList, final Element job) { + // enabled="no" disables the job without removing it from conf.xml + if ("no".equalsIgnoreCase(getConfigAttributeValue(job, "enabled"))) { + LOG.debug("Job '{}' is disabled via enabled=\"no\", skipping", getConfigAttributeValue(job, JOB_NAME_ATTRIBUTE)); + return; + } + //get the job type final String strJobType = getConfigAttributeValue(job, JOB_TYPE_ATTRIBUTE); @@ -1107,6 +1140,12 @@ private void configureStartup(final Element startup) throws DatabaseConfiguratio // Get element final Element trigger = (Element) nlTrigger.item(i); + // enabled="no" disables the trigger without removing it from conf.xml + if ("no".equalsIgnoreCase(trigger.getAttribute("enabled"))) { + LOG.debug("Startup trigger '{}' is disabled via enabled=\"no\", skipping", trigger.getAttribute("class")); + continue; + } + // Get @class final String startupTriggerClass = trigger.getAttribute("class"); @@ -1191,13 +1230,23 @@ private void configureIndexer(final Document doc, final Element indexer) throws return; } final NodeList module = ((Element) modules.item(0)).getElementsByTagName(IndexManager.CONFIGURATION_MODULE_ELEMENT_NAME); - final IndexModuleConfig[] modConfig = new IndexModuleConfig[module.getLength()]; + final List modConfigList = new ArrayList<>(); + final Set configuredIds = new HashSet<>(); + final Set disabledIds = new HashSet<>(); for (int i = 0; i < module.getLength(); i++) { final Element elem = (Element) module.item(i); - final String className = elem.getAttribute(IndexManager.INDEXER_MODULES_CLASS_ATTRIBUTE); final String id = elem.getAttribute(IndexManager.INDEXER_MODULES_ID_ATTRIBUTE); + // enabled="no" disables the index module without removing it from conf.xml + if ("no".equalsIgnoreCase(elem.getAttribute("enabled"))) { + LOG.debug("Index module '{}' is disabled via enabled=\"no\", skipping", id); + disabledIds.add(id); + continue; + } + + final String className = elem.getAttribute(IndexManager.INDEXER_MODULES_CLASS_ATTRIBUTE); + if (className.isEmpty()) { throw (new DatabaseConfigurationException("Required attribute class is missing for module")); } @@ -1206,9 +1255,25 @@ private void configureIndexer(final Document doc, final Element indexer) throws throw (new DatabaseConfigurationException("Required attribute id is missing for module")); } - modConfig[i] = new IndexModuleConfig(id, className, elem); + configuredIds.add(id); + modConfigList.add(new IndexModuleConfig(id, className, elem)); + } + + // SPI: auto-discover index modules whose id is not explicitly listed in conf.xml + for (final IndexFactory factory : ServiceLoader.load(IndexFactory.class, Configuration.class.getClassLoader())) { + final String id = factory.getDefaultId(); + if (id == null || id.isBlank()) { + LOG.warn("IndexFactory {} returned a null or blank default id; skipping SPI registration", factory.getClass().getName()); + continue; + } + if (configuredIds.contains(id) || disabledIds.contains(id)) { + continue; + } + LOG.debug("SPI-registered index module: {} ({})", id, factory.getIndexClass().getName()); + modConfigList.add(new IndexModuleConfig(id, factory.getIndexClass().getName(), null)); } - setProperty(IndexManager.PROPERTY_INDEXER_MODULES, modConfig); + + setProperty(IndexManager.PROPERTY_INDEXER_MODULES, modConfigList.toArray(new IndexModuleConfig[0])); } private void configureValidation(final Optional dbHome, final Element validation) { @@ -1323,6 +1388,25 @@ private void configureRpcServer(final Element validation) throws DatabaseConfigu }); } + private void configureVectorModels(final Element vectorModels) { + if ("no".equalsIgnoreCase(vectorModels.getAttribute("enabled"))) { + return; + } + final NodeList models = vectorModels.getElementsByTagName("model"); + final Map entries = new HashMap<>(); + for (int i = 0; i < models.getLength(); i++) { + final Element model = (Element) models.item(i); + final String id = model.getAttribute("id"); + final String path = model.getAttribute("path"); + final String dimension = model.getAttribute("dimension"); + if (id.isEmpty() || path.isEmpty()) { + continue; + } + entries.put(id.trim(), new String[]{path.trim(), dimension.trim()}); + } + setProperty(PROPERTY_VECTOR_MODELS, entries); + } + /** * Gets the value of a configuration attribute *

diff --git a/exist-core/src/main/java/org/exist/util/ParametersExtractor.java b/exist-core/src/main/java/org/exist/util/ParametersExtractor.java index 28f0cfa15e8..3454fef082d 100644 --- a/exist-core/src/main/java/org/exist/util/ParametersExtractor.java +++ b/exist-core/src/main/java/org/exist/util/ParametersExtractor.java @@ -255,6 +255,10 @@ private static Properties parseProperties(final Node container, final String ele for (int i = 0; i < params.getLength(); i++) { final Element param = ((Element) params.item(i)); + if ("no".equalsIgnoreCase(param.getAttribute("enabled"))) { + continue; + } + final String name = param.getAttribute("name"); final String value = param.getAttribute("value"); diff --git a/exist-core/src/main/java/org/exist/xquery/ModuleFactory.java b/exist-core/src/main/java/org/exist/xquery/ModuleFactory.java new file mode 100644 index 00000000000..2cbb614557c --- /dev/null +++ b/exist-core/src/main/java/org/exist/xquery/ModuleFactory.java @@ -0,0 +1,60 @@ +/* + * eXist-db Open Source Native XML Database + * Copyright (C) 2001 The eXist-db Authors + * + * info@exist-db.org + * http://www.exist-db.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +package org.exist.xquery; + +/** + * SPI interface for automatic XQuery module registration. + * + *

A JAR that bundles an XQuery module can self-register by: + *

    + *
  1. Providing an implementation of this interface (conventionally a static + * inner class named {@code Factory} on the module class).
  2. + *
  3. Listing the implementation's fully-qualified class name in + * {@code META-INF/services/org.exist.xquery.ModuleFactory}.
  4. + *
+ * + *

At startup, {@code Configuration} discovers all {@code ModuleFactory} + * implementations on the classpath via {@link java.util.ServiceLoader} and + * pre-populates the module registry before processing {@code conf.xml} entries. + * A {@code conf.xml} entry always wins over an SPI-discovered entry for the + * same namespace URI; {@code enabled="no"} suppresses an SPI-discovered module. + */ +public interface ModuleFactory { + + /** + * The namespace URI that uniquely identifies the module. + * Must match the value returned by {@link Module#getNamespaceURI()} for + * the module class returned by {@link #getModuleClass()}. + * + * @return namespace URI + */ + String getNamespaceURI(); + + /** + * The concrete {@link Module} implementation class to register. + * The class must have a public constructor accepting + * {@code Map> parameters}. + * + * @return module implementation class + */ + Class getModuleClass(); +} diff --git a/exist-core/src/main/java/org/exist/xquery/functions/array/ArrayModule.java b/exist-core/src/main/java/org/exist/xquery/functions/array/ArrayModule.java index c3dde997d14..71bdc86f3ba 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/array/ArrayModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/array/ArrayModule.java @@ -94,4 +94,9 @@ public String getDescription() { public String getReleaseVersion() { return "2.2.1"; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return ArrayModule.class; } + } } diff --git a/exist-core/src/main/java/org/exist/xquery/functions/inspect/InspectionModule.java b/exist-core/src/main/java/org/exist/xquery/functions/inspect/InspectionModule.java index d56cc19d721..217f428eb41 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/inspect/InspectionModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/inspect/InspectionModule.java @@ -86,4 +86,9 @@ static FunctionSignature functionSignature(final String name, final String descr static FunctionSignature[] functionSignatures(final String name, final String description, final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType[][] variableParamTypes) { return FunctionDSL.functionSignatures(new QName(name, NAMESPACE_URI, PREFIX), description, returnType, variableParamTypes); } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return InspectionModule.class; } + } } diff --git a/exist-core/src/main/java/org/exist/xquery/functions/map/MapModule.java b/exist-core/src/main/java/org/exist/xquery/functions/map/MapModule.java index 73a28441270..db3b5032b60 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/map/MapModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/map/MapModule.java @@ -81,4 +81,9 @@ public String getReleaseVersion() { static FunctionSignature functionSignature(final String name, final String description, final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType... paramTypes) { return FunctionDSL.functionSignature(new QName(name, NAMESPACE_URI, PREFIX), description, returnType, paramTypes); } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return MapModule.class; } + } } diff --git a/exist-core/src/main/java/org/exist/xquery/functions/math/MathModule.java b/exist-core/src/main/java/org/exist/xquery/functions/math/MathModule.java index be6211ee905..442f13ef4f1 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/math/MathModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/math/MathModule.java @@ -79,4 +79,9 @@ public String getDescription() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return MathModule.class; } + } } diff --git a/exist-core/src/main/java/org/exist/xquery/functions/request/RequestModule.java b/exist-core/src/main/java/org/exist/xquery/functions/request/RequestModule.java index b2099c6cb7d..28b614899ae 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/request/RequestModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/request/RequestModule.java @@ -27,6 +27,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.xquery.*; +import org.exist.xquery.Module; /** * Module function definitions for transform module. @@ -103,4 +104,9 @@ public String getDefaultPrefix() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return RequestModule.class; } + } } diff --git a/exist-core/src/main/java/org/exist/xquery/functions/response/ResponseModule.java b/exist-core/src/main/java/org/exist/xquery/functions/response/ResponseModule.java index d86a1870ce0..fc37866db39 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/response/ResponseModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/response/ResponseModule.java @@ -27,6 +27,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.xquery.*; +import org.exist.xquery.Module; /** * Module function definitions for xmldb module. @@ -82,4 +83,9 @@ public String getDefaultPrefix() { public String getReleaseVersion() { return (RELEASED_IN_VERSION); } + + public static final class Factory implements ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return ResponseModule.class; } + } } diff --git a/exist-core/src/main/java/org/exist/xquery/functions/securitymanager/SecurityManagerModule.java b/exist-core/src/main/java/org/exist/xquery/functions/securitymanager/SecurityManagerModule.java index 4577446871c..7d7e9316c44 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/securitymanager/SecurityManagerModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/securitymanager/SecurityManagerModule.java @@ -140,4 +140,9 @@ public String getDescription() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return SecurityManagerModule.class; } + } } \ No newline at end of file diff --git a/exist-core/src/main/java/org/exist/xquery/functions/session/SessionModule.java b/exist-core/src/main/java/org/exist/xquery/functions/session/SessionModule.java index 905ad32ae27..d857bc56fe9 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/session/SessionModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/session/SessionModule.java @@ -27,6 +27,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.xquery.*; +import org.exist.xquery.Module; /** * Module function definitions for transform module. @@ -86,4 +87,9 @@ public String getDefaultPrefix() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return SessionModule.class; } + } } diff --git a/exist-core/src/main/java/org/exist/xquery/functions/system/SystemModule.java b/exist-core/src/main/java/org/exist/xquery/functions/system/SystemModule.java index af003787f99..90253881272 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/system/SystemModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/system/SystemModule.java @@ -117,4 +117,9 @@ static FunctionSignature functionSignature(final String name, final String descr static FunctionSignature[] functionSignatures(final String name, final String description, final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType[][] variableParamTypes) { return FunctionDSL.functionSignatures(new QName(name, NAMESPACE_URI, PREFIX), description, returnType, variableParamTypes); } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return SystemModule.class; } + } } diff --git a/exist-core/src/main/java/org/exist/xquery/functions/transform/TransformModule.java b/exist-core/src/main/java/org/exist/xquery/functions/transform/TransformModule.java index a2f3564de8b..6b236845ae9 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/transform/TransformModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/transform/TransformModule.java @@ -76,4 +76,8 @@ public String getReleaseVersion() { return RELEASED_IN_VERSION; } + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return TransformModule.class; } + } } diff --git a/exist-core/src/main/java/org/exist/xquery/functions/util/UtilModule.java b/exist-core/src/main/java/org/exist/xquery/functions/util/UtilModule.java index f99a4b9bbbe..07b8f65e7df 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/util/UtilModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/util/UtilModule.java @@ -26,6 +26,7 @@ import org.exist.dom.QName; import org.exist.xquery.*; +import org.exist.xquery.Module; import org.exist.xquery.value.FunctionParameterSequenceType; import org.exist.xquery.value.FunctionReturnSequenceType; @@ -219,5 +220,10 @@ static FunctionSignature functionSignature(final String name, final String descr static FunctionSignature[] functionSignatures(final String name, final String description, final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType[][] variableParamTypes) { return FunctionDSL.functionSignatures(new QName(name, NAMESPACE_URI, PREFIX), description, returnType, variableParamTypes); } + + public static final class Factory implements ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return UtilModule.class; } + } } diff --git a/exist-core/src/main/java/org/exist/xquery/functions/validation/ValidationModule.java b/exist-core/src/main/java/org/exist/xquery/functions/validation/ValidationModule.java index 1fd18b59c05..08d7b30396e 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/validation/ValidationModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/validation/ValidationModule.java @@ -110,4 +110,9 @@ public String getDefaultPrefix() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return ValidationModule.class; } + } } diff --git a/exist-core/src/main/java/org/exist/xquery/functions/websocket/ConsoleCompatModule.java b/exist-core/src/main/java/org/exist/xquery/functions/websocket/ConsoleCompatModule.java index f1832a569c3..9a3a0614bb2 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/websocket/ConsoleCompatModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/websocket/ConsoleCompatModule.java @@ -71,4 +71,9 @@ public String getDescription() { public String getReleaseVersion() { return "7.0.0"; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return ConsoleCompatModule.class; } + } } diff --git a/exist-core/src/main/java/org/exist/xquery/functions/websocket/WebSocketModule.java b/exist-core/src/main/java/org/exist/xquery/functions/websocket/WebSocketModule.java index 280d1166905..c32e536fb29 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/websocket/WebSocketModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/websocket/WebSocketModule.java @@ -111,4 +111,9 @@ public String getDescription() { public String getReleaseVersion() { return "7.0.0"; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return WebSocketModule.class; } + } } diff --git a/exist-core/src/main/java/org/exist/xquery/functions/xmldb/XMLDBModule.java b/exist-core/src/main/java/org/exist/xquery/functions/xmldb/XMLDBModule.java index 9f60ddd10ce..f5eec7f6e38 100644 --- a/exist-core/src/main/java/org/exist/xquery/functions/xmldb/XMLDBModule.java +++ b/exist-core/src/main/java/org/exist/xquery/functions/xmldb/XMLDBModule.java @@ -153,4 +153,9 @@ static FunctionSignature functionSignature(final String name, final String descr static FunctionSignature[] functionSignatures(final String name, final String description, final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType[][] variableParamTypes) { return FunctionDSL.functionSignatures(new QName(name, NAMESPACE_URI, PREFIX), description, returnType, variableParamTypes); } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return XMLDBModule.class; } + } } diff --git a/exist-core/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/exist-core/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..dfcccc6dffa --- /dev/null +++ b/exist-core/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1,16 @@ +org.exist.xquery.functions.map.MapModule$Factory +org.exist.xquery.functions.math.MathModule$Factory +org.exist.xquery.functions.array.ArrayModule$Factory +org.exist.backup.xquery.BackupModule$Factory +org.exist.xquery.functions.inspect.InspectionModule$Factory +org.exist.xquery.functions.request.RequestModule$Factory +org.exist.xquery.functions.response.ResponseModule$Factory +org.exist.xquery.functions.securitymanager.SecurityManagerModule$Factory +org.exist.xquery.functions.session.SessionModule$Factory +org.exist.xquery.functions.system.SystemModule$Factory +org.exist.xquery.functions.transform.TransformModule$Factory +org.exist.xquery.functions.util.UtilModule$Factory +org.exist.xquery.functions.validation.ValidationModule$Factory +org.exist.xquery.functions.websocket.WebSocketModule$Factory +org.exist.xquery.functions.websocket.ConsoleCompatModule$Factory +org.exist.xquery.functions.xmldb.XMLDBModule$Factory diff --git a/exist-core/src/test/resources-filtered/conf-fixture.xsl b/exist-core/src/test/resources-filtered/conf-fixture.xsl index ca4da98b55d..228815058b8 100644 --- a/exist-core/src/test/resources-filtered/conf-fixture.xsl +++ b/exist-core/src/test/resources-filtered/conf-fixture.xsl @@ -30,22 +30,13 @@ + + + + - - + - + - + @@ -212,12 +212,12 @@ - - - - - + --> + @@ -252,7 +252,7 @@ mode "rwxrwx___" (0770) with mime-type "application/xquery". The names of the scripts must end with ".xq", ".xqy" or ".xquery". --> - + @@ -545,35 +545,24 @@ suppress-whitespace="none"> - - - - + - - + - - + - + - - - - @@ -954,8 +938,7 @@ xmldb:xcollection() should return an empty sequence when an XML resource can not be retrieved. --> - - @@ -963,63 +946,34 @@ - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - + - - - - - - - - - - + + - - + diff --git a/extensions/contentextraction/src/main/java/org/exist/contentextraction/xquery/ContentExtractionModule.java b/extensions/contentextraction/src/main/java/org/exist/contentextraction/xquery/ContentExtractionModule.java index 90520a9062c..8f9ae205f44 100644 --- a/extensions/contentextraction/src/main/java/org/exist/contentextraction/xquery/ContentExtractionModule.java +++ b/extensions/contentextraction/src/main/java/org/exist/contentextraction/xquery/ContentExtractionModule.java @@ -74,4 +74,9 @@ public String getDescription() { public String getReleaseVersion() { return (RELEASED_IN_VERSION); } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return ContentExtractionModule.class; } + } } diff --git a/extensions/contentextraction/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/contentextraction/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..6ed7236b6ef --- /dev/null +++ b/extensions/contentextraction/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.contentextraction.xquery.ContentExtractionModule$Factory diff --git a/extensions/expath/src/main/java/org/expath/exist/ZipModule.java b/extensions/expath/src/main/java/org/expath/exist/ZipModule.java index 377647804b2..147289cb85e 100644 --- a/extensions/expath/src/main/java/org/expath/exist/ZipModule.java +++ b/extensions/expath/src/main/java/org/expath/exist/ZipModule.java @@ -72,4 +72,9 @@ public String getDescription() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return ZipModule.class; } + } } diff --git a/extensions/expath/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/expath/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..07c4a092d7c --- /dev/null +++ b/extensions/expath/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.expath.exist.ZipModule$Factory diff --git a/extensions/exquery/modules/request/src/main/java/org/exist/extensions/exquery/modules/request/RequestModule.java b/extensions/exquery/modules/request/src/main/java/org/exist/extensions/exquery/modules/request/RequestModule.java index 6cecc83a3ab..a5ceb0b62be 100644 --- a/extensions/exquery/modules/request/src/main/java/org/exist/extensions/exquery/modules/request/RequestModule.java +++ b/extensions/exquery/modules/request/src/main/java/org/exist/extensions/exquery/modules/request/RequestModule.java @@ -96,4 +96,9 @@ public String getDescription() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return RequestModule.class; } + } } diff --git a/extensions/exquery/modules/request/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/exquery/modules/request/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..96c5bead2c5 --- /dev/null +++ b/extensions/exquery/modules/request/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.extensions.exquery.modules.request.RequestModule$Factory diff --git a/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/xquery/RestXqModule.java b/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/xquery/RestXqModule.java index 39e0f3d45c9..9631c995dda 100644 --- a/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/xquery/RestXqModule.java +++ b/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/xquery/RestXqModule.java @@ -71,4 +71,9 @@ public String getDescription() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return RestXqModule.class; } + } } \ No newline at end of file diff --git a/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/xquery/exist/ExistRestXqModule.java b/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/xquery/exist/ExistRestXqModule.java index d9877a1cd05..1e56ce207c2 100644 --- a/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/xquery/exist/ExistRestXqModule.java +++ b/extensions/exquery/restxq/src/main/java/org/exist/extensions/exquery/restxq/impl/xquery/exist/ExistRestXqModule.java @@ -76,4 +76,9 @@ public String getDescription() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return ExistRestXqModule.class; } + } } diff --git a/extensions/exquery/restxq/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/exquery/restxq/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..7f2b3176e4e --- /dev/null +++ b/extensions/exquery/restxq/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1,2 @@ +org.exist.extensions.exquery.restxq.impl.xquery.RestXqModule$Factory +org.exist.extensions.exquery.restxq.impl.xquery.exist.ExistRestXqModule$Factory diff --git a/extensions/indexes/lucene/src/main/java/org/exist/indexing/lucene/LuceneIndex.java b/extensions/indexes/lucene/src/main/java/org/exist/indexing/lucene/LuceneIndex.java index 21d7370c16a..da97a7cb66b 100644 --- a/extensions/indexes/lucene/src/main/java/org/exist/indexing/lucene/LuceneIndex.java +++ b/extensions/indexes/lucene/src/main/java/org/exist/indexing/lucene/LuceneIndex.java @@ -91,21 +91,23 @@ public void configure(BrokerPool pool, Path dataDir, Element config) throws Data if (LOG.isDebugEnabled()) LOG.debug("Configuring Lucene index"); - String bufferSizeParam = config.getAttribute("buffer"); - if (!bufferSizeParam.isEmpty()) - try { - bufferSize = Double.parseDouble(bufferSizeParam); - } catch (NumberFormatException e) { - LOG.warn("Invalid buffer size setting for Lucene index: {}", bufferSizeParam, e); + if (config != null) { + String bufferSizeParam = config.getAttribute("buffer"); + if (!bufferSizeParam.isEmpty()) + try { + bufferSize = Double.parseDouble(bufferSizeParam); + } catch (NumberFormatException e) { + LOG.warn("Invalid buffer size setting for Lucene index: {}", bufferSizeParam, e); + } + + if (LOG.isDebugEnabled()) + LOG.debug("Using buffer size: {}", bufferSize); + + NodeList nl = config.getElementsByTagName("analyzer"); + if (nl.getLength() > 0) { + Element node = (Element) nl.item(0); + defaultAnalyzer = AnalyzerConfig.configureAnalyzer(node); } - - if (LOG.isDebugEnabled()) - LOG.debug("Using buffer size: {}", bufferSize); - - NodeList nl = config.getElementsByTagName("analyzer"); - if (nl.getLength() > 0) { - Element node = (Element) nl.item(0); - defaultAnalyzer = AnalyzerConfig.configureAnalyzer(node); } if (defaultAnalyzer == null) @@ -114,6 +116,11 @@ public void configure(BrokerPool pool, Path dataDir, Element config) throws Data LOG.debug("Using default analyzer: {}", defaultAnalyzer.getClass().getName()); } + public static final class Factory implements org.exist.indexing.IndexFactory { + @Override public String getDefaultId() { return "lucene-index"; } + @Override public Class getIndexClass() { return LuceneIndex.class; } + } + @Override public void open() throws DatabaseConfigurationException { Path dir = getDataDir().resolve(getDirName()); diff --git a/extensions/indexes/lucene/src/main/java/org/exist/xquery/modules/lucene/LuceneModule.java b/extensions/indexes/lucene/src/main/java/org/exist/xquery/modules/lucene/LuceneModule.java index 74182bdc54f..d32f7099429 100644 --- a/extensions/indexes/lucene/src/main/java/org/exist/xquery/modules/lucene/LuceneModule.java +++ b/extensions/indexes/lucene/src/main/java/org/exist/xquery/modules/lucene/LuceneModule.java @@ -122,7 +122,12 @@ protected final static class LuceneErrorCode extends ErrorCode { public LuceneErrorCode(String code, String description) { super(new QName(code, NAMESPACE_URI, PREFIX), description); } - + + } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return LuceneModule.class; } } } diff --git a/extensions/indexes/lucene/src/main/resources/META-INF/services/org.exist.indexing.IndexFactory b/extensions/indexes/lucene/src/main/resources/META-INF/services/org.exist.indexing.IndexFactory new file mode 100644 index 00000000000..9cbb03d790c --- /dev/null +++ b/extensions/indexes/lucene/src/main/resources/META-INF/services/org.exist.indexing.IndexFactory @@ -0,0 +1 @@ +org.exist.indexing.lucene.LuceneIndex$Factory diff --git a/extensions/indexes/lucene/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/indexes/lucene/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..8cd608d552b --- /dev/null +++ b/extensions/indexes/lucene/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.lucene.LuceneModule$Factory diff --git a/extensions/indexes/ngram/src/main/java/org/exist/indexing/ngram/NGramIndex.java b/extensions/indexes/ngram/src/main/java/org/exist/indexing/ngram/NGramIndex.java index 9f581656b93..74fa66e105c 100644 --- a/extensions/indexes/ngram/src/main/java/org/exist/indexing/ngram/NGramIndex.java +++ b/extensions/indexes/ngram/src/main/java/org/exist/indexing/ngram/NGramIndex.java @@ -58,17 +58,24 @@ public class NGramIndex extends AbstractIndex implements RawBackupSupport { public void configure(BrokerPool pool, Path dataDir, Element config) throws DatabaseConfigurationException { super.configure(pool, dataDir, config); String fileName = "ngram.dbx"; - if (config.hasAttribute("file")) - fileName = config.getAttribute("file"); - if (config.hasAttribute("n")) - try { - gramSize = Integer.parseInt(config.getAttribute("n")); - } catch (NumberFormatException e) { - throw new DatabaseConfigurationException("Configuration parameter 'n' should be an integer."); - } + if (config != null) { + if (config.hasAttribute("file")) + fileName = config.getAttribute("file"); + if (config.hasAttribute("n")) + try { + gramSize = Integer.parseInt(config.getAttribute("n")); + } catch (NumberFormatException e) { + throw new DatabaseConfigurationException("Configuration parameter 'n' should be an integer."); + } + } dataFile = dataDir.resolve(fileName); } + public static final class Factory implements org.exist.indexing.IndexFactory { + @Override public String getDefaultId() { return "ngram-index"; } + @Override public Class getIndexClass() { return NGramIndex.class; } + } + @Override public void open() throws DatabaseConfigurationException { try { diff --git a/extensions/indexes/ngram/src/main/java/org/exist/xquery/modules/ngram/NGramModule.java b/extensions/indexes/ngram/src/main/java/org/exist/xquery/modules/ngram/NGramModule.java index 4308023811a..d14428e8dc5 100644 --- a/extensions/indexes/ngram/src/main/java/org/exist/xquery/modules/ngram/NGramModule.java +++ b/extensions/indexes/ngram/src/main/java/org/exist/xquery/modules/ngram/NGramModule.java @@ -73,4 +73,9 @@ public String getDescription() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return NGramModule.class; } + } } diff --git a/extensions/indexes/ngram/src/main/resources/META-INF/services/org.exist.indexing.IndexFactory b/extensions/indexes/ngram/src/main/resources/META-INF/services/org.exist.indexing.IndexFactory new file mode 100644 index 00000000000..10fef024311 --- /dev/null +++ b/extensions/indexes/ngram/src/main/resources/META-INF/services/org.exist.indexing.IndexFactory @@ -0,0 +1 @@ +org.exist.indexing.ngram.NGramIndex$Factory diff --git a/extensions/indexes/ngram/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/indexes/ngram/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..ef96f49e326 --- /dev/null +++ b/extensions/indexes/ngram/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.ngram.NGramModule$Factory diff --git a/extensions/indexes/range/src/main/java/org/exist/indexing/range/RangeIndex.java b/extensions/indexes/range/src/main/java/org/exist/indexing/range/RangeIndex.java index d2908750249..029154cc628 100644 --- a/extensions/indexes/range/src/main/java/org/exist/indexing/range/RangeIndex.java +++ b/extensions/indexes/range/src/main/java/org/exist/indexing/range/RangeIndex.java @@ -43,6 +43,11 @@ public class RangeIndex extends LuceneIndex { public final static String ID = RangeIndex.class.getName(); + public static final class Factory implements org.exist.indexing.IndexFactory { + @Override public String getDefaultId() { return "range-index"; } + @Override public Class getIndexClass() { return RangeIndex.class; } + } + /** * Enumeration of supported operators and optimized functions. */ diff --git a/extensions/indexes/range/src/main/java/org/exist/xquery/modules/range/RangeIndexModule.java b/extensions/indexes/range/src/main/java/org/exist/xquery/modules/range/RangeIndexModule.java index 56ab19b3eaa..e629bb919ee 100644 --- a/extensions/indexes/range/src/main/java/org/exist/xquery/modules/range/RangeIndexModule.java +++ b/extensions/indexes/range/src/main/java/org/exist/xquery/modules/range/RangeIndexModule.java @@ -113,4 +113,9 @@ public String getDescription() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return RangeIndexModule.class; } + } } diff --git a/extensions/indexes/range/src/main/resources/META-INF/services/org.exist.indexing.IndexFactory b/extensions/indexes/range/src/main/resources/META-INF/services/org.exist.indexing.IndexFactory new file mode 100644 index 00000000000..0e4c0c33aa1 --- /dev/null +++ b/extensions/indexes/range/src/main/resources/META-INF/services/org.exist.indexing.IndexFactory @@ -0,0 +1 @@ +org.exist.indexing.range.RangeIndex$Factory diff --git a/extensions/indexes/range/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/indexes/range/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..410708c8fa3 --- /dev/null +++ b/extensions/indexes/range/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.range.RangeIndexModule$Factory diff --git a/extensions/indexes/sort/src/main/java/org/exist/indexing/sort/SortIndex.java b/extensions/indexes/sort/src/main/java/org/exist/indexing/sort/SortIndex.java index 4ce3117eb74..cf2e17f8e8b 100644 --- a/extensions/indexes/sort/src/main/java/org/exist/indexing/sort/SortIndex.java +++ b/extensions/indexes/sort/src/main/java/org/exist/indexing/sort/SortIndex.java @@ -61,6 +61,11 @@ public class SortIndex extends AbstractIndex implements RawBackupSupport { protected static final Logger LOG = LogManager.getLogger(SortIndex.class); protected BTreeStore btree; + public static final class Factory implements org.exist.indexing.IndexFactory { + @Override public String getDefaultId() { return "sort-index"; } + @Override public Class getIndexClass() { return SortIndex.class; } + } + @Override public void open() throws DatabaseConfigurationException { final Path file = getDataDir().resolve(FILE_NAME); diff --git a/extensions/indexes/sort/src/main/java/org/exist/xquery/modules/sort/SortModule.java b/extensions/indexes/sort/src/main/java/org/exist/xquery/modules/sort/SortModule.java index 10a3f64259c..3f47ff037b5 100644 --- a/extensions/indexes/sort/src/main/java/org/exist/xquery/modules/sort/SortModule.java +++ b/extensions/indexes/sort/src/main/java/org/exist/xquery/modules/sort/SortModule.java @@ -67,4 +67,9 @@ public String getDescription() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return SortModule.class; } + } } diff --git a/extensions/indexes/sort/src/main/resources/META-INF/services/org.exist.indexing.IndexFactory b/extensions/indexes/sort/src/main/resources/META-INF/services/org.exist.indexing.IndexFactory new file mode 100644 index 00000000000..eaa663be1e3 --- /dev/null +++ b/extensions/indexes/sort/src/main/resources/META-INF/services/org.exist.indexing.IndexFactory @@ -0,0 +1 @@ +org.exist.indexing.sort.SortIndex$Factory diff --git a/extensions/indexes/sort/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/indexes/sort/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..df15076c43e --- /dev/null +++ b/extensions/indexes/sort/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.sort.SortModule$Factory diff --git a/extensions/modules/cache/src/main/java/org/exist/xquery/modules/cache/CacheModule.java b/extensions/modules/cache/src/main/java/org/exist/xquery/modules/cache/CacheModule.java index 6e2c68d1cd0..c0d321ec4b2 100644 --- a/extensions/modules/cache/src/main/java/org/exist/xquery/modules/cache/CacheModule.java +++ b/extensions/modules/cache/src/main/java/org/exist/xquery/modules/cache/CacheModule.java @@ -30,6 +30,7 @@ import org.apache.logging.log4j.Logger; import org.exist.dom.QName; import org.exist.xquery.*; +import org.exist.xquery.Module; import org.exist.xquery.value.FunctionParameterSequenceType; import org.exist.xquery.value.FunctionReturnSequenceType; @@ -194,4 +195,9 @@ private static Optional getFirstString(final Map> parame Optional getLazyCacheConfig() { return lazyCacheConfig; } + + public static final class Factory implements ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return CacheModule.class; } + } } diff --git a/extensions/modules/cache/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/cache/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..d795623550a --- /dev/null +++ b/extensions/modules/cache/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.cache.CacheModule$Factory diff --git a/extensions/modules/cache/src/test/resources-filtered/lazy-cache-conf.xml b/extensions/modules/cache/src/test/resources-filtered/lazy-cache-conf.xml index af9663be608..0350bee319a 100644 --- a/extensions/modules/cache/src/test/resources-filtered/lazy-cache-conf.xml +++ b/extensions/modules/cache/src/test/resources-filtered/lazy-cache-conf.xml @@ -735,7 +735,6 @@ xmldb:xcollection() should return an empty sequence when an XML resource can not be retrieved. --> - - getModuleClass() { return CompressionModule.class; } + } } diff --git a/extensions/modules/compression/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/compression/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..32a27612fd2 --- /dev/null +++ b/extensions/modules/compression/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.compression.CompressionModule$Factory diff --git a/extensions/modules/counter/src/main/java/org/exist/xquery/modules/counter/CounterModule.java b/extensions/modules/counter/src/main/java/org/exist/xquery/modules/counter/CounterModule.java index d563cbca277..265a63bfa88 100644 --- a/extensions/modules/counter/src/main/java/org/exist/xquery/modules/counter/CounterModule.java +++ b/extensions/modules/counter/src/main/java/org/exist/xquery/modules/counter/CounterModule.java @@ -92,5 +92,10 @@ public String getDefaultPrefix() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return CounterModule.class; } + } } diff --git a/extensions/modules/counter/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/counter/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..00c7ea8e4c8 --- /dev/null +++ b/extensions/modules/counter/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.counter.CounterModule$Factory diff --git a/extensions/modules/cqlparser/src/main/java/org/exist/xquery/modules/cqlparser/CQLParserModule.java b/extensions/modules/cqlparser/src/main/java/org/exist/xquery/modules/cqlparser/CQLParserModule.java index 96a83116eba..f5236979092 100644 --- a/extensions/modules/cqlparser/src/main/java/org/exist/xquery/modules/cqlparser/CQLParserModule.java +++ b/extensions/modules/cqlparser/src/main/java/org/exist/xquery/modules/cqlparser/CQLParserModule.java @@ -70,4 +70,8 @@ public String getReleaseVersion() { return RELEASED_IN_VERSION; } + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return CQLParserModule.class; } + } } diff --git a/extensions/modules/cqlparser/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/cqlparser/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..2a7dcb88c0b --- /dev/null +++ b/extensions/modules/cqlparser/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.cqlparser.CQLParserModule$Factory diff --git a/extensions/modules/expathrepo/src/main/java/org/exist/xquery/modules/expathrepo/ExpathPackageModule.java b/extensions/modules/expathrepo/src/main/java/org/exist/xquery/modules/expathrepo/ExpathPackageModule.java index 7627fdd8bad..729c94ab955 100644 --- a/extensions/modules/expathrepo/src/main/java/org/exist/xquery/modules/expathrepo/ExpathPackageModule.java +++ b/extensions/modules/expathrepo/src/main/java/org/exist/xquery/modules/expathrepo/ExpathPackageModule.java @@ -24,6 +24,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.exist.xquery.*; +import org.exist.xquery.Module; import java.util.List; import java.util.Map; @@ -85,4 +86,9 @@ public String getDescription() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return ExpathPackageModule.class; } + } } diff --git a/extensions/modules/expathrepo/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/expathrepo/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..a7702b185e2 --- /dev/null +++ b/extensions/modules/expathrepo/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.expathrepo.ExpathPackageModule$Factory diff --git a/extensions/modules/file/src/main/java/org/exist/xquery/modules/file/FileModule.java b/extensions/modules/file/src/main/java/org/exist/xquery/modules/file/FileModule.java index ef7542a87a3..117e51e1167 100644 --- a/extensions/modules/file/src/main/java/org/exist/xquery/modules/file/FileModule.java +++ b/extensions/modules/file/src/main/java/org/exist/xquery/modules/file/FileModule.java @@ -97,4 +97,9 @@ public String getDescription() public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return FileModule.class; } + } } diff --git a/extensions/modules/file/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/file/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..e1ae37a6a43 --- /dev/null +++ b/extensions/modules/file/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.file.FileModule$Factory diff --git a/extensions/modules/http-client/src/main/java/org/exist/xquery/modules/httpclient/HttpClientModule.java b/extensions/modules/http-client/src/main/java/org/exist/xquery/modules/httpclient/HttpClientModule.java index 3db2ede81ff..457e29a69b8 100644 --- a/extensions/modules/http-client/src/main/java/org/exist/xquery/modules/httpclient/HttpClientModule.java +++ b/extensions/modules/http-client/src/main/java/org/exist/xquery/modules/httpclient/HttpClientModule.java @@ -113,4 +113,9 @@ public String getReleaseVersion() { static QName qname(final String localPart) { return new QName(localPart, NAMESPACE_URI, PREFIX); } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return HttpClientModule.class; } + } } diff --git a/extensions/modules/http-client/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/http-client/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..431fce3684a --- /dev/null +++ b/extensions/modules/http-client/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.httpclient.HttpClientModule$Factory diff --git a/extensions/modules/image/src/main/java/org/exist/xquery/modules/image/ImageModule.java b/extensions/modules/image/src/main/java/org/exist/xquery/modules/image/ImageModule.java index 386a64e84d5..50f54582a76 100644 --- a/extensions/modules/image/src/main/java/org/exist/xquery/modules/image/ImageModule.java +++ b/extensions/modules/image/src/main/java/org/exist/xquery/modules/image/ImageModule.java @@ -251,4 +251,9 @@ static class RenderingHintVariable { this.value = value; } } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return ImageModule.class; } + } } diff --git a/extensions/modules/image/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/image/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..4f52e224c52 --- /dev/null +++ b/extensions/modules/image/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.image.ImageModule$Factory diff --git a/extensions/modules/jndi/src/main/java/org/exist/xquery/modules/jndi/JNDIModule.java b/extensions/modules/jndi/src/main/java/org/exist/xquery/modules/jndi/JNDIModule.java index e88f9ec809b..65e0d8ab6f7 100644 --- a/extensions/modules/jndi/src/main/java/org/exist/xquery/modules/jndi/JNDIModule.java +++ b/extensions/modules/jndi/src/main/java/org/exist/xquery/modules/jndi/JNDIModule.java @@ -304,4 +304,9 @@ protected static BasicAttributes parseAttributes( Sequence arg ) return( attributes ); } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return JNDIModule.class; } + } } diff --git a/extensions/modules/jndi/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/jndi/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..d549c397e69 --- /dev/null +++ b/extensions/modules/jndi/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.jndi.JNDIModule$Factory diff --git a/extensions/modules/mail/src/main/java/org/exist/xquery/modules/mail/MailModule.java b/extensions/modules/mail/src/main/java/org/exist/xquery/modules/mail/MailModule.java index e1f02f1872e..6b27ff9b966 100644 --- a/extensions/modules/mail/src/main/java/org/exist/xquery/modules/mail/MailModule.java +++ b/extensions/modules/mail/src/main/java/org/exist/xquery/modules/mail/MailModule.java @@ -395,4 +395,9 @@ public void reset( XQueryContext context, boolean keepGlobals ) { // close any open stores closeAllStores(context); } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return MailModule.class; } + } } \ No newline at end of file diff --git a/extensions/modules/mail/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/mail/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..7461a11b8b7 --- /dev/null +++ b/extensions/modules/mail/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.mail.MailModule$Factory diff --git a/extensions/modules/persistentlogin/src/main/java/org/exist/xquery/modules/persistentlogin/PersistentLoginModule.java b/extensions/modules/persistentlogin/src/main/java/org/exist/xquery/modules/persistentlogin/PersistentLoginModule.java index 2feaf5176ec..05b538f91dd 100644 --- a/extensions/modules/persistentlogin/src/main/java/org/exist/xquery/modules/persistentlogin/PersistentLoginModule.java +++ b/extensions/modules/persistentlogin/src/main/java/org/exist/xquery/modules/persistentlogin/PersistentLoginModule.java @@ -72,4 +72,9 @@ public String getDescription() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE; } + @Override public Class getModuleClass() { return PersistentLoginModule.class; } + } } \ No newline at end of file diff --git a/extensions/modules/persistentlogin/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/persistentlogin/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..af84c237990 --- /dev/null +++ b/extensions/modules/persistentlogin/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.persistentlogin.PersistentLoginModule$Factory diff --git a/extensions/modules/process/src/main/java/org/exist/xquery/modules/process/ProcessModule.java b/extensions/modules/process/src/main/java/org/exist/xquery/modules/process/ProcessModule.java index 5f116ac6ffe..6f1ed41430b 100644 --- a/extensions/modules/process/src/main/java/org/exist/xquery/modules/process/ProcessModule.java +++ b/extensions/modules/process/src/main/java/org/exist/xquery/modules/process/ProcessModule.java @@ -60,4 +60,9 @@ public String getDescription() { public String getReleaseVersion() { return RELEASE; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE; } + @Override public Class getModuleClass() { return ProcessModule.class; } + } } diff --git a/extensions/modules/process/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/process/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..d2a4712bd4f --- /dev/null +++ b/extensions/modules/process/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.process.ProcessModule$Factory diff --git a/extensions/modules/scheduler/src/main/java/org/exist/xquery/modules/scheduler/SchedulerModule.java b/extensions/modules/scheduler/src/main/java/org/exist/xquery/modules/scheduler/SchedulerModule.java index ab4e3d1bd94..8469a83a46e 100644 --- a/extensions/modules/scheduler/src/main/java/org/exist/xquery/modules/scheduler/SchedulerModule.java +++ b/extensions/modules/scheduler/src/main/java/org/exist/xquery/modules/scheduler/SchedulerModule.java @@ -91,4 +91,8 @@ public String getReleaseVersion() return( RELEASED_IN_VERSION ); } + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return SchedulerModule.class; } + } } diff --git a/extensions/modules/scheduler/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/scheduler/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..da74d950f45 --- /dev/null +++ b/extensions/modules/scheduler/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.scheduler.SchedulerModule$Factory diff --git a/extensions/modules/simpleql/src/main/java/org/exist/xquery/modules/simpleql/SimpleQLModule.java b/extensions/modules/simpleql/src/main/java/org/exist/xquery/modules/simpleql/SimpleQLModule.java index 4601fa5a3aa..c81a9b481ec 100644 --- a/extensions/modules/simpleql/src/main/java/org/exist/xquery/modules/simpleql/SimpleQLModule.java +++ b/extensions/modules/simpleql/src/main/java/org/exist/xquery/modules/simpleql/SimpleQLModule.java @@ -67,4 +67,8 @@ public String getReleaseVersion() { return RELEASED_IN_VERSION; } + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return SimpleQLModule.class; } + } } diff --git a/extensions/modules/simpleql/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/simpleql/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..d7d79ae9db6 --- /dev/null +++ b/extensions/modules/simpleql/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.simpleql.SimpleQLModule$Factory diff --git a/extensions/modules/sql/src/main/java/org/exist/xquery/modules/sql/SQLModule.java b/extensions/modules/sql/src/main/java/org/exist/xquery/modules/sql/SQLModule.java index 0cfa49e2dae..5f732d13c30 100644 --- a/extensions/modules/sql/src/main/java/org/exist/xquery/modules/sql/SQLModule.java +++ b/extensions/modules/sql/src/main/java/org/exist/xquery/modules/sql/SQLModule.java @@ -38,6 +38,7 @@ import org.apache.logging.log4j.Logger; import org.exist.xquery.*; +import org.exist.xquery.Module; import java.sql.Connection; import java.sql.SQLException; @@ -288,4 +289,9 @@ public void modifyEntry(final Entry entry) { } }); } + + public static final class Factory implements ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return SQLModule.class; } + } } diff --git a/extensions/modules/sql/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/sql/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..fd5299b6359 --- /dev/null +++ b/extensions/modules/sql/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.sql.SQLModule$Factory diff --git a/extensions/modules/xmldiff/src/main/java/org/exist/xquery/modules/xmldiff/XmlDiffModule.java b/extensions/modules/xmldiff/src/main/java/org/exist/xquery/modules/xmldiff/XmlDiffModule.java index 531eb7789aa..65ff3a0ba27 100644 --- a/extensions/modules/xmldiff/src/main/java/org/exist/xquery/modules/xmldiff/XmlDiffModule.java +++ b/extensions/modules/xmldiff/src/main/java/org/exist/xquery/modules/xmldiff/XmlDiffModule.java @@ -37,6 +37,7 @@ import org.exist.dom.QName; import org.exist.xquery.*; +import org.exist.xquery.Module; import org.exist.xquery.value.FunctionParameterSequenceType; import org.exist.xquery.value.FunctionReturnSequenceType; @@ -97,4 +98,9 @@ private XmldDiffModuleErrorCode(final String code, final String description) { } static final ErrorCodes.ErrorCode UNSUPPORTED_DOM_IMPLEMENTATION = new XmldDiffModuleErrorCode("unsupported-dom-impl", "The DOM implementation of a Node is unsupported."); + + public static final class Factory implements ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return XmlDiffModule.class; } + } } diff --git a/extensions/modules/xmldiff/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/xmldiff/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..338093f45ba --- /dev/null +++ b/extensions/modules/xmldiff/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.xmldiff.XmlDiffModule$Factory diff --git a/extensions/modules/xslfo/src/main/java/org/exist/xquery/modules/xslfo/XSLFOModule.java b/extensions/modules/xslfo/src/main/java/org/exist/xquery/modules/xslfo/XSLFOModule.java index 25b7d6eb1ce..668326e8155 100644 --- a/extensions/modules/xslfo/src/main/java/org/exist/xquery/modules/xslfo/XSLFOModule.java +++ b/extensions/modules/xslfo/src/main/java/org/exist/xquery/modules/xslfo/XSLFOModule.java @@ -102,4 +102,9 @@ public synchronized ProcessorAdapter getProcessorAdapter() { static FunctionSignature[] functionSignatures(final String name, final String description, final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType[][] variableParamTypes) { return FunctionDSL.functionSignatures(new QName(name, NAMESPACE_URI, PREFIX), description, returnType, variableParamTypes); } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return XSLFOModule.class; } + } } \ No newline at end of file diff --git a/extensions/modules/xslfo/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/modules/xslfo/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..64c60cbe40d --- /dev/null +++ b/extensions/modules/xslfo/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.xslfo.XSLFOModule$Factory diff --git a/extensions/vector/src/main/java/org/exist/vector/ModelRegistry.java b/extensions/vector/src/main/java/org/exist/vector/ModelRegistry.java index 09edb859952..1bfce74d953 100644 --- a/extensions/vector/src/main/java/org/exist/vector/ModelRegistry.java +++ b/extensions/vector/src/main/java/org/exist/vector/ModelRegistry.java @@ -23,6 +23,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.exist.util.Configuration; import org.exist.util.ConfigurationHelper; import javax.annotation.Nonnull; @@ -70,7 +71,33 @@ public ModelEntry(final String path, final int dimension) { } private ModelRegistry() { - load(); + } + + /** + * Initialises the registry from the parsed Configuration object. + * Called reflectively by VectorStoreServiceImpl.configure() during broker pool startup. + * Must be called before any call to getInstance() for the registry to reflect conf.xml entries. + * + * @param configuration the eXist-db configuration + */ + @SuppressWarnings("unchecked") + public static void configure(final Configuration configuration) { + final Map raw = + (Map) configuration.getProperty(Configuration.PROPERTY_VECTOR_MODELS); + final ModelRegistry r = new ModelRegistry(); + if (raw != null) { + for (final Map.Entry e : raw.entrySet()) { + final String id = e.getKey(); + final String[] vals = e.getValue(); + final String path = vals[0]; + final int dim = parseDimension(vals.length > 1 ? vals[1] : "", 384); + r.entries.put(id, new ModelEntry(path, dim)); + } + if (!r.entries.isEmpty()) { + LOG.info("Loaded {} model(s) from configuration", r.entries.size()); + } + } + instance = r; } @Nonnull @@ -80,7 +107,10 @@ public static ModelRegistry getInstance() { synchronized (ModelRegistry.class) { r = instance; if (r == null) { + // Fallback: no Configuration was provided (e.g. standalone tools, tests). + // Parse conf.xml directly as before. r = instance = new ModelRegistry(); + r.load(); } } } diff --git a/extensions/vector/src/main/java/org/exist/vector/VectorEmbeddingService.java b/extensions/vector/src/main/java/org/exist/vector/VectorEmbeddingService.java index c41a949d428..5859773d03a 100644 --- a/extensions/vector/src/main/java/org/exist/vector/VectorEmbeddingService.java +++ b/extensions/vector/src/main/java/org/exist/vector/VectorEmbeddingService.java @@ -27,7 +27,9 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.nio.file.Path; +import java.util.Collections; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** @@ -41,6 +43,7 @@ public final class VectorEmbeddingService { private static volatile VectorEmbeddingService instance; private final Map cache = new ConcurrentHashMap<>(); + private final Set failed = Collections.newSetFromMap(new ConcurrentHashMap<>()); private VectorEmbeddingService() { } @@ -121,8 +124,13 @@ public VectorEmbeddingProvider getProvider(@Nonnull final String modelId, } final Path modelPath = ModelPathResolver.resolve(modelId, path); if (modelPath == null) { - LOG.warn("Model '{}' could not be resolved (path='{}'). Ensure the directory exists under exist.home and contains model.onnx and tokenizer.json, or configure in conf.xml, or use an absolute path or URL.", - modelId, path); + final String unresolvedKey = "unresolved:" + modelId + ":" + path; + if (failed.add(unresolvedKey)) { + LOG.warn("Model '{}' could not be resolved (path='{}'). Ensure the directory exists under exist.home and contains model.onnx and tokenizer.json, or configure in conf.xml, or use an absolute path or URL.", + modelId, path); + } else { + LOG.debug("Model '{}' still not available at '{}'", modelId, path); + } return null; } return getProviderByPath(modelId, modelPath, dim); @@ -141,18 +149,24 @@ public VectorEmbeddingProvider getProviderByPath(@Nonnull final String modelId, @Nonnull final Path modelPath, final int dimension) { final String cacheKey = modelId + ":" + modelPath.toAbsolutePath(); - return cache.computeIfAbsent(cacheKey, k -> { - try { - final VectorEmbeddingProvider p = OnnxVectorProvider.create(modelPath, dimension); - if (p != null) { - LOG.info("Loaded ONNX embedding model: {} from {}", modelId, modelPath); - return p; - } - } catch (final Exception e) { + final VectorEmbeddingProvider cached = cache.get(cacheKey); + if (cached != null) return cached; + if (failed.contains(cacheKey)) return null; + try { + final VectorEmbeddingProvider p = OnnxVectorProvider.create(modelPath, dimension); + if (p != null) { + LOG.info("Loaded ONNX embedding model: {} from {}", modelId, modelPath); + cache.put(cacheKey, p); + return p; + } + } catch (final Exception e) { + if (failed.add(cacheKey)) { LOG.warn("Failed to load ONNX model {} from {}: {}", modelId, modelPath, e.getMessage()); } return null; - }); + } + failed.add(cacheKey); + return null; } @Nonnull @@ -169,6 +183,7 @@ private static String httpCacheKey(@Nonnull final String modelId, @Nonnull final public void evict(@Nonnull final String modelId, @Nonnull final Path modelPath) { final String cacheKey = modelId + ":" + modelPath.toAbsolutePath(); cache.remove(cacheKey); + failed.remove(cacheKey); } /** diff --git a/extensions/vector/src/main/java/org/exist/xquery/modules/vector/VectorModule.java b/extensions/vector/src/main/java/org/exist/xquery/modules/vector/VectorModule.java index 89beb626d97..bc7ba46bd40 100644 --- a/extensions/vector/src/main/java/org/exist/xquery/modules/vector/VectorModule.java +++ b/extensions/vector/src/main/java/org/exist/xquery/modules/vector/VectorModule.java @@ -96,6 +96,11 @@ public String getReleaseVersion() { return RELEASED_IN_VERSION; } + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return VectorModule.class; } + } + static FunctionSignature functionSignature(final String name, final String description, final FunctionReturnSequenceType returnType, final FunctionParameterSequenceType... paramTypes) { return FunctionDSL.functionSignature(new QName(name, NAMESPACE_URI, PREFIX), description, returnType, paramTypes); diff --git a/extensions/vector/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/vector/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..ec037bafcfb --- /dev/null +++ b/extensions/vector/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xquery.modules.vector.VectorModule$Factory diff --git a/extensions/xqdoc/src/main/java/org/exist/xqdoc/xquery/XQDocModule.java b/extensions/xqdoc/src/main/java/org/exist/xqdoc/xquery/XQDocModule.java index 3cf6c643d78..5c999b2bbc2 100644 --- a/extensions/xqdoc/src/main/java/org/exist/xqdoc/xquery/XQDocModule.java +++ b/extensions/xqdoc/src/main/java/org/exist/xqdoc/xquery/XQDocModule.java @@ -62,4 +62,9 @@ public String getDescription() { public String getReleaseVersion() { return RELEASED_IN_VERSION; } + + public static final class Factory implements org.exist.xquery.ModuleFactory { + @Override public String getNamespaceURI() { return NAMESPACE_URI; } + @Override public Class getModuleClass() { return XQDocModule.class; } + } } diff --git a/extensions/xqdoc/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory b/extensions/xqdoc/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory new file mode 100644 index 00000000000..7989bbad638 --- /dev/null +++ b/extensions/xqdoc/src/main/resources/META-INF/services/org.exist.xquery.ModuleFactory @@ -0,0 +1 @@ +org.exist.xqdoc.xquery.XQDocModule$Factory diff --git a/schema/conf.xsd b/schema/conf.xsd index fe7b7e65922..e2086335df2 100644 --- a/schema/conf.xsd +++ b/schema/conf.xsd @@ -8,7 +8,7 @@ + version="2.7.0"> @@ -19,6 +19,16 @@ + + + + + + + @@ -36,6 +46,20 @@ + + + + Optional human-readable description of the parameter's purpose. + + + + + + + Set to "no" to disable this parameter without removing it from the configuration. + + + @@ -64,6 +88,13 @@ + + + + Set to "no" to disable this trigger without removing it from the configuration. + + + @@ -74,14 +105,14 @@ - + Maximum number of connections allowed. - + Minimum number of connections to keep alive. @@ -151,7 +182,7 @@ it will wait until the current file buffer (32kb) is really full. This can speed up eXist on some systems where a file sync is an expensive operation (mainly windows - XP; not necessary on Linux). However, group-comit="yes" + XP; not necessary on Linux). However, group-commit="yes" will increase the risk of an already committed operation being rolled back after a database crash. @@ -166,7 +197,7 @@ - + This attributes sets the maximum allowed size of the journal @@ -267,7 +298,7 @@ - + The maximum amount of memory to use for database page buffers. @@ -303,7 +334,7 @@ - + Maximum amount of memory (in megabytes) to use for collection caches. @@ -342,7 +373,7 @@ - + The amount of disk space (in megabytes) which should be available for @@ -449,7 +480,7 @@ - + When set above 0, this captures n frames of each threads stack that performs a try/lock/release @@ -619,14 +650,18 @@ - TODO + Number of documents to index before the n-gram index + is flushed to disk. Higher values improve throughput + at the cost of memory during bulk ingest. - TODO + The n in n-gram: the number of characters per token. + Default 3 produces trigrams, which support efficient + substring searches via the ngram:contains() function. @@ -637,6 +672,13 @@ + + + + Set to "no" to disable this index module without removing it from the configuration. + + + @@ -650,21 +692,25 @@ - TODO + XPath expression to the node to index (e.g. "//book/title"). + Mutually exclusive with qname. - TODO + Qualified name of the element or attribute to index + (e.g. "title" or "@id"). Mutually exclusive with path. - + - TODO + XQuery/XML Schema type to cast node values to when indexing + (e.g. "xs:integer", "xs:dateTime"). Determines the comparison + semantics available on this index. @@ -798,7 +844,7 @@ - + Can be used to define an explicit period for firing the job instead @@ -823,6 +869,13 @@ + + + + Set to "no" to disable this job without removing it from the configuration. + + + @@ -853,6 +906,13 @@ + + + + Set to "no" to disable this feature flag without removing it from the configuration. + + + @@ -883,6 +943,13 @@ + + + + Set to "no" to disable this property without removing it from the configuration. + + + @@ -907,6 +974,13 @@ + + + + Set to "no" to disable this feature flag without removing it from the configuration. + + + @@ -1098,11 +1172,10 @@ - + - You can enable or disable xsl caching by this option. - This option is set to "yes" by default. + Set to "no" to disable XSL stylesheet caching. @@ -1196,21 +1269,34 @@ - TODO + Fully-qualified class name of the Java module implementation. + The class must implement org.exist.xquery.Module. + Mutually exclusive with src. - TODO + Namespace URI that this module is bound to + (e.g. "http://exist-db.org/xquery/math"). + Must match the URI declared inside the module source. - TODO + Path to an XQuery library module source file. + Used instead of class for XQuery-implemented modules. + Mutually exclusive with class. + + + + + + + Set to "no" to disable this module without removing it from the configuration. @@ -1255,24 +1341,23 @@ - When set to "strict", eXist will not use a range index unless all - collections in the context sequence define it. When set to - "always", the query engine will still use an index, even if only - one collection has it defined. It thus leaves it to the user to - properly define indexes and if you forget to specify an index on - a particular collection, it will be missing in the results. + Set to "yes" if a call to doc(), xmldb:document(), collection() or + xmldb:xcollection() should raise an error (FODC0002) when an + XML resource cannot be retrieved. + Set to "no" (default) if such a call should return an empty sequence + when the resource cannot be retrieved. - Set to "yes" if a call to doc(), xmldb:document(), collection() or - xmldb:xcollection() should raise an error (FODC0002) when an - XML resource can not be retrieved. - Set to "no" if a call to doc(), xmldb:document(), collection() or - xmldb:xcollection() should return an empty sequence when an - XML resource can not be retrieved. + Controls whether range indexes must be defined on all collections + in the context sequence before the query engine will use them. + "strict" — the index is used only if every collection in the context + defines it; otherwise the engine falls back to a full scan. + "always" — the engine uses an available index even if only some + collections define it; results may be incomplete if others lack the index. @@ -1308,7 +1393,9 @@ - TODO + Percentage by which the DOM storage file grows when it needs to + be expanded to accommodate new data. A value of 20 means the + file grows by 20% of its current size each time it is extended. @@ -1347,7 +1434,7 @@ - + Defines the maximum amount of bytes stored in memory for each content file instance. @@ -1385,9 +1472,30 @@ - Global vector embedding model registry. When vector-field or vector:embed - omits model-path, the registry supplies path and dimension. Add models - here to use custom or additional embedding models. + Global vector embedding model registry used by the vector extension + (extensions/vector). Requires the vector extension JAR on the classpath + and the vector XQuery module enabled in <builtin-modules>. + + This registry maps short model identifiers to their resolved path and + embedding dimension. When a collection.xconf <vector-field> element + or a vector:embed() / vector:embed-batch() call omits the model-path + parameter, the registry resolves path and dimension from the matching + <model id="..."> entry here. If no entry matches, the runtime falls + back to looking for a directory named "onnx-models/{model-id}" under + $EXIST_HOME. + + Registered models are enumerable at query time via vector:models(). + + Example — register a local ONNX model and an OpenAI API endpoint: + + <vector-models enabled="yes"> + <model id="all-MiniLM-L6-v2" + path="onnx-models/all-MiniLM-L6-v2" + dimension="384"/> + <model id="text-embedding-3-small" + path="https://api.openai.com/v1" + dimension="1536"/> + </vector-models> @@ -1396,22 +1504,69 @@ - Model identifier (e.g. all-MiniLM-L6-v2) + + Short identifier for this model. Must match the value + used in collection.xconf <vector-field model="..."> + and in vector:embed($text, $model-id, ...) calls. + Typical values: "all-MiniLM-L6-v2", "multilingual-e5-large", + "text-embedding-3-small". + - Local path or HuggingFace/API URL + + Location of the embedding model. Three forms are accepted: + + 1. Relative path — resolved against $EXIST_HOME. The + directory must contain model.onnx and tokenizer.json. + Example: "onnx-models/all-MiniLM-L6-v2" + + 2. Absolute path — e.g. "/opt/models/all-MiniLM-L6-v2". + Same layout requirements as relative paths. + + 3. HTTP API base URL — for OpenAI-compatible embedding + APIs (OpenAI, Azure OpenAI, local proxies such as + Ollama). The runtime appends /embeddings to the base + URL and authenticates via the OPENAI_API_KEY + environment variable (or the apiKey parameter of + vector:embed). + Example: "https://api.openai.com/v1" + - + - Embedding dimension (default 384) + + Number of float32 values in the output embedding vector. + Must match the actual model output dimension; used to size + the Lucene KNN field and validate embeddings at index time. + + Defaults to 384 when omitted. + + Common values: + 384 — all-MiniLM-L6-v2, paraphrase-MiniLM-L6-v2 + 768 — multilingual-e5-base, BERT-base variants + 1024 — multilingual-e5-large + 1536 — text-embedding-3-small (OpenAI) + 3072 — text-embedding-3-large (OpenAI) + + + + + Set to "no" to disable the vector model registry without removing + it from the configuration. When disabled, vector-field and vector:embed + will not resolve model IDs via this registry; calls that rely on + registry-supplied paths or dimensions will fall back to the + $EXIST_HOME/onnx-models/{model-id} default location. + + + diff --git a/schema/generate-conf-fixture.xsl b/schema/generate-conf-fixture.xsl index 98b44a42248..542fcd4a8e2 100644 --- a/schema/generate-conf-fixture.xsl +++ b/schema/generate-conf-fixture.xsl @@ -125,6 +125,10 @@ + + + @@ -135,6 +139,9 @@ + + + @@ -146,9 +153,15 @@ Canonical's RestXq/AutoDeployment startup triggers assume a full webapp deployment, a RESTXQ registry, an autodeploy directory, neither present nor wanted in an isolated test fixture, so they're dropped by default; restored per-fixture via $extra-triggers if needed. + XQueryStartupTrigger is dropped too: it requires /db/system/autostart infrastructure not + present in test fixtures. Re-add via $extra-triggers when needed. --> + + +