package dods.dap.Server; import java.util.*; import dods.dap.NoSuchFunctionException; /** Represents a library of available server-side functions for use * in evaluating constraint expressions. <p> * * When created, a FunctionLibrary is empty. * There are two ways to populate it, described below. Once the * FunctionLibrary has been created and populated, it should be * used to create a ClauseFactory, which can then be given to * the CEEvaluator for use in parsing.<p> * * <p> The most straightforward is to pass an instance of each * ServerSideFunction class to the add() method. If you have a large * number of ServerSideFunctions, or if you want to have choose class names * for your functions independent of the actual function name, this is the * approach to use. * * A second, more complex method resolves * server-side function names at runtime. The function library automatically * looks for a class whose * name matches the name requested (if a prefix is set, it will * look for a class whose name is prefix + name requested). If such a class * exists, and it implements the ServerSideFunction interface, a new instance * of the class is created using the default constructor, added to the list * of available functions, and returned to the caller. <p> * * This is not quite as complicated as it sounds. For instance, say the * FunctionLibrary's prefix is set to "dods.servers.test.SSF". Then the * first time * the server gets a constraint expression containing the function "dummy()", * the FunctionLibrary will * automatically load the class "dods.servers.test.SSFdummy", and return * a new instance using the class's default constructor. <p> * * This avoids the need to hardcode a list of server-side functions, and * allows you to create new functions at any time. For instance to create * a function "newfn()" you can simply * create the class "dods.servers.test.SSFnewfn" and put it somewhere * in the server's classpath . Then the first CE containing this function will * cause that class to be automatically loaded, just the like the dummy() * function was. * * @author joew */ public class FunctionLibrary { /** Creates a new FunctionLibrary with no prefix set. */ public FunctionLibrary() { this(""); } /** Creates a new FunctionLibrary. * @param prefix A string that will be prepended to function names in order * to create a classname for that function. For example, */ public FunctionLibrary(String prefix) { this.prefix = prefix; this.boolFunctions = new HashMap(); this.btFunctions = new HashMap(); } /** Sets the prefix to use for classname lookup. * For instance, if the prefix * is "myserver.SSF", then when the library doesn't have an entry * for function "xyz" it will look for a class "myserver.SSFxyz". */ public void setPrefix(String prefix) { this.prefix = prefix; } /** Returns the prefix being used for classname lookup. */ public String getPrefix() { return prefix; } /** Adds a function to the library. The function will be inspected * to determine whether it is a boolean or BaseType function. */ public void add(ServerSideFunction function) { if (function instanceof BoolFunction) { boolFunctions.put(function.getName(), function); } if (function instanceof BTFunction) { btFunctions.put(function.getName(), function); } } /** Retrieves a boolean function from the library. If the function * is not found the library will attempt to load it using the * mechanism described in the class documentation. * @param name The name of the function being requested. * @return Null if the function is not * in the library, and the attempt to load it fails. */ public BoolFunction getBoolFunction(String name) throws NoSuchFunctionException { if (!boolFunctions.containsKey(name)) { loadNewFunction(name); } return (BoolFunction)boolFunctions.get(name); } /** Retrieves a BaseType function from the library. If the function * is not found the library will attempt to load it using the * mechanism described in the class documentation. * @param name The name of the function being requested. * @return Null if the function is not * in the library, and the attempt to load it fails. */ public BTFunction getBTFunction(String name) throws NoSuchFunctionException { if (!btFunctions.containsKey(name)) { loadNewFunction(name); } return (BTFunction)btFunctions.get(name); } /** Tries to load a function with the given name. */ protected void loadNewFunction(String name) { try { String fullName = prefix + name; Class value = Class.forName(fullName); if ((ServerSideFunction.class).isAssignableFrom(value)) { add((ServerSideFunction)value.newInstance()); return; } } catch (ClassNotFoundException e) { } catch (IllegalAccessException e) { } catch (InstantiationException e) { } } protected Map boolFunctions; protected Map btFunctions; protected String prefix; }