Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/sun/xacml/cond/Apply.java


1   
2   /*
3    * @(#)Apply.java
4    *
5    * Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions are met:
9    *
10   *   1. Redistribution of source code must retain the above copyright notice,
11   *      this list of conditions and the following disclaimer.
12   * 
13   *   2. Redistribution in binary form must reproduce the above copyright
14   *      notice, this list of conditions and the following disclaimer in the
15   *      documentation and/or other materials provided with the distribution.
16   *
17   * Neither the name of Sun Microsystems, Inc. or the names of contributors may
18   * be used to endorse or promote products derived from this software without
19   * specific prior written permission.
20   * 
21   * This software is provided "AS IS," without a warranty of any kind. ALL
22   * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
23   * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
24   * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
25   * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
26   * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
27   * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
28   * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
29   * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
30   * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
31   * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
32   *
33   * You acknowledge that this software is not designed or intended for use in
34   * the design, construction, operation or maintenance of any nuclear facility.
35   */
36  
37  package com.sun.xacml.cond;
38  
39  import com.sun.xacml.EvaluationCtx;
40  import com.sun.xacml.Indenter;
41  import com.sun.xacml.ParsingException;
42  import com.sun.xacml.UnknownIdentifierException;
43  
44  import com.sun.xacml.attr.AttributeDesignator;
45  import com.sun.xacml.attr.AttributeFactory;
46  import com.sun.xacml.attr.AttributeSelector;
47  import com.sun.xacml.attr.AttributeValue;
48  
49  import java.io.OutputStream;
50  import java.io.PrintStream;
51  
52  import java.net.URI;
53  
54  import java.util.ArrayList;
55  import java.util.Collections;
56  import java.util.Iterator;
57  import java.util.List;
58  
59  import org.w3c.dom.Node;
60  import org.w3c.dom.NodeList;
61  
62  
63  /**
64   * Represents the XACML ApplyType and ConditionType XML types.
65   *
66   * @since 1.0
67   * @author Seth Proctor
68   */
69  public class Apply implements Evaluatable
70  {
71  
72      // the function used to evaluate the contents of the apply
73      private Function function;
74  
75      // the paramaters to the function...ie, the contents of the apply
76      private List evals;
77  
78      // an apply may have an entry that's a function for bag operations
79      private Function bagFunction;
80  
81      // whether or not this is a condition
82      private boolean isCondition;
83  
84      /**
85       * Constructs an <code>Apply</code> object. Throws an
86       * <code>IllegalArgumentException</code> if the given parameter list
87       * isn't valid for the given function.
88       *
89       * @param function the <code>Function</code> to use in evaluating the
90       *                 elements in the apply
91       * @param evals the contents of the apply which will be the parameters
92       *              to the function, each of which is an
93       *              <code>Evaluatable</code>
94       * @param isCondition true if this <code>Apply</code> is a Condition,
95       *                    false otherwise
96       */
97      public Apply(Function function, List evals, boolean isCondition)
98          throws IllegalArgumentException
99      {
100         this(function, evals, null, isCondition);
101     }
102 
103     /**
104      * Constructs an <code>Apply</code> object that contains a higher-order
105      * bag function. Throws an <code>IllegalArgumentException</code> if the
106      * given parameter list isn't valid for the given function.
107      * 
108      * @param function the <code>Function</code> to use in evaluating the
109      *                 elements in the apply
110      * @param evals the contents of the apply which will be the parameters
111      *              to the function, each of which is an
112      *              <code>Evaluatable</code>
113      * @param bagFunction the higher-order function to use
114      * @param isCondition true if this <code>Apply</code> is a Condition,
115      *                    false otherwise
116      */
117     public Apply(Function function, List evals, Function bagFunction,
118                  boolean isCondition)
119         throws IllegalArgumentException
120     {
121         // check that the given inputs work for the function
122         List inputs = evals;
123         if (bagFunction != null) {
124             inputs = new ArrayList();
125             inputs.add(bagFunction);
126             inputs.addAll(evals);
127         }
128         function.checkInputs(inputs);
129 
130         // if everything checks out, then store the inputs
131         this.function = function;
132         this.evals = Collections.unmodifiableList(new ArrayList(evals));
133         this.bagFunction = bagFunction;
134         this.isCondition = isCondition;
135     }
136     
137     /**
138      * Returns an instance of an <code>Apply</code> based on the given DOM
139      * root node. This will actually return a special kind of
140      * <code>Apply</code>, namely an XML ConditionType, which is the root
141      * of the condition logic in a RuleType. A ConditionType is the same
142      * as an ApplyType except that it must use a FunctionId that returns
143      * a boolean value.
144      * 
145      * @param root the DOM root of a ConditionType XML type
146      * @param xpathVersion the XPath version to use in any selectors or XPath
147      *                     functions, or null if this is unspecified (ie, not
148      *                     supplied in the defaults section of the policy)
149      *
150      * @throws ParsingException if this is not a valid ConditionType
151      */
152     public static Apply getConditionInstance(Node root, String xpathVersion)
153         throws ParsingException
154     {
155         return getInstance(root, FunctionFactory.getConditionInstance(), true,
156                            xpathVersion);
157     }
158 
159     /**
160      * Returns an instance of <code>Apply</code> based on the given DOM root.
161      * 
162      * @param root the DOM root of an ApplyType XML type
163      * @param xpathVersion the XPath version to use in any selectors or XPath
164      *                     functions, or null if this is unspecified (ie, not
165      *                     supplied in the defaults section of the policy)
166      *
167      * @throws ParsingException if this is not a valid ApplyType
168      */
169     public static Apply getInstance(Node root, String xpathVersion)
170         throws ParsingException
171     {
172         return getInstance(root, FunctionFactory.getGeneralInstance(), false,
173                            xpathVersion);
174     }
175 
176     /**
177      * This is a helper method that is called by the two getInstance
178      * methods. It takes a factory so we know that we're getting the right
179      * kind of function.
180      */
181     private static Apply getInstance(Node root, FunctionFactory factory,
182                                      boolean isCondition, String xpathVersion)
183         throws ParsingException
184     {
185         Function function = getFunction(root, xpathVersion, factory);
186         Function bagFunction = null;
187         List evals = new ArrayList();
188         
189         AttributeFactory attrFactory = AttributeFactory.getInstance();
190 
191         NodeList nodes = root.getChildNodes();
192         for (int i = 0; i < nodes.getLength(); i++) {
193             Node node = nodes.item(i);
194             String name = node.getNodeName();
195 
196             if (name.equals("Apply")) {
197                 evals.add(Apply.getInstance(node, xpathVersion));
198             } else if (name.equals("AttributeValue")) {
199                 try {
200                     evals.add(attrFactory.createValue(node));
201                 } catch (UnknownIdentifierException uie) {
202                     throw new ParsingException("Unknown DataType", uie);
203                 }
204             } else if (name.equals("SubjectAttributeDesignator")) {
205                 evals.add(AttributeDesignator.
206                           getInstance(node,
207                                       AttributeDesignator.SUBJECT_TARGET));
208             } else if (name.equals("ResourceAttributeDesignator")) {
209                 evals.add(AttributeDesignator.
210                           getInstance(node,
211                                       AttributeDesignator.RESOURCE_TARGET));
212             } else if (name.equals("ActionAttributeDesignator")) {
213                 evals.add(AttributeDesignator.
214                           getInstance(node,
215                                       AttributeDesignator.ACTION_TARGET));
216             } else if (name.equals("EnvironmentAttributeDesignator")) {
217                 evals.add(AttributeDesignator.
218                           getInstance(node,
219                                       AttributeDesignator.ENVIRONMENT_TARGET));
220             } else if (name.equals("AttributeSelector")) {
221                 evals.add(AttributeSelector.getInstance(node, xpathVersion));
222             } else if (name.equals("Function")) {
223                 // while the schema doesn't enforce this, it's illegal to
224                 // have more than one FunctionType in a given ApplyType
225                 if (bagFunction != null)
226                     throw new ParsingException("Too many FunctionTypes");
227 
228                 bagFunction =
229                     getFunction(node, xpathVersion,
230                                 FunctionFactory.getGeneralInstance());
231             }
232         }
233 
234         return new Apply(function, evals, bagFunction, isCondition);
235     }
236 
237     /**
238      * Helper method that tries to get a function instance
239      */
240     private static Function getFunction(Node root, String version,
241                                         FunctionFactory factory)
242         throws ParsingException
243     {
244         Node functionNode = root.getAttributes().getNamedItem("FunctionId");
245         String functionName = functionNode.getNodeValue();
246 
247         try {
248             // try to get an instance of the given function
249             return factory.createFunction(functionName);
250         } catch (UnknownIdentifierException uie) {
251             throw new ParsingException("Unknown FunctionId in Apply", uie);
252         } catch (FunctionTypeException fte) {
253             // try creating as an abstract function, using a general factory
254             try {
255                 FunctionFactory ff = FunctionFactory.getGeneralInstance();
256                 return ff.createAbstractFunction(functionName, root, version);
257             } catch (Exception e) {
258                 // any exception at this point is a failure
259                 throw new ParsingException("failed to create abstract function"
260                                            + " " + functionName, e);
261             }
262         }
263     }
264 
265     /**
266      * Returns the <code>Function</code> used by this <code>Apply</code>.
267      *
268      * @return the <code>Function</code>
269      */
270     public Function getFunction() {
271         return function;
272     }
273 
274     /**
275      * Returns the <code>List</code> of children for this <code>Apply</code>.
276      * The <code>List</code> contains <code>Evaluatable</code>s. The list is
277      * unmodifiable, and may be empty.
278      *
279      * @return a <code>List</code> of <code>Evaluatable</code>s
280      */
281     public List getChildren() {
282         return evals;
283     }
284 
285     /**
286      * Returns the higher order bag function used by this <code>Apply</code>
287      * if it exists, or null if no higher order function is used.
288      *
289      * @return the higher order <code>Function</code> or null
290      */
291     public Function getHigherOrderFunction() {
292         return bagFunction;
293     }
294 
295     /**
296      * Returns whether or not this ApplyType is actually a ConditionType.
297      *
298      * @return whether or not this represents a ConditionType
299      */
300     public boolean isCondition() {
301         return isCondition;
302     }
303 
304     /**
305      * Evaluates the apply object using the given function. This will in
306      * turn call evaluate on all the given parameters, some of which may be
307      * other <code>Apply</code> objects.
308      *
309      * @param context the representation of the request
310      *
311      * @return the result of trying to evaluate this apply object
312      */
313     public EvaluationResult evaluate(EvaluationCtx context) {
314         List parameters = evals;
315 
316         // see if there is a higher-order function in here
317         if (bagFunction != null) {
318             // this is a special case, so we setup the parameters, starting
319             // with the function
320             parameters = new ArrayList();
321             parameters.add(bagFunction);
322 
323             // now we evaluate all the parameters, returning INDETERMINATE
324             // if that's what any of them return, and otherwise tracking
325             // all the AttributeValues that get returned
326             Iterator it = evals.iterator();
327             while (it.hasNext()) {
328                 Evaluatable eval = (Evaluatable)(it.next());
329                 EvaluationResult result = eval.evaluate(context);
330                 
331                 // in a higher-order case, if anything is INDETERMINATE, then
332                 // we stop right away
333                 if (result.indeterminate())
334                     return result;
335 
336                 parameters.add(result.getAttributeValue());
337             }
338         }
339 
340         // now we can call the base function
341         return function.evaluate(parameters, context);
342     }
343 
344     /**
345      * Returns the type of attribute that this object will return on a call
346      * to <code>evaluate</code>. In practice, this will always be the same as
347      * the result of calling <code>getReturnType</code> on the function used
348      * by this object.
349      *
350      * @return the type returned by <code>evaluate</code>
351      */
352     public URI getType() {
353         return function.getReturnType();
354     }
355 
356     /**
357      * Returns whether or not the <code>Function</code> will return a bag
358      * of values on evaluation.
359      *
360      * @return true if evaluation will return a bag of values, false otherwise
361      */
362     public boolean evaluatesToBag() {
363         return function.returnsBag();
364     }
365 
366     /**
367      * Encodes this <code>Apply</code> into its XML representation and
368      * writes this encoding to the given <code>OutputStream</code> with no
369      * indentation.
370      *
371      * @param output a stream into which the XML-encoded data is written
372      */
373     public void encode(OutputStream output) {
374         encode(output, new Indenter(0));
375     }
376 
377     /**
378      * Encodes this <code>Apply</code> into its XML representation and
379      * writes this encoding to the given <code>OutputStream</code> with
380      * indentation.
381      *
382      * @param output a stream into which the XML-encoded data is written
383      * @param indenter an object that creates indentation strings
384      */
385     public void encode(OutputStream output, Indenter indenter) {
386         PrintStream out = new PrintStream(output);
387         String indent = indenter.makeString();
388 
389         if (isCondition)
390             out.println(indent + "<Condition FunctionId=\"" +
391                         function.getIdentifier() + "\">");
392         else
393             out.println(indent + "<Apply FunctionId=\"" +
394                         function.getIdentifier() + "\">");
395         indenter.in();
396 
397         if (bagFunction != null)
398             out.println("<Function FunctionId=\"" +
399                         bagFunction.getIdentifier() + "\"/>");
400 
401         Iterator it = evals.iterator();
402         while (it.hasNext()) {
403             Evaluatable eval = (Evaluatable)(it.next());
404             eval.encode(output, indenter);
405         }
406 
407         indenter.out();
408         if (isCondition)
409             out.println(indent + "</Condition>");
410         else
411             out.println(indent + "</Apply>");
412     }
413 
414 }