From: <se...@us...> - 2004-02-13 18:00:23
|
Update of /cvsroot/sunxacml/sunxacml/com/sun/xacml/cond In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31308/com/sun/xacml/cond Added Files: StandardFunctionFactory.java Log Message: introduced new, still unstable, factories for standard 1.0/1.1 behavior --- NEW FILE: StandardFunctionFactory.java --- /* * @(#)StandardFunctionFactory.java * * Copyright 2004 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.cond; import com.sun.xacml.ParsingException; import com.sun.xacml.UnknownIdentifierException; import com.sun.xacml.attr.BooleanAttribute; import java.net.URI; import java.net.URISyntaxException; import java.util.Collection; import java.util.Iterator; import java.util.HashMap; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; /** * This factory supports the standard set of functions specified in XACML * 1.0 and 1.1. It is the default factory used by the system. * * @author Seth Proctor */ public class StandardFunctionFactory extends FunctionFactory { // internal identifiers for each of the three types private static final int TARGET_FACTORY = 0; private static final int CONDITION_FACTORY = 1; private static final int GENERAL_FACTORY = 2; // the backing maps for the Function objects private static HashMap targetFunctionMap = null; private static HashMap conditionFunctionMap = null; private static HashMap generalFunctionMap = null; // the three singleton instances private static FunctionFactory targetFactory = null; private static FunctionFactory conditionFactory = null; private static FunctionFactory generalFactory = null; /** * A mapping of the three types from the *_FACTORY fields to their String * representations. This is particularly useful for error messages. */ private static final String [] NAMES = { "Target", "Condition", "General" }; // the type of this instance private int factoryType; // dummy object used as a lock for the getFactory routines // FIXME: this needs a better mechanism private static Object factoryLock = new Object(); /** * Creates a new StandardFunctionFactory, making sure that the default * maps are initialized correctly. */ private StandardFunctionFactory(int type) { factoryType = type; // first off, we always have to fill in the target map, since this // is the base that all three types use if (targetFunctionMap == null) { targetFunctionMap = new HashMap(); // add EqualFunction EqualFunction.addFunctions(targetFunctionMap); // add LogicalFunction LogicalFunction.addFunctions(targetFunctionMap); // add NOfFunction NOfFunction.addFunctions(targetFunctionMap); // add NotFunction NotFunction.addFunctions(targetFunctionMap); // add ComparisonFunction ComparisonFunction.addFunctions(targetFunctionMap); // add MatchFunction MatchFunction.addFunctions(targetFunctionMap); } // next, initialize the condition map if that's what kind we are (or // if we're a GENERAL, in which case we need all the functions) and if // it hasn't been initialized yet if (((type == CONDITION_FACTORY) || (type == GENERAL_FACTORY)) && (conditionFunctionMap == null)) { conditionFunctionMap = new HashMap(targetFunctionMap); // add condition functions from BagFunction BagFunction.addConditionFunctions(conditionFunctionMap); // add condition functions from SetFunction SetFunction.addConditionFunctions(conditionFunctionMap); // add condition functions from HigherOrderFunction HigherOrderFunction.addConditionFunctions(conditionFunctionMap); } // finally, initialize the general map if that's what kind we are and // if it hasn't been initialized yet if ((type == GENERAL_FACTORY) && (generalFunctionMap == null)) { generalFunctionMap = new HashMap(conditionFunctionMap); // add AddFunction AddFunction.addFunctions(generalFunctionMap); // add SubtractFunction SubtractFunction.addFunctions(generalFunctionMap); // add MultiplyFunction MultiplyFunction.addFunctions(generalFunctionMap); // add DivideFunction DivideFunction.addFunctions(generalFunctionMap); // add ModFunction ModFunction.addFunctions(generalFunctionMap); // add AbsFunction AbsFunction.addFunctions(generalFunctionMap); // add RoundFunction RoundFunction.addFunctions(generalFunctionMap); // add FloorFunction FloorFunction.addFunctions(generalFunctionMap); // add DateMathFunction DateMathFunction.addFunctions(generalFunctionMap); // add general functions from BagFunction BagFunction.addGeneralFunctions(generalFunctionMap); // add NumericConvertFunction NumericConvertFunction.addFunctions(generalFunctionMap); // add StringNormalizeFunction StringNormalizeFunction.addFunctions(generalFunctionMap); // add general functions from SetFunction SetFunction.addGeneralFunctions(generalFunctionMap); // add the map function generalFunctionMap.put(MapFunction.NAME, new FunctionProxy() { public Function getInstance(Node root, String xpathVersion) throws Exception { return MapFunction.getInstance(root); } }); } } /** * Returns a FunctionFactory that will only provide those functions that * are usable in Target matching. * * @return a <code>FunctionFactory</code> for target functions */ public static FunctionFactory getTargetFactory() { if (targetFactory == null) { synchronized (factoryLock) { if (targetFactory == null) targetFactory = new StandardFunctionFactory(TARGET_FACTORY); } } return targetFactory; } /** * Returns a FuntionFactory that will only provide those functions that * are usable in the root of the Condition. These Functions are a superset * of the Target functions. * * @return a <code>FunctionFactory</code> for condition functions */ public static FunctionFactory getConditionFactory() { if (conditionFactory == null) { synchronized (factoryLock) { if (conditionFactory == null) conditionFactory = new StandardFunctionFactory(CONDITION_FACTORY); } } return conditionFactory; } /** * Returns a FunctionFactory that provides access to all the functions. * These Functions are a superset of the Condition functions. * * @return a <code>FunctionFactory</code> for all functions */ public static FunctionFactory getGeneralFactory() { if (generalFactory == null) { synchronized (factoryLock) { if (generalFactory == null) generalFactory = new StandardFunctionFactory(GENERAL_FACTORY); } } return generalFactory; } /** * Adds the function to the factory. Most functions have no state, so * the singleton model used here is typically desireable. The factory will * enforce the requirement that a Target or Condition matching function * must be boolean. * * @param function the <code>Function</code> to add to the factory * * @throws IllegalArgumentException if the function's identifier is already * used or if the function is non-boolean * (when this is a Target or Condition * factory) */ public void addFunction(Function function) throws IllegalArgumentException { addFunctionHelper(function, function.getIdentifier()); } /** * Adds the abstract function proxy to the factory. This is used for * those functions which have state, or change behavior (for instance * the standard map function, which changes its return type based on * how it is used). * * @param proxy the <code>FunctionProxy</code> to add to the factory * @param identity the function's identifier * * @throws IllegalArgumentException if the function's identifier is already * used */ public void addAbstractFunction(FunctionProxy proxy, URI identity) throws IllegalArgumentException { addFunctionHelper(proxy, identity); } /** * This is the first of 4 basic helpers used by the function addition * code. This method picks the right starting point based on what kind * of factory this is. */ private void addFunctionHelper(Object object, URI identity) { String id = identity.toString(); switch (factoryType) { case TARGET_FACTORY: addTargetFunctionHelper(object, id); break; case CONDITION_FACTORY: addConditionFunctionHelper(object, id); break; case GENERAL_FACTORY: addGeneralFunctionHelper(object, id); break; } } /** * Adds the function or proxy to the Target map if it can be added to * the other maps as well and if it's not already in the Target map. */ private void addTargetFunctionHelper(Object object, String id) throws IllegalArgumentException { // make sure this doesn't already exist if (targetFunctionMap.containsKey(id)) throw new IllegalArgumentException("function already exists"); // next, add to the Condition list, since all Target functions are // also availabe as Condition functions addConditionFunctionHelper(object, id); // finally, add it to our list targetFunctionMap.put(id, object); } /** * Adds the function or proxy to the Condition map if it can be added to * the General map as well and if it's not already in the Condition map. */ private void addConditionFunctionHelper(Object object, String id) throws IllegalArgumentException { // in case we haven't created the Condition factory, do it now getConditionFactory(); // make sure this doesn't already exist if (conditionFunctionMap.containsKey(id)) throw new IllegalArgumentException("function already exists"); // next, add to the General list, since all Condition functions are // also availabe as General functions addGeneralFunctionHelper(object, id); // finally, add it to our list conditionFunctionMap.put(id, object); } /** * Adds the function or proxy to the General map if it's not already in * that map. */ private void addGeneralFunctionHelper(Object object, String id) throws IllegalArgumentException { // in case we haven't created the General factory, do it now getGeneralFactory(); // make sure this doesn't already exist if (generalFunctionMap.containsKey(id)) throw new IllegalArgumentException("function already exists"); // now add it to our list generalFunctionMap.put(id, object); } /** * Tries to get an instance of the specified function. * * @param identity the name of the function * * @throws UnknownIdentifierException if the name isn't known * @throws FunctionTypeException if the name is known to map to an * abstract function, and should therefore * be created through createAbstractFunction */ public Function createFunction(URI identity) throws UnknownIdentifierException, FunctionTypeException { return createFunction(identity.toString()); } /** * Tries to get an instance of the specified function. * * @param identity the name of the function * * @throws UnknownIdentifierException if the name isn't known * @throws FunctionTypeException if the name is known to map to an * abstract function, and should therefore * be created through createAbstractFunction */ public Function createFunction(String identity) throws UnknownIdentifierException, FunctionTypeException { Object entry = createFunctionHelper(identity); if (entry != null) { if (entry instanceof Function) { return (Function)entry; } else { // this is actually a proxy, which means the other create // method should have been called throw new FunctionTypeException("function is abstract"); } } else { // we couldn't find a match throw new UnknownIdentifierException(NAMES[factoryType] + " functions of type " + identity + " not supported"); } } /** * Tries to get an instance of the specified abstract function. * * @param identity the name of the function * @param root the DOM root containing info used to create the function * * @throws UnknownIdentifierException if the name isn't known * @throws FunctionTypeException if the name is known to map to a * concrete function, and should therefore * be created through createFunction * @throws ParsingException if the function can't be created with the * given inputs */ public Function createAbstractFunction(URI identity, Node root) throws UnknownIdentifierException, ParsingException, FunctionTypeException { return createAbstractFunction(identity.toString(), root, null); } /** * Tries to get an instance of the specified abstract function. * * @param identity the name of the function * @param root the DOM root containing info used to create the function * @param xpathVersion the version specified in the contianing policy, or * null if no version was specified * * @throws UnknownIdentifierException if the name isn't known * @throws FunctionTypeException if the name is known to map to a * concrete function, and should therefore * be created through createFunction * @throws ParsingException if the function can't be created with the * given inputs */ public Function createAbstractFunction(URI identity, Node root, String xpathVersion) throws UnknownIdentifierException, ParsingException, FunctionTypeException { return createAbstractFunction(identity.toString(), root, xpathVersion); } /** * Tries to get an instance of the specified abstract function. * * @param identity the name of the function * @param root the DOM root containing info used to create the function * * @throws UnknownIdentifierException if the name isn't known * @throws FunctionTypeException if the name is known to map to a * concrete function, and should therefore * be created through createFunction * @throws ParsingException if the function can't be created with the * given inputs */ public Function createAbstractFunction(String identity, Node root) throws UnknownIdentifierException, ParsingException, FunctionTypeException { return createAbstractFunction(identity, root, null); } /** * Tries to get an instance of the specified abstract function. * * @param identity the name of the function * @param root the DOM root containing info used to create the function * @param xpathVersion the version specified in the contianing policy, or * null if no version was specified * * @throws UnknownIdentifierException if the name isn't known * @throws FunctionTypeException if the name is known to map to a * concrete function, and should therefore * be created through createFunction * @throws ParsingException if the function can't be created with the * given inputs */ public Function createAbstractFunction(String identity, Node root, String xpathVersion) throws UnknownIdentifierException, ParsingException, FunctionTypeException { Object entry = createFunctionHelper(identity); if (entry != null) { if (entry instanceof FunctionProxy) { try { return ((FunctionProxy)entry).getInstance(root, xpathVersion); } catch (Exception e) { throw new ParsingException("couldn't create abstract" + " function " + identity, e); } } else { // this is actually a concrete function, which means that // the other create method should have been called throw new FunctionTypeException("function is concrete"); } } else { // we couldn't find a match throw new UnknownIdentifierException(NAMES[factoryType] + " abstract functions of " + "type " + identity + " not supported"); } } /** * Looks in the right map for the given key */ private Object createFunctionHelper(String identity) { switch (factoryType) { case TARGET_FACTORY: return targetFunctionMap.get(identity); case CONDITION_FACTORY: return conditionFunctionMap.get(identity); case GENERAL_FACTORY: return generalFunctionMap.get(identity); } return null; } } |