![JAR search and dependency download from the Maven repository](/logo.png)
net.sf.saxon.functions.registry.OnDemandFunctionSet Maven / Gradle / Ivy
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018-2023 Saxonica Limited
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
package net.sf.saxon.functions.registry;
import net.sf.saxon.Configuration;
import net.sf.saxon.expr.Expression;
import net.sf.saxon.expr.StaticContext;
import net.sf.saxon.functions.FunctionLibrary;
import net.sf.saxon.om.FunctionItem;
import net.sf.saxon.om.NamespaceUri;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.trans.SymbolicName;
import net.sf.saxon.trans.XPathException;
import java.util.List;
import java.util.Map;
/**
* The OnDemandFunctionSet
represents a function library where the implementation classes
* are loaded dynamically on demand. The idea is that no failure should occur if implementations
* are not available unless the functions are actually required. The class contains the name of
* a real FunctionLibrary containing the function implementations; that FunctionLibrary is dynamically
* loaded if an attempt is made to bind a function name in the namespace registered with this
* class.
* This mechanism is currently used for the SQL function library, because the implementations
* of these functions are shipped in a separate JAR file (and this is not available on .NET).
* If the target function library cannot be loaded, the relevant functions will be reported as
* being not available.
*/
public class OnDemandFunctionSet implements FunctionLibrary {
private final Configuration config;
private final NamespaceUri namespace;
private final String libraryClass;
private FunctionLibrary library;
public OnDemandFunctionSet(Configuration config, NamespaceUri namespace, String libraryClass) {
this.config = config;
this.namespace = namespace;
this.libraryClass = libraryClass;
}
/**
* Given a function name, test whether it is in the namespace handled by this
* {@code OnDemandFunctionSet}, and if so (and if the library is not already loaded),
* attempt to dynamically load the target {@code FunctionLibrary}.
* @param functionName the function that is required
* @param reasons either null, or a list to which reasons for failure can be added
* @return true if the function name is in the namespace recognized by this library.
*/
private boolean load(SymbolicName.F functionName, List reasons) {
if (functionName.getComponentName().hasURI(namespace)) {
if (library == null) {
try {
Object lib = config.getDynamicLoader().getInstance(libraryClass, null);
if (lib instanceof FunctionLibrary) {
library = (FunctionLibrary)lib;
} else {
if (reasons != null) {
reasons.add("Class " + libraryClass + " was loaded but it is not a FunctionLibrary");
}
return false;
}
} catch (XPathException e) {
if (reasons != null) {
reasons.add("Failed to load class " + libraryClass + ": " + e.getMessage());
}
return false;
}
}
library.setConfiguration(config);
return true;
} else {
return false;
}
}
@Override
public boolean isAvailable(SymbolicName.F functionName, int languageLevel) {
boolean match = load(functionName, null);
return match && library.isAvailable(functionName, languageLevel);
}
@Override
public Expression bind(SymbolicName.F functionName, Expression[] staticArgs,
Map keywords, StaticContext env,
List reasons) throws XPathException {
boolean match = load(functionName, reasons);
if (match) {
if (keywords != null && !keywords.isEmpty()) {
reasons.add("Calls to Saxon SQL functions cannot use keyword arguments");
return null;
}
return library.bind(functionName, staticArgs, null, env, reasons);
} else {
return null;
}
}
@Override
public FunctionLibrary copy() {
return this;
}
@Override
public FunctionItem getFunctionItem(SymbolicName.F functionName, StaticContext staticContext) throws XPathException {
boolean match = load(functionName, null);
if (match) {
return library.getFunctionItem(functionName, staticContext);
} else {
return null;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy