/* * @(#)ConfigurationStore.java * * Copyright 2004-2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistribution of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed or intended for use in * the design, construction, operation or maintenance of any nuclear facility. */ package com.sun.xacml; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import com.sun.xacml.attr.AttributeFactory; import com.sun.xacml.attr.AttributeFactoryProxy; import com.sun.xacml.attr.AttributeProxy; import com.sun.xacml.attr.BaseAttributeFactory; import com.sun.xacml.attr.StandardAttributeFactory; import com.sun.xacml.combine.BaseCombiningAlgFactory; import com.sun.xacml.combine.CombiningAlgFactory; import com.sun.xacml.combine.CombiningAlgFactoryProxy; import com.sun.xacml.combine.CombiningAlgorithm; import com.sun.xacml.combine.StandardCombiningAlgFactory; import com.sun.xacml.cond.BaseFunctionFactory; import com.sun.xacml.cond.BasicFunctionFactoryProxy; import com.sun.xacml.cond.Function; import com.sun.xacml.cond.FunctionFactory; import com.sun.xacml.cond.FunctionFactoryProxy; import com.sun.xacml.cond.FunctionProxy; import com.sun.xacml.cond.StandardFunctionFactory; import com.sun.xacml.cond.cluster.FunctionCluster; import com.sun.xacml.finder.AttributeFinder; import com.sun.xacml.finder.AttributeFinderModule; import com.sun.xacml.finder.PolicyFinder; import com.sun.xacml.finder.PolicyFinderModule; import com.sun.xacml.finder.ResourceFinder; import com.sun.xacml.finder.ResourceFinderModule; /** * This class supports run-time loading of configuration data. It loads the configurations from an * XML file that conforms to the configuration schema. By design this class does not get used * automatically, nor does it change the state of the system directly. A programmer must choose to * support this mechanism in their program, and then must explicitly use loaded elements. This way, * the programmer still has full control over their security model, but also has the convenience of * re-using a common configuration mechanism. See * http://sunxacml.sourceforge.net/schema/config-0.4.xsd for the valid schema. * <p> * Note that becuase this doesn't tie directly into the rest of the code, you are still free to * design your own run-time configuration mechanisms. This is simply provided as a convenience, and * so that all programmers can start from a common point. * * @since 1.2 * @author Seth Proctor * * Adding generic type support by Christian Mueller (geotools) */ public class ConfigurationStore { /** * Property used to specify the configuration file. */ public static final String PDP_CONFIG_PROPERTY = "com.sun.xacml.PDPConfigFile"; // pdp elements private PDPConfig defaultPDPConfig; private HashMap<String, PDPConfig> pdpConfigMap; // attribute factory elements private AttributeFactory defaultAttributeFactory; private HashMap<String, AttributeFactory> attributeMap; // combining algorithm factory elements private CombiningAlgFactory defaultCombiningFactory; private HashMap<String, CombiningAlgFactory> combiningMap; // function factory elements private FunctionFactoryProxy defaultFunctionFactoryProxy; private HashMap<String, FunctionFactoryProxy> functionMap; // the classloader we'll use for loading classes private ClassLoader loader; // the logger we'll use for all messages private static final Logger logger = Logger.getLogger(ConfigurationStore.class.getName()); /** * Default constructor. This constructor uses the <code>PDP_CONFIG_PROPERTY</code> property to * load the configuration. If the property isn't set, if it names a file that can't be accessed, * or if the file is invalid, then an exception is thrown. * * @throws ParsingException * if anything goes wrong during the parsing of the configuration file, the class * loading, or the factory and pdp setup */ public ConfigurationStore() throws ParsingException { String configFile = System.getProperty(PDP_CONFIG_PROPERTY); // make sure that the right property was set if (configFile == null) { logger.severe("A property defining a config file was expected, " + "but none was provided"); throw new ParsingException("Config property " + PDP_CONFIG_PROPERTY + " needs to be set"); } try { setupConfig(new File(configFile)); } catch (ParsingException pe) { logger.log(Level.SEVERE, "Runtime config file couldn't be loaded" + " so no configurations will be available", pe); throw pe; } } /** * Constructor that explicitly specifies the configuration file to load. This is useful if your * security model doesn't allow the use of properties, if you don't want to use a property to * specify a configuration file, or if you want to use more then one configuration file. If the * file can't be accessed, or if the file is invalid, then an exception is thrown. * * @throws ParsingException * if anything goes wrong during the parsing of the configuration file, the class * loading, or the factory and pdp setup */ public ConfigurationStore(File configFile) throws ParsingException { try { setupConfig(configFile); } catch (ParsingException pe) { logger.log(Level.SEVERE, "Runtime config file couldn't be loaded" + " so no configurations will be available", pe); throw pe; } } /** * Private helper function used by both constructors to actually load the configuration data. * This is the root of several private methods used to setup all the pdps and factories. */ private void setupConfig(File configFile) throws ParsingException { logger.config("Loading runtime configuration"); // load our classloader loader = getClass().getClassLoader(); // get the root node from the configuration file Node root = getRootNode(configFile); // initialize all the maps pdpConfigMap = new HashMap<String, PDPConfig>(); attributeMap = new HashMap<String, AttributeFactory>(); combiningMap = new HashMap<String, CombiningAlgFactory>(); functionMap = new HashMap<String, FunctionFactoryProxy>(); // get the default names NamedNodeMap attrs = root.getAttributes(); String defaultPDP = attrs.getNamedItem("defaultPDP").getNodeValue(); String defaultAF = getDefaultFactory(attrs, "defaultAttributeFactory"); String defaultCAF = getDefaultFactory(attrs, "defaultCombiningAlgFactory"); String defaultFF = getDefaultFactory(attrs, "defaultFunctionFactory"); // loop through all the root-level elements, for each one getting its // name and then loading the right kind of element NodeList children = root.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); String childName = child.getNodeName(); String elementName = null; // get the element's name if (child.getNodeType() == Node.ELEMENT_NODE) elementName = child.getAttributes().getNamedItem("name").getNodeValue(); // see if this is a pdp or a factory, and load accordingly, // putting the new element into the respective map...make sure // that we're never loading something with the same name twice if (childName.equals("pdp")) { if (logger.isLoggable(Level.CONFIG)) logger.config("Loading PDP: " + elementName); if (pdpConfigMap.containsKey(elementName)) throw new ParsingException("more that one pdp with " + "name \"" + elementName + "\""); pdpConfigMap.put(elementName, parsePDPConfig(child)); } else if (childName.equals("attributeFactory")) { if (logger.isLoggable(Level.CONFIG)) logger.config("Loading AttributeFactory: " + elementName); if (attributeMap.containsKey(elementName)) throw new ParsingException("more that one " + "attributeFactory with name " + elementName + "\""); attributeMap.put(elementName, parseAttributeFactory(child)); } else if (childName.equals("combiningAlgFactory")) { if (logger.isLoggable(Level.CONFIG)) logger.config("Loading CombiningAlgFactory: " + elementName); if (combiningMap.containsKey(elementName)) throw new ParsingException("more that one " + "combiningAlgFactory with " + "name \"" + elementName + "\""); combiningMap.put(elementName, parseCombiningAlgFactory(child)); } else if (childName.equals("functionFactory")) { if (logger.isLoggable(Level.CONFIG)) logger.config("Loading FunctionFactory: " + elementName); if (functionMap.containsKey(elementName)) throw new ParsingException("more that one functionFactory" + " with name \"" + elementName + "\""); functionMap.put(elementName, parseFunctionFactory(child)); } } // finally, extract the default elements defaultPDPConfig = (PDPConfig) (pdpConfigMap.get(defaultPDP)); defaultAttributeFactory = (AttributeFactory) (attributeMap.get(defaultAF)); if (defaultAttributeFactory == null) { try { defaultAttributeFactory = AttributeFactory.getInstance(defaultAF); } catch (Exception e) { throw new ParsingException("Unknown AttributeFactory", e); } } defaultCombiningFactory = (CombiningAlgFactory) (combiningMap.get(defaultCAF)); if (defaultCombiningFactory == null) { try { defaultCombiningFactory = CombiningAlgFactory.getInstance(defaultCAF); } catch (Exception e) { throw new ParsingException("Unknown CombininAlgFactory", e); } } defaultFunctionFactoryProxy = (FunctionFactoryProxy) (functionMap.get(defaultFF)); if (defaultFunctionFactoryProxy == null) { try { defaultFunctionFactoryProxy = FunctionFactory.getInstance(defaultFF); } catch (Exception e) { throw new ParsingException("Unknown FunctionFactory", e); } } } /** * Private helper that gets a default factory identifier, or fills in the default value if no * identifier is provided. */ private String getDefaultFactory(NamedNodeMap attrs, String factoryName) { Node node = attrs.getNamedItem(factoryName); if (node != null) return node.getNodeValue(); else return PolicyMetaData.XACML_1_0_IDENTIFIER; } /** * Private helper that parses the file and sets up the DOM tree. */ private Node getRootNode(File configFile) throws ParsingException { DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); dbFactory.setIgnoringComments(true); dbFactory.setNamespaceAware(false); dbFactory.setValidating(false); DocumentBuilder db = null; try { db = dbFactory.newDocumentBuilder(); } catch (ParserConfigurationException pce) { throw new ParsingException("couldn't get a document builder", pce); } Document doc = null; try { doc = db.parse(new FileInputStream(configFile)); } catch (IOException ioe) { throw new ParsingException("failed to load the file ", ioe); } catch (SAXException saxe) { throw new ParsingException("error parsing the XML tree", saxe); } catch (IllegalArgumentException iae) { throw new ParsingException("no data to parse", iae); } Element root = doc.getDocumentElement(); if (!root.getTagName().equals("config")) throw new ParsingException("unknown document type: " + root.getTagName()); return root; } /** * Private helper that handles the pdp elements. */ private PDPConfig parsePDPConfig(Node root) throws ParsingException { ArrayList<AttributeFinderModule> attrModules = new ArrayList<AttributeFinderModule>(); HashSet<PolicyFinderModule> policyModules = new HashSet<PolicyFinderModule>(); ArrayList<ResourceFinderModule> rsrcModules = new ArrayList<ResourceFinderModule>(); // go through all elements of the pdp, loading the specified modules NodeList children = root.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); String name = child.getNodeName(); if (name.equals("policyFinderModule")) { policyModules.add((PolicyFinderModule) loadClass("module", child)); } else if (name.equals("attributeFinderModule")) { attrModules.add((AttributeFinderModule) loadClass("module", child)); } else if (name.equals("resourceFinderModule")) { rsrcModules.add((ResourceFinderModule) loadClass("module", child)); } } // after loading the modules, use the collections to setup a // PDPConfig based on this pdp element AttributeFinder attrFinder = new AttributeFinder(); attrFinder.setModules(attrModules); PolicyFinder policyFinder = new PolicyFinder(); policyFinder.setModules(policyModules); ResourceFinder rsrcFinder = new ResourceFinder(); rsrcFinder.setModules(rsrcModules); return new PDPConfig(attrFinder, policyFinder, rsrcFinder); } /** * Private helper that handles the attributeFactory elements. */ private AttributeFactory parseAttributeFactory(Node root) throws ParsingException { AttributeFactory factory = null; // check if we're starting with the standard factory setup if (useStandard(root, "useStandardDatatypes")) { logger.config("Starting with standard Datatypes"); factory = StandardAttributeFactory.getNewFactory(); } else { factory = new BaseAttributeFactory(); } // now look for all datatypes specified for this factory, adding // them as we go NodeList children = root.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); if (child.getNodeName().equals("datatype")) { // a datatype is a class with an identifier String identifier = child.getAttributes().getNamedItem("identifier").getNodeValue(); AttributeProxy proxy = (AttributeProxy) (loadClass("datatype", child)); try { factory.addDatatype(identifier, proxy); } catch (IllegalArgumentException iae) { throw new ParsingException("duplicate datatype: " + identifier, iae); } } } return factory; } /** * Private helper that handles the combiningAlgFactory elements. */ private CombiningAlgFactory parseCombiningAlgFactory(Node root) throws ParsingException { CombiningAlgFactory factory = null; // check if we're starting with the standard factory setup if (useStandard(root, "useStandardAlgorithms")) { logger.config("Starting with standard Combining Algorithms"); factory = StandardCombiningAlgFactory.getNewFactory(); } else { factory = new BaseCombiningAlgFactory(); } // now look for all algorithms specified for this factory, adding // them as we go NodeList children = root.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); if (child.getNodeName().equals("algorithm")) { // an algorithm is a simple class element CombiningAlgorithm alg = (CombiningAlgorithm) (loadClass("algorithm", child)); try { factory.addAlgorithm(alg); } catch (IllegalArgumentException iae) { throw new ParsingException("duplicate combining " + "algorithm: " + alg.getIdentifier().toString(), iae); } } } return factory; } /** * Private helper that handles the functionFactory elements. This one is a little more complex * than the other two factory helper methods, since it consists of three factories (target, * condition, and general). */ private FunctionFactoryProxy parseFunctionFactory(Node root) throws ParsingException { FunctionFactoryProxy proxy = null; FunctionFactory generalFactory = null; FunctionFactory conditionFactory = null; FunctionFactory targetFactory = null; // check if we're starting with the standard factory setup, and // make sure that the proxy is pre-configured if (useStandard(root, "useStandardFunctions")) { logger.config("Starting with standard Functions"); proxy = StandardFunctionFactory.getNewFactoryProxy(); targetFactory = proxy.getTargetFactory(); conditionFactory = proxy.getConditionFactory(); generalFactory = proxy.getGeneralFactory(); } else { generalFactory = new BaseFunctionFactory(); conditionFactory = new BaseFunctionFactory(generalFactory); targetFactory = new BaseFunctionFactory(conditionFactory); proxy = new BasicFunctionFactoryProxy(targetFactory, conditionFactory, generalFactory); } // go through and load the three sections, putting the loaded // functions into the appropriate factory NodeList children = root.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); String name = child.getNodeName(); if (name.equals("target")) { logger.config("Loading [TARGET] functions"); functionParserHelper(child, targetFactory); } else if (name.equals("condition")) { logger.config("Loading [CONDITION] functions"); functionParserHelper(child, conditionFactory); } else if (name.equals("general")) { logger.config("Loading [GENERAL] functions"); functionParserHelper(child, generalFactory); } } return proxy; } /** * Private helper used by the function factory code to load a specific target, condition, or * general section. */ private void functionParserHelper(Node root, FunctionFactory factory) throws ParsingException { // go through all elements in the section NodeList children = root.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); String name = child.getNodeName(); if (name.equals("function")) { // a function section is a simple class element Function function = (Function) (loadClass("function", child)); try { factory.addFunction(function); } catch (IllegalArgumentException iae) { throw new ParsingException("duplicate function", iae); } } else if (name.equals("abstractFunction")) { // an abstract function is a class with an identifier URI identifier = null; try { identifier = new URI(child.getAttributes().getNamedItem("identifier") .getNodeValue()); } catch (URISyntaxException urise) { throw new ParsingException("invalid function identifier", urise); } FunctionProxy proxy = (FunctionProxy) (loadClass("abstract function", child)); try { factory.addAbstractFunction(proxy, identifier); } catch (IllegalArgumentException iae) { throw new ParsingException("duplicate abstract function", iae); } } else if (name.equals("functionCluster")) { // a cluster is a class that will give us a collection of // functions that need to be added one by one into the factory FunctionCluster cluster = (FunctionCluster) (loadClass("function cluster", child)); for (Function function : cluster.getSupportedFunctions()) { try { factory.addFunction(function); } catch (IllegalArgumentException iae) { throw new ParsingException("duplicate function", iae); } } } } } /** * Private helper that is used by all the code to load an instance of the given class...this * assumes that the class is in the classpath, both for simplicity and for stronger security */ private Object loadClass(String prefix, Node root) throws ParsingException { // get the name of the class String className = root.getAttributes().getNamedItem("class").getNodeValue(); if (logger.isLoggable(Level.CONFIG)) logger.config("Loading [ " + prefix + ": " + className + " ]"); // load the given class using the local classloader Class<?> c = null; try { c = loader.loadClass(className); } catch (ClassNotFoundException cnfe) { throw new ParsingException("couldn't load class " + className, cnfe); } Object instance = null; // figure out if there are any parameters to the constructor if (!root.hasChildNodes()) { // we're using a null constructor, so this is easy try { instance = c.newInstance(); } catch (InstantiationException ie) { throw new ParsingException("couldn't instantiate " + className + " with empty constructor", ie); } catch (IllegalAccessException iae) { throw new ParsingException("couldn't get access to instance " + "of " + className, iae); } } else { // parse the arguments to the constructor List<Object> args = null; try { args = getArgs(root); } catch (IllegalArgumentException iae) { throw new ParsingException("illegal class arguments", iae); } int argLength = args.size(); // next we need to see if there's a constructor that matches the // arguments provided...this has to be done by hand since // Class.getConstructor(Class []) doesn't handle sub-classes and // generic types (for instance, a constructor taking List won't // match a parameter list containing ArrayList) // get the list of all available constructors Constructor<?>[] cons = c.getConstructors(); Constructor<?> constructor = null; for (int i = 0; i < cons.length; i++) { // get the parameters for this constructor Class<?>[] params = cons[i].getParameterTypes(); if (params.length == argLength) { int j = 0; // loop through the parameters and see if each one is // assignable from the coresponding input argument for (Object obj : args) { if (!params[j].isAssignableFrom(obj.getClass())) break; j++; } // if we looked at all the parameters, then this // constructor matches the input if (j == argLength) constructor = cons[i]; } // if we've found a matching constructor then stop looping if (constructor != null) break; } // make sure we found a matching constructor if (constructor == null) throw new ParsingException("couldn't find a matching " + "constructor"); // finally, instantiate the class try { instance = constructor.newInstance(args.toArray()); } catch (InstantiationException ie) { throw new ParsingException("couldn't instantiate " + className, ie); } catch (IllegalAccessException iae) { throw new ParsingException("couldn't get access to instance " + "of " + className, iae); } catch (InvocationTargetException ite) { throw new ParsingException("couldn't create " + className, ite); } } return instance; } /** * Private helper that gets the constructor arguments for a given class. Right now this just * supports String and List, but it's trivial to add support for other types should that be * needed. Right now, it's not clear that there's any need for other types. */ private List<Object> getArgs(Node root) { List<Object> args = new ArrayList<Object>(); NodeList children = root.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { Node child = children.item(i); String name = child.getNodeName(); if (child.getNodeType() == Node.ELEMENT_NODE) { if (name.equals("string")) { args.add(child.getFirstChild().getNodeValue()); } else if (name.equals("list")) { args.add(getArgs(child)); } else { throw new IllegalArgumentException("unkown arg type: " + name); } } } return args; } /** * Private helper used by the three factory routines to see if the given factory should be based * on the standard setup */ private boolean useStandard(Node node, String attributeName) { NamedNodeMap map = node.getAttributes(); if (map == null) return true; Node attrNode = map.getNamedItem(attributeName); if (attrNode == null) return true; return attrNode.getNodeValue().equals("true"); } /** * Returns the default PDP configuration. If no default was specified then this throws an * exception. * * @return the default PDP configuration * * @throws UnknownIdentifierException * if there is no default config */ public PDPConfig getDefaultPDPConfig() throws UnknownIdentifierException { if (defaultPDPConfig == null) throw new UnknownIdentifierException("no default available"); return defaultPDPConfig; } /** * Returns the PDP configuration with the given name. If no such configuration exists then an * exception is thrown. * * @return the matching PDP configuation * * @throws UnknownIdentifierException * if the name is unknown */ public PDPConfig getPDPConfig(String name) throws UnknownIdentifierException { Object object = pdpConfigMap.get(name); if (object == null) throw new UnknownIdentifierException("unknown pdp: " + name); return (PDPConfig) object; } /** * Returns a set of identifiers representing each PDP configuration available. * * @return a <code>Set</code> of <code>String</code>s */ public Set<String> getSupportedPDPConfigurations() { return Collections.unmodifiableSet(pdpConfigMap.keySet()); } /** * Returns the default attribute factory. * * @return the default attribute factory */ public AttributeFactory getDefaultAttributeFactory() { return defaultAttributeFactory; } /** * Returns the attribute factory with the given name. If no such factory exists then an * exception is thrown. * * @return the matching attribute factory * * @throws UnknownIdentifierException * if the name is unknown */ public AttributeFactory getAttributeFactory(String name) throws UnknownIdentifierException { Object object = attributeMap.get(name); if (object == null) throw new UnknownIdentifierException("unknown factory: " + name); return (AttributeFactory) object; } /** * Returns a set of identifiers representing each attribute factory available. * * @return a <code>Set</code> of <code>String</code>s */ public Set<String> getSupportedAttributeFactories() { return Collections.unmodifiableSet(attributeMap.keySet()); } /** * Registers all the supported factories with the given identifiers. If a given identifier is * already in use, then that factory is not registered. This method is provided only as a * convenience, and any registration that may involve identifier clashes should be done by * registering each factory individually. */ public void registerAttributeFactories() { for (String id : attributeMap.keySet()) { AttributeFactory af = attributeMap.get(id); try { AttributeFactory.registerFactory(id, new AFProxy(af)); } catch (IllegalArgumentException iae) { logger.log(Level.WARNING, "Couldn't register AttributeFactory:" + id + " (already in use)", iae); } } } /** * Returns the default combiningAlg factory. * * @return the default combiningAlg factory */ public CombiningAlgFactory getDefaultCombiningAlgFactory() { return defaultCombiningFactory; } /** * Returns the combiningAlg factory with the given name. If no such factory exists then an * exception is thrown. * * @return the matching combiningAlg factory * * @throws UnknownIdentifierException * if the name is unknown */ public CombiningAlgFactory getCombiningAlgFactory(String name) throws UnknownIdentifierException { Object object = combiningMap.get(name); if (object == null) throw new UnknownIdentifierException("unknown factory: " + name); return (CombiningAlgFactory) object; } /** * Returns a set of identifiers representing each combiningAlg factory available. * * @return a <code>Set</code> of <code>String</code>s */ public Set<String> getSupportedCombiningAlgFactories() { return Collections.unmodifiableSet(combiningMap.keySet()); } /** * Registers all the supported factories with the given identifiers. If a given identifier is * already in use, then that factory is not registered. This method is provided only as a * convenience, and any registration that may involve identifier clashes should be done by * registering each factory individually. */ public void registerCombiningAlgFactories() { for (String id : combiningMap.keySet()) { CombiningAlgFactory cf = (CombiningAlgFactory) (combiningMap.get(id)); try { CombiningAlgFactory.registerFactory(id, new CAFProxy(cf)); } catch (IllegalArgumentException iae) { logger.log(Level.WARNING, "Couldn't register " + "CombiningAlgFactory: " + id + " (already in use)", iae); } } } /** * Returns the default function factory proxy. * * @return the default function factory proxy */ public FunctionFactoryProxy getDefaultFunctionFactoryProxy() { return defaultFunctionFactoryProxy; } /** * Returns the function factory proxy with the given name. If no such proxy exists then an * exception is thrown. * * @return the matching function factory proxy * * @throws UnknownIdentifierException * if the name is unknown */ public FunctionFactoryProxy getFunctionFactoryProxy(String name) throws UnknownIdentifierException { Object object = functionMap.get(name); if (object == null) throw new UnknownIdentifierException("unknown factory: " + name); return (FunctionFactoryProxy) object; } /** * Returns a set of identifiers representing each function factory proxy available. * * @return a <code>Set</code> of <code>String</code>s */ public Set<String> getSupportedFunctionFactories() { return Collections.unmodifiableSet(functionMap.keySet()); } /** * Registers all the supported factories with the given identifiers. If a given identifier is * already in use, then that factory is not registered. This method is provided only as a * convenience, and any registration that may involve identifier clashes should be done by * registering each factory individually. */ public void registerFunctionFactories() { for (String id : functionMap.keySet()) { FunctionFactoryProxy ffp = (FunctionFactoryProxy) (functionMap.get(id)); try { FunctionFactory.registerFactory(id, ffp); } catch (IllegalArgumentException iae) { logger.log(Level.WARNING, "Couldn't register FunctionFactory: " + id + " (already in use)", iae); } } } /** * Uses the default configuration to re-set the default factories used by the system (attribute, * combining algorithm, and function). If a default is not provided for a given factory, then * that factory will not be set as the system's default. */ public void useDefaultFactories() { logger.fine("Switching to default factories from configuration"); // set the default attribute factory, if it exists here if (defaultAttributeFactory != null) { AttributeFactory.setDefaultFactory(new AFProxy(defaultAttributeFactory)); } // set the default combining algorithm factory, if it exists here if (defaultCombiningFactory != null) { CombiningAlgFactory.setDefaultFactory(new CAFProxy(defaultCombiningFactory)); } // set the default function factories, if they exists here if (defaultFunctionFactoryProxy != null) FunctionFactory.setDefaultFactory(defaultFunctionFactoryProxy); } /** * */ class AFProxy implements AttributeFactoryProxy { private AttributeFactory factory; public AFProxy(AttributeFactory factory) { this.factory = factory; } public AttributeFactory getFactory() { return factory; } } /** * */ class CAFProxy implements CombiningAlgFactoryProxy { private CombiningAlgFactory factory; public CAFProxy(CombiningAlgFactory factory) { this.factory = factory; } public CombiningAlgFactory getFactory() { return factory; } } }