Update of /cvsroot/sunxacml/sunxacml/com/sun/xacml/cond
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17448/com/sun/xacml/cond
Modified Files:
Apply.java Evaluatable.java Function.java FunctionBase.java
HigherOrderFunction.java MapFunction.java
Added Files:
Expression.java ExpressionHandler.java VariableDefinition.java
VariableManager.java VariableReference.java
Log Message:
introduced support for variable referencing and definition, one of the major
new features in XACML 2.0
Index: HigherOrderFunction.java
===================================================================
RCS file: /cvsroot/sunxacml/sunxacml/com/sun/xacml/cond/HigherOrderFunction.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -C2 -d -r1.8 -r1.9
*** HigherOrderFunction.java 20 Dec 2004 21:21:07 -0000 1.8
--- HigherOrderFunction.java 7 Jan 2005 23:49:32 -0000 1.9
***************
*** 3,7 ****
* @(#)HigherOrderFunction.java
*
! * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
--- 3,7 ----
* @(#)HigherOrderFunction.java
*
! * Copyright 2003-20045Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
***************
*** 180,183 ****
--- 180,192 ----
/**
+ * Returns false since functions aren't directly evaluatable.
+ *
+ * @return false
+ */
+ public boolean isEvaluatable() {
+ return false;
+ }
+
+ /**
* Returns a <code>Set</code> containing all the function identifiers
* supported by this class.
***************
*** 199,202 ****
--- 208,221 ----
/**
+ * Returns the same value as <code>getReturnType</code>. This is here
+ * to support the <code>Expression</code> interface.
+ *
+ * @return the return type
+ */
+ public URI getType() {
+ return getReturnType();
+ }
+
+ /**
* Returns the type of attribute value that will be returned by
* this function.
***************
*** 236,240 ****
// get the first arg, which is the function
! Function function = (Function)(iterator.next());
// get the two inputs ... note that unlike other functions, we don't
--- 255,267 ----
// get the first arg, which is the function
! Expression xpr = (Expression)(iterator.next());
! Function function = null;
!
! if (xpr instanceof Function) {
! function = (Function)xpr;
! } else {
! function = (Function)(((VariableReference)xpr).
! getReferencedDefinition().getExpression());
! }
// get the two inputs ... note that unlike other functions, we don't
***************
*** 375,384 ****
// now, try to cast the first element into a function
! if (! (list[0] instanceof Function))
throw new IllegalArgumentException("first arg to higher-order " +
" function must be a function");
// check that the function returns a boolean
! if (! ((Function)(list[0])).getReturnType().toString().
equals(BooleanAttribute.identifier))
throw new IllegalArgumentException("higher-order function must " +
--- 402,422 ----
// now, try to cast the first element into a function
! Function function = null;
!
! if (list[0] instanceof Function) {
! function = (Function)(list[0]);
! } else if (list[0] instanceof VariableReference) {
! Expression xpr = ((VariableReference)(list[0])).
! getReferencedDefinition().getExpression();
! if (xpr instanceof Function)
! function = (Function)xpr;
! }
!
! if (function == null)
throw new IllegalArgumentException("first arg to higher-order " +
" function must be a function");
// check that the function returns a boolean
! if (! function.getReturnType().toString().
equals(BooleanAttribute.identifier))
throw new IllegalArgumentException("higher-order function must " +
***************
*** 407,411 ****
args.add(eval1);
args.add(eval2);
! ((Function)(list[0])).checkInputsNoBag(args);
}
--- 445,449 ----
args.add(eval1);
args.add(eval2);
! function.checkInputsNoBag(args);
}
Index: FunctionBase.java
===================================================================
RCS file: /cvsroot/sunxacml/sunxacml/com/sun/xacml/cond/FunctionBase.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -C2 -d -r1.3 -r1.4
*** FunctionBase.java 17 Mar 2004 18:03:38 -0000 1.3
--- FunctionBase.java 7 Jan 2005 23:49:32 -0000 1.4
***************
*** 3,7 ****
* @(#)FunctionBase.java
*
! * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
--- 3,7 ----
* @(#)FunctionBase.java
*
! * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
***************
*** 223,226 ****
--- 223,235 ----
/**
+ * Returns false since functions aren't directly evaluatable.
+ *
+ * @return false
+ */
+ public boolean isEvaluatable() {
+ return false;
+ }
+
+ /**
* Returns the full identifier of this function, as known by the factories.
*
***************
*** 261,264 ****
--- 270,283 ----
/**
+ * Returns the same value as <code>getReturnType</code>. This is here
+ * to support the <code>Expression</code> interface.
+ *
+ * @return the return type
+ */
+ public URI getType() {
+ return getReturnType();
+ }
+
+ /**
* Get the attribute type returned by this function.
*
--- NEW FILE: Expression.java ---
/*
* @(#)Expression.java
*
* Copyright 2005 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 java.net.URI;
/**
* This interface represents the expression type in the XACML 2.0 schema.
*
* @since 2.0
* @author Seth Proctor
*/
public interface Expression
{
/**
* Returns true if this expression is evaluatable. Typically, this
* is any expression type except for functions, which can't be
* evaluated directly.
*
* @return true if this expression is evaluatable
*/
public boolean isEvaluatable();
/**
* Returns the type of the expression.
*
* @return the attribute type of the referenced expression
*/
public URI getType();
}
--- NEW FILE: VariableReference.java ---
/*
* @(#)VariableReference.java
*
* Copyright 2005 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.EvaluationCtx;
import com.sun.xacml.Indenter;
import com.sun.xacml.ParsingException;
import com.sun.xacml.ProcessingException;
import com.sun.xacml.attr.AttributeValue;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URI;
import java.util.Collections;
import java.util.List;
import org.w3c.dom.Node;
/**
* This class supports the VariableReferenceType type introuced in XACML
* 2.0. It allows an expression to reference a variable definition. If there
* is no such definition then the Policy is invalid. A reference can be
* included anywwhere in an expression where the referenced expression would
* be valid.
*
* @since 2.0
* @author Seth Proctor
*/
public class VariableReference implements Evaluatable
{
// the identifier used to resolve the reference
private String variableId;
// the actual definition we refernce, if it's known
private VariableDefinition definition = null;
// a manager for resolving references, if it's been provided
private VariableManager manager = null;
/**
* Simple constructor that takes only the identifier. This is provided
* for tools that want to build policies only for the sake of encoding
* or displaying them. This constructor will not create a reference
* that can be followed to its associated definition, so it cannot be
* used in evaluation.
*
* @param variableId the reference identifier
*/
public VariableReference(String variableId) {
this.variableId = variableId;
}
/**
* Constructor that takes the definition referenced by this class. If
* you're building policies programatically, this is typically the form
* you use. It does make the connection from reference to definition,
* so this will result in an evaluatable reference.
*
* @param definition the definition this class references
*/
public VariableReference(VariableDefinition definition) {
this.variableId = definition.getVariableId();
this.definition = definition;
}
/**
* Constructor that takes the reference identifier and a manager. This
* is typically only used by parsing code, since the manager is used
* to handle out-of-order definitions and circular references.
*
* @param variableId the reference identifier
* @param manager a <code>VariableManager</code> used to handle the
* dependencies between references and definitions during
* parsing
*/
public VariableReference(String variableId, VariableManager manager) {
this.variableId = variableId;
this.manager = manager;
}
/**
* Returns a new instance of the <code>VariableReference</code> class
* based on a DOM node. The node must be the root of an XML
* VariableReferenceType.
*
* @param root the DOM root of a VariableReferenceType XML type
* @param manager the <code>VariableManager</code> used to connect this
* reference to its definition
*
* @throws ParsingException if the VariableReferenceType is invalid
*/
public static VariableReference getInstance(Node root,
VariableManager manager)
throws ParsingException
{
// pretty easy, since there's just an attribute...
String variableId = root.getAttributes().getNamedItem("VariableId").
getNodeValue();
// ...but we keep the manager since after this we'll probably get
// asked for our type, etc., and the manager will also be used to
// resolve the actual definition
return new VariableReference(variableId, manager);
}
/**
* Returns true since this expression is evaluatable.
*
* @return true
*/
public boolean isEvaluatable() {
return true;
}
/**
* Returns the reference identifier.
*
* @return the reference's identifier
*/
public String getVariableId() {
return variableId;
}
/**
* Returns the <code>VariableDefinition</code> referenced by this class,
* or null if the definition cannot be resolved.
*
* @return the referenced definition or null
*/
public VariableDefinition getReferencedDefinition() {
// if this was created with a concrete definition, then that's what
// we return, otherwise we query the manager (if we have one)
if (definition != null) {
return definition;
} else if (manager != null) {
return manager.getDefinition(variableId);
}
// if the simple constructor was used, then we have nothing
return null;
}
/**
* Evaluates the referenced expression using the given context, and either
* returns an error or a resulting value. If this doesn't reference an
* evaluatable expression (eg, a single Function) then this will throw
* an exception.
*
* @param context the representation of the request
*
* @return the result of evaluation
*
* @throws ProcessingException if the expression isn't evaluatable
*/
public EvaluationResult evaluate(EvaluationCtx context) {
Expression xpr = getReferencedDefinition().getExpression();
if (xpr.isEvaluatable())
return ((Evaluatable)xpr).evaluate(context);
throw new ProcessingException("tried to evaluate an expression " +
"that isn't evaluatable");
}
/**
* Returns the type of the referenced expression.
*
* @return the attribute return type of the referenced expression
*
* @throws ProcessingException if the type couldn't be resolved
*/
public URI getType() {
// if we have a concrete definition, then ask it for the type,
// otherwise query the manager using the getVariableType method,
// since this handles type-checking for definitions that haven't
// been parsed yet
if (definition != null) {
return definition.getExpression().getType();
} else {
if (manager != null)
return manager.getVariableType(variableId);
}
throw new ProcessingException("couldn't resolve the type");
}
/**
* Tells whether evaluation will return a bag or a single value.
*
* @return true if evaluation will return a bag, false otherwise
*
* @throws ProcessingException if the return type couldn't be resolved
*/
public boolean evaluatesToBag() {
// see comment in getType()
if (definition != null) {
Expression xpr = getReferencedDefinition().getExpression();
// FIXME: for now we need to do this casting, but this should
// change soon when the Function interface comes in line with
// the Evaluatable type methods through the Expression interface
if (xpr.isEvaluatable())
return ((Evaluatable)xpr).evaluatesToBag();
else
return ((Function)xpr).returnsBag();
} else {
if (manager != null)
return manager.evaluatesToBag(variableId);
}
throw new ProcessingException("couldn't resolve the return type");
}
/**
* Always returns an empty list since references never have children in
* the policy tree. Note that the referenced definition may still have
* children, so tools may want to treat these as children of this
* reference, but must take care since circular references could create
* a tree of infinite depth.
*
* @return an empty <code>List</code>
*/
public List getChildren() {
return Collections.EMPTY_LIST;
}
/**
* Encodes this class into its XML representation and writes this
* encoding to the given <code>OutputStream</code> with no indentation.
*
* @param output a stream into which the XML-encoded data is written
*/
public void encode(OutputStream output) {
encode(output, new Indenter(0));
}
/**
* Encodes this class into its XML representation and writes this
* encoding to the given <code>OutputStream</code> with indentation.
*
* @param output a stream into which the XML-encoded data is written
* @param indenter an object that creates indentation strings
*/
public void encode(OutputStream output, Indenter indenter) {
PrintStream out = new PrintStream(output);
String indent = indenter.makeString();
out.println(indent + "<VariableReference VariableId=\"" +
variableId + "\"/>");
}
}
--- NEW FILE: VariableManager.java ---
/*
* @(#)VariableManager.java
*
* Copyright 2005 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.ProcessingException;
import java.net.URI;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* This class is used by the parsing routines to handle the relationships
* between variable references and definitions. Specifically, it takes care
* of the fact that definitions can be placed after their first reference,
* and can use references to create circular or recursive relationships. It
* keeps track of what's in the process of being parsed and will pre-parse
* elements as needed.
* <p>
* Note that you should never have to use this class directly. It is really
* meant only as a utility for the internal parsing routines. Also, note that
* the operations on this class are not thread-safe. Typically this doesn't
* matter, since the code doesn't support using more than one thread to
* parse a single Policy.
*
* @since 2.0
* @author Seth Proctor
*/
public class VariableManager
{
// the map from identifiers to internal data
private Map idMap;
// the version of xpath defined in the policy, if any
private String xpathVersion;
/**
* Creates a manager with a fixed set of supported identifiers. For
* each of these identifiers, the map supplies a cooresponding DOM node
* used to parse the definition. This is used if, in the course of
* parsing one definition, a reference requires that you have information
* about another definition available. All parsed definitions are cached
* so that each is only parsed once. If a node is not provided, then the
* parsing code may throw an exception if out-of-order or circular
* refereces are used.
* <p>
* Note that the use of a DOM node may change to an arbitrary interface,
* so that you could use your own mechanism, but this is still being
* hashed out. This interface will be forzed before a 2.0 release.
*
* @param variableIds a <code>Map</code> from an identifier to the
* <code>Node</code> that is the root of the
* cooresponding variable definition, or null
*/
public VariableManager(Map variableIds, String xpathVersion) {
idMap = new HashMap();
Iterator it = variableIds.keySet().iterator();
while (it.hasNext()) {
Object key = it.next();
Node node = (Node)(variableIds.get(key));
idMap.put(key, new VariableState(null, node, null, false, false));
}
this.xpathVersion = xpathVersion;
}
/**
* Returns the definition with the given identifier. If the definition
* is not available, then this method will try to get the definition
* based on the DOM node given for this identifier. If parsing the
* definition requires loading another definition (because of a reference)
* then this method will be recursively invoked. This may make it slow
* to call this method once, but all retrieved definitions are cached,
* and once this manager has started parsing a definition it will never
* try parsing that definition again. If the definition cannot be
* retrieved, then an exception is thrown.
*
* @param variableId the definition's identifier
*
* @return the identified definition
*
* @throws ProcessingException if the definition cannot be resolved
*/
public VariableDefinition getDefinition(String variableId) {
VariableState state = (VariableState)(idMap.get(variableId));
// make sure this is an identifier we handle
if (state == null)
throw new ProcessingException("variable is unsupported: " +
variableId);
// if we've resolved the definition before, then we're done
if (state.definition != null)
return state.definition;
// we don't have the definition, so get the DOM node
Node node = state.rootNode;
// we can't keep going unless we have a node to work with
if (node != null) {
// if we've already started parsing this node before, then
// don't start again
if (state.handled)
// FIXME: should we use a different exception here?
throw new ProcessingException("processing in progress");
// keep track of the fact that we're parsing this node, and
// also get the type (if it's an Apply node)
state.handled = true;
discoverApplyType(node, state);
try {
// now actually try parsing the definition...remember that
// if its expression has a reference, we could end up
// calling this manager method again
state.definition =
VariableDefinition.getInstance(state.rootNode,
xpathVersion, this);
return state.definition;
} catch (ParsingException pe) {
// we failed to parse the definition for some reason
throw new ProcessingException("failed to parse the definition",
pe);
}
}
// we couldn't figure out how to resolve the definition
throw new ProcessingException("couldn't retrieve definition: " +
variableId);
}
/**
* Private helper method to get the type of an expression, but only if
* that expression is an Apply. Basically, if there is a circular
* reference, then we'll need to know the types before we're done
* parsing one of the definitions. But, a circular reference that
* requires type-checking can only happen if the definition's expression
* is an Apply. So, we look here, and if it's an Apply, we get the
* type information and store that for later use, just in case.
* <p>
* Note that we could wait until later to try this, or we could check
* first to see if there will be a circular reference. Comparatively,
* however, this isn't too expensive, and it makes the system much
* simpler. Still, it's worth re-examining this to see if there's a
* way that makes more sense.
*/
private void discoverApplyType(Node root, VariableState state) {
// get the first element, which is the expression node
NodeList nodes = root.getChildNodes();
Node xprNode = nodes.item(0);
int i = 1;
while (xprNode.getNodeType() != Node.ELEMENT_NODE)
xprNode = nodes.item(i++);
// now see if the node is an Apply
if (xprNode.getNodeName().equals("Apply")) {
try {
// get the function in the Apply...
Function function = ExpressionHandler.
getFunction(xprNode, xpathVersion,
FunctionFactory.getGeneralInstance());
// ...and store the type information in the variable state
state.type = function.getReturnType();
state.evaluatesToBag = function.returnsBag();
} catch (ParsingException pe) {
// we can just ignore this...if there really is an error,
// then it will come up during parsing in a code path that
// can handle the error cleanly
}
}
}
/**
* Returns the datatype that the identified definition's expression
* resolves to on evaluation. Note that this method makes every attempt
* to discover this value, including parsing dependent definitions if
* needed and possible.
*
* @param variableId the identifier for the definition
*
* @return the datatype that the identified definition's expression
* evaluates to
*
* @throws ProcessingException if the identifier is not supported or if
* the result cannot be resolved
*/
public URI getVariableType(String variableId) {
VariableState state = (VariableState)(idMap.get(variableId));
// make sure the variable is supported
if (state == null)
throw new ProcessingException("variable not supported: " +
variableId);
// if we've previously figured out the type, then return that
if (state.type != null)
return state.type;
// we haven't figured out the type already, so see if we have or
// can resolve the definition
VariableDefinition definition = state.definition;
if (definition == null)
definition = getDefinition(variableId);
// if we could get the definition, then ask it for the type
if (definition != null)
return definition.getExpression().getType();
// we exhausted all our ways to get the right answer
throw new ProcessingException("we couldn't establish the type: " +
variableId);
}
/**
* Returns true if the identified definition's expression resolves to
* a bag on evaluation. Note that this method makes every attempt to
* discover this value, including parsing dependent definitions if
* needed and possible.
*
* @param variableId the identifier for the definition
*
* @return true if the identified definition's expression evaluates
* to a bag
*
* @throws ProcessingException if the identifier is not supported or if
* the result cannot be resolved
*/
public boolean evaluatesToBag(String variableId) {
VariableState state = (VariableState)(idMap.get(variableId));
// make sure the variable is supported
if (state == null)
throw new ProcessingException("variable not supported: " +
variableId);
// the flag is only valid if a type has also been determined
if (state.type != null)
return state.evaluatesToBag;
// we haven't figured out the type already, so see if we have or
// can resolve the definition
VariableDefinition definition = state.definition;
if (definition == null)
definition = getDefinition(variableId);
// if we could get the definition, then ask it for the bag return
if (definition != null) {
Expression xpr = definition.getExpression();
// FIXME: remove this casing once the Function and Expression
// interfaces are updated
if (xpr.isEvaluatable())
return ((Evaluatable)xpr).evaluatesToBag();
else
return ((Function)xpr).returnsBag();
}
// we exhausted all our ways to get the right answer
throw new ProcessingException("couldn't establish bag return for " +
variableId);
}
/**
* Inner class that is used simply to manage fields associated with a
* given identifier.
*/
class VariableState {
// the resolved definition for the identifier
public VariableDefinition definition;
// the DOM node used to parse the definition
public Node rootNode;
// the datatype returned when evaluating the definition
public URI type;
// whether the definition's root evaluates to a Bag
public boolean evaluatesToBag;
// whether the definition is being parsed and constructed
public boolean handled;
public VariableState() {
this.definition = null;
this.rootNode = null;
this.type = null;
this.evaluatesToBag = false;
this.handled = false;
}
public VariableState(VariableDefinition definition, Node rootNode,
URI type, boolean evaluatesToBag,
boolean handled) {
this.definition = definition;
this.rootNode = rootNode;
this.type = type;
this.evaluatesToBag = evaluatesToBag;
this.handled = handled;
}
}
}
--- NEW FILE: VariableDefinition.java ---
/*
* @(#)VariableDefinition.java
*
* Copyright 2005 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.Indenter;
import com.sun.xacml.ParsingException;
import java.io.OutputStream;
import java.io.PrintStream;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* This class supports the VariableDefinitionType type introuced in XACML
* 2.0. It allows a Policy to pre-define any number of expression blocks for
* general use. Note that it's legal (though not usually useful) to define
* expressions that don't get referenced within the Policy. It is illegal to
* have more than one definition with the same identifier within a Policy.
*
* @since 2.0
* @author Seth Proctor
*/
public class VariableDefinition
{
// the identitifer for this definition
private String variableId;
// the actual expression defined here
private Expression expression;
/**
* Creates a new <code>VariableDefinition</code> with the given
* identifier and expression.
*
* @param variableId the identifier for this definition
* @param expression the expression defined here
*/
public VariableDefinition(String variableId, Expression expression) {
this.variableId = variableId;
this.expression = expression;
}
/**
* Returns a new instance of the <code>VariableDefinition</code> class
* based on a DOM node. The node must be the root of an XML
* VariableDefinitionType.
*
* @param root the DOM root of a VariableDefinitionType XML type
* @param xpathVersion the XPath version to use in any selectors or XPath
* functions, or null if this is unspecified (ie, not
* supplied in the defaults section of the policy)
* @param manager <code>VariableManager</code> used to connect references
* to this definition
*
* @throws ParsingException if the VariableDefinitionType is invalid
*/
public static VariableDefinition getInstance(Node root,
String xpathVersion,
VariableManager manager)
throws ParsingException
{
String variableId = root.getAttributes().getNamedItem("VariableId").
getNodeValue();
// get the first element, which is the expression node
NodeList nodes = root.getChildNodes();
Node xprNode = nodes.item(0);
int i = 1;
while (xprNode.getNodeType() != Node.ELEMENT_NODE)
xprNode = nodes.item(i++);
// use that node to get the expression
Expression xpr = ExpressionHandler.
parseExpression(xprNode, xpathVersion, manager);
return new VariableDefinition(variableId, xpr);
}
/**
* Returns the identifier for this definition.
*
* @return the definition's identifier
*/
public String getVariableId() {
return variableId;
}
/**
* Returns the expression provided by this definition.
*
* @return the definition's expression
*/
public Expression getExpression() {
return expression;
}
/**
* Encodes this class into its XML representation and writes this
* encoding to the given <code>OutputStream</code> with no indentation.
*
* @param output a stream into which the XML-encoded data is written
*/
public void encode(OutputStream output) {
encode(output, new Indenter(0));
}
/**
* Encodes this class into its XML representation and writes this
* encoding to the given <code>OutputStream</code> with indentation.
*
* @param output a stream into which the XML-encoded data is written
* @param indenter an object that creates indentation strings
*/
public void encode(OutputStream output, Indenter indenter) {
PrintStream out = new PrintStream(output);
String indent = indenter.makeString();
out.println(indent + "<VariableDefinition VariableId=\"" +
variableId + "\">");
indenter.in();
if (expression.isEvaluatable()) {
((Evaluatable)expression).encode(output, indenter);
} else {
Function function = (Function)expression;
out.println(indenter.makeString() + "<Function FunctionId=\"" +
function.getIdentifier() + "\"/>");
}
out.println("</VariableDefinition>");
indenter.out();
}
}
Index: Apply.java
===================================================================
RCS file: /cvsroot/sunxacml/sunxacml/com/sun/xacml/cond/Apply.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -C2 -d -r1.8 -r1.9
*** Apply.java 14 May 2004 20:43:07 -0000 1.8
--- Apply.java 7 Jan 2005 23:49:31 -0000 1.9
***************
*** 3,7 ****
* @(#)Apply.java
*
! * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
--- 3,7 ----
* @(#)Apply.java
*
! * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
***************
*** 147,158 ****
* functions, or null if this is unspecified (ie, not
* supplied in the defaults section of the policy)
*
* @throws ParsingException if this is not a valid ConditionType
*/
! public static Apply getConditionInstance(Node root, String xpathVersion)
throws ParsingException
{
return getInstance(root, FunctionFactory.getConditionInstance(), true,
! xpathVersion);
}
--- 147,161 ----
* functions, or null if this is unspecified (ie, not
* supplied in the defaults section of the policy)
+ * @param manager <code>VariableManager</code> used to connect references
+ * and definitions while parsing
*
* @throws ParsingException if this is not a valid ConditionType
*/
! public static Apply getConditionInstance(Node root, String xpathVersion,
! VariableManager manager)
throws ParsingException
{
return getInstance(root, FunctionFactory.getConditionInstance(), true,
! xpathVersion, manager);
}
***************
*** 164,175 ****
* functions, or null if this is unspecified (ie, not
* supplied in the defaults section of the policy)
*
* @throws ParsingException if this is not a valid ApplyType
*/
! public static Apply getInstance(Node root, String xpathVersion)
throws ParsingException
{
return getInstance(root, FunctionFactory.getGeneralInstance(), false,
! xpathVersion);
}
--- 167,181 ----
* functions, or null if this is unspecified (ie, not
* supplied in the defaults section of the policy)
+ * @param manager <code>VariableManager</code> used to connect references
+ * and definitions while parsing
*
* @throws ParsingException if this is not a valid ApplyType
*/
! public static Apply getInstance(Node root, String xpathVersion,
! VariableManager manager)
throws ParsingException
{
return getInstance(root, FunctionFactory.getGeneralInstance(), false,
! xpathVersion, manager);
}
***************
*** 180,187 ****
*/
private static Apply getInstance(Node root, FunctionFactory factory,
! boolean isCondition, String xpathVersion)
throws ParsingException
{
! Function function = getFunction(root, xpathVersion, factory);
Function bagFunction = null;
List evals = new ArrayList();
--- 186,195 ----
*/
private static Apply getInstance(Node root, FunctionFactory factory,
! boolean isCondition, String xpathVersion,
! VariableManager manager)
throws ParsingException
{
! Function function = ExpressionHandler.
! getFunction(root, xpathVersion, factory);
Function bagFunction = null;
List evals = new ArrayList();
***************
*** 191,232 ****
NodeList nodes = root.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
! Node node = nodes.item(i);
! String name = node.getNodeName();
! if (name.equals("Apply")) {
! evals.add(Apply.getInstance(node, xpathVersion));
! } else if (name.equals("AttributeValue")) {
! try {
! evals.add(attrFactory.createValue(node));
! } catch (UnknownIdentifierException uie) {
! throw new ParsingException("Unknown DataType", uie);
}
- } else if (name.equals("SubjectAttributeDesignator")) {
- evals.add(AttributeDesignator.
- getInstance(node,
- AttributeDesignator.SUBJECT_TARGET));
- } else if (name.equals("ResourceAttributeDesignator")) {
- evals.add(AttributeDesignator.
- getInstance(node,
- AttributeDesignator.RESOURCE_TARGET));
- } else if (name.equals("ActionAttributeDesignator")) {
- evals.add(AttributeDesignator.
- getInstance(node,
- AttributeDesignator.ACTION_TARGET));
- } else if (name.equals("EnvironmentAttributeDesignator")) {
- evals.add(AttributeDesignator.
- getInstance(node,
- AttributeDesignator.ENVIRONMENT_TARGET));
- } else if (name.equals("AttributeSelector")) {
- evals.add(AttributeSelector.getInstance(node, xpathVersion));
- } else if (name.equals("Function")) {
- // while the schema doesn't enforce this, it's illegal to
- // have more than one FunctionType in a given ApplyType
- if (bagFunction != null)
- throw new ParsingException("Too many FunctionTypes");
-
- bagFunction =
- getFunction(node, xpathVersion,
- FunctionFactory.getGeneralInstance());
}
}
--- 199,223 ----
NodeList nodes = root.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
! Expression xpr = ExpressionHandler.
! parseExpression(nodes.item(i), xpathVersion, manager);
! if (xpr != null) {
! if (! xpr.isEvaluatable()) {
! // see if it's a function...
! if (xpr instanceof Function) {
! // while the schema doesn't enforce this, it's illegal
! // to have more than one FunctionType in a given
! // ApplyType ... FIXME: should I remove this?
! if (bagFunction != null)
! throw new
! ParsingException("Too many FunctionTypes");
!
! bagFunction = (Function)xpr;
! } else {
! evals.add(xpr);
! }
! } else {
! evals.add(xpr);
}
}
}
***************
*** 236,264 ****
/**
! * Helper method that tries to get a function instance
*/
! private static Function getFunction(Node root, String version,
! FunctionFactory factory)
! throws ParsingException
! {
! Node functionNode = root.getAttributes().getNamedItem("FunctionId");
! String functionName = functionNode.getNodeValue();
!
! try {
! // try to get an instance of the given function
! return factory.createFunction(functionName);
! } catch (UnknownIdentifierException uie) {
! throw new ParsingException("Unknown FunctionId in Apply", uie);
! } catch (FunctionTypeException fte) {
! // try creating as an abstract function, using a general factory
! try {
! FunctionFactory ff = FunctionFactory.getGeneralInstance();
! return ff.createAbstractFunction(functionName, root, version);
! } catch (Exception e) {
! // any exception at this point is a failure
! throw new ParsingException("failed to create abstract function"
! + " " + functionName, e);
! }
! }
}
--- 227,236 ----
/**
! * Returns true since this expression is evaluatable.
! *
! * @return true
*/
! public boolean isEvaluatable() {
! return true;
}
***************
*** 396,400 ****
if (bagFunction != null)
! out.println("<Function FunctionId=\"" +
bagFunction.getIdentifier() + "\"/>");
--- 368,372 ----
if (bagFunction != null)
! out.println(indenter.makeString() + "<Function FunctionId=\"" +
bagFunction.getIdentifier() + "\"/>");
Index: Evaluatable.java
===================================================================
RCS file: /cvsroot/sunxacml/sunxacml/com/sun/xacml/cond/Evaluatable.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** Evaluatable.java 14 May 2004 20:43:07 -0000 1.4
--- Evaluatable.java 7 Jan 2005 23:49:32 -0000 1.5
***************
*** 58,62 ****
* @author Seth Proctor
*/
! public interface Evaluatable
{
--- 58,62 ----
* @author Seth Proctor
*/
! public interface Evaluatable extends Expression
{
Index: Function.java
===================================================================
RCS file: /cvsroot/sunxacml/sunxacml/com/sun/xacml/cond/Function.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** Function.java 17 Mar 2004 18:03:38 -0000 1.4
--- Function.java 7 Jan 2005 23:49:32 -0000 1.5
***************
*** 3,7 ****
* @(#)Function.java
*
! * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
--- 3,7 ----
* @(#)Function.java
*
! * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
***************
*** 52,56 ****
* @author Seth Proctor
*/
! public interface Function
{
--- 52,56 ----
* @author Seth Proctor
*/
! public interface Function extends Expression
{
Index: MapFunction.java
===================================================================
RCS file: /cvsroot/sunxacml/sunxacml/com/sun/xacml/cond/MapFunction.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** MapFunction.java 18 Mar 2004 21:13:09 -0000 1.4
--- MapFunction.java 7 Jan 2005 23:49:32 -0000 1.5
***************
*** 3,7 ****
* @(#)MapFunction.java 1.4 01/30/03
*
! * Copyright 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
--- 3,7 ----
* @(#)MapFunction.java 1.4 01/30/03
*
! * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
***************
*** 100,103 ****
--- 100,112 ----
/**
+ * Returns false since functions aren't directly evaluatable.
+ *
+ * @return false
+ */
+ public boolean isEvaluatable() {
+ return false;
+ }
+
+ /**
* Returns a <code>Set</code> containing all the function identifiers
* supported by this class.
***************
*** 178,181 ****
--- 187,200 ----
/**
+ * Returns the same value as <code>getReturnType</code>. This is here
+ * to support the <code>Expression</code> interface.
+ *
+ * @return the return type
+ */
+ public URI getType() {
+ return getReturnType();
+ }
+
+ /**
* Returns the attribute type returned by this function.
*
***************
*** 217,221 ****
// get the inputs, which we expect to be correct
Iterator iterator = inputs.iterator();
! Function function = (Function)(iterator.next());
BagAttribute bag = (BagAttribute)(iterator.next());
--- 236,249 ----
// get the inputs, which we expect to be correct
Iterator iterator = inputs.iterator();
! Function function = null;
!
! Expression xpr = (Expression)(iterator.next());
! if (xpr instanceof Function) {
! function = (Function)xpr;
! } else {
! function = (Function)(((VariableReference)xpr).
! getReferencedDefinition().getExpression());
! }
!
BagAttribute bag = (BagAttribute)(iterator.next());
***************
*** 258,262 ****
// now check that we've got the right types for map
! if (! (list[0] instanceof Function))
throw new IllegalArgumentException("first argument to map must " +
"be a Function");
--- 286,301 ----
// now check that we've got the right types for map
! Function function = null;
!
! if (list[0] instanceof Function) {
! function = (Function)(list[0]);
! } else if (list[0] instanceof VariableReference) {
! Expression xpr = ((VariableReference)(list[0])).
! getReferencedDefinition().getExpression();
! if (xpr instanceof Function)
! function = (Function)xpr;
! }
!
! if (function == null)
throw new IllegalArgumentException("first argument to map must " +
"be a Function");
***************
*** 269,273 ****
List input = new ArrayList();
input.add(list[1]);
! ((Function)(list[0])).checkInputsNoBag(input);
}
--- 308,312 ----
List input = new ArrayList();
input.add(list[1]);
! function.checkInputsNoBag(input);
}
--- NEW FILE: ExpressionHandler.java ---
/*
* ExpressionHandler.java
*
* Created by: seth proctor (stp)
* Created on: Wed Dec 29, 2004 8:24:30 PM
* Desc:
*
*/
package com.sun.xacml.cond;
import com.sun.xacml.ParsingException;
import com.sun.xacml.UnknownIdentifierException;
import com.sun.xacml.attr.AttributeDesignator;
import com.sun.xacml.attr.AttributeFactory;
import com.sun.xacml.attr.AttributeSelector;
import org.w3c.dom.Node;
/**
* This is a package-private utility class that handles parsing all the
* possible expression types. It was added becuase in 2.0 multiple classes
* needed this. Note that this could also be added to Expression and
* that interface could be made an abstract class, but that would require
* substantial change.
*
* @since 2.0
* @author Seth Proctor
*/
class ExpressionHandler
{
/**
* Parses an expression, recursively handling any sub-elements. This is
* provided as a utility class, but in practice is used only by
* <code>Apply</code> and <code>VariableDefinition</code>.
*
*/
public static Expression parseExpression(Node root, String xpathVersion,
VariableManager manager)
throws ParsingException
{
String name = root.getNodeName();
if (name.equals("Apply")) {
return Apply.getInstance(root, xpathVersion, manager);
} else if (name.equals("AttributeValue")) {
try {
return AttributeFactory.getInstance().createValue(root);
} catch (UnknownIdentifierException uie) {
throw new ParsingException("Unknown DataType", uie);
}
} else if (name.equals("SubjectAttributeDesignator")) {
return AttributeDesignator.
getInstance(root, AttributeDesignator.SUBJECT_TARGET);
} else if (name.equals("ResourceAttributeDesignator")) {
return AttributeDesignator.
getInstance(root, AttributeDesignator.RESOURCE_TARGET);
} else if (name.equals("ActionAttributeDesignator")) {
return AttributeDesignator.
getInstance(root, AttributeDesignator.ACTION_TARGET);
} else if (name.equals("EnvironmentAttributeDesignator")) {
return AttributeDesignator.
getInstance(root, AttributeDesignator.ENVIRONMENT_TARGET);
} else if (name.equals("AttributeSelector")) {
return AttributeSelector.getInstance(root, xpathVersion);
} else if (name.equals("Function")) {
return getFunction(root, xpathVersion,
FunctionFactory.getGeneralInstance());
} else if (name.equals("VariableReference")) {
return VariableReference.getInstance(root, manager);
}
// return null if it was none of these
return null;
}
/**
* Helper method that tries to get a function instance
*/
public static Function getFunction(Node root, String version,
FunctionFactory factory)
throws ParsingException
{
Node functionNode = root.getAttributes().getNamedItem("FunctionId");
String functionName = functionNode.getNodeValue();
try {
// try to get an instance of the given function
return factory.createFunction(functionName);
} catch (UnknownIdentifierException uie) {
throw new ParsingException("Unknown FunctionId", uie);
} catch (FunctionTypeException fte) {
// try creating as an abstract function
try {
FunctionFactory ff = FunctionFactory.getGeneralInstance();
return ff.createAbstractFunction(functionName, root, version);
} catch (Exception e) {
// any exception at this point is a failure
throw new ParsingException("failed to create abstract function"
+ " " + functionName, e);
}
}
}
}
|