Source code: com/sun/xacml/cond/MapFunction.java
1
2 /*
3 * @(#)MapFunction.java 1.4 01/30/03
4 *
5 * Copyright 2003 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.ParsingException;
41
42 import com.sun.xacml.attr.AttributeValue;
43 import com.sun.xacml.attr.BagAttribute;
44
45 import com.sun.xacml.ctx.Status;
46
47 import java.net.URI;
48
49 import java.util.ArrayList;
50 import java.util.HashSet;
51 import java.util.Iterator;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.Set;
55
56 import org.w3c.dom.Node;
57 import org.w3c.dom.NodeList;
58
59
60 /**
61 * Represents the higher order bag function map.
62 *
63 * @since 1.0
64 * @author Seth Proctor
65 */
66 class MapFunction implements Function
67 {
68
69 /**
70 * The name of this function
71 */
72 public static final String NAME_MAP = FunctionBase.FUNCTION_NS + "map";
73
74 // the return type for this instance
75 private URI returnType;
76
77 // the stuff used to make sure that we have a valid identifier or a
78 // known error, just like in the attribute classes
79 private static URI identifier;
80 private static RuntimeException earlyException;
81
82 // try to initialize the identifier
83 static {
84 try {
85 identifier = new URI(NAME_MAP);
86 } catch (Exception e) {
87 earlyException = new IllegalArgumentException();
88 earlyException.initCause(e);
89 }
90 };
91
92 /**
93 * Creates a new instance of a <code>MapFunction</code>.
94 *
95 * @param returnType the type returned by this function
96 */
97 public MapFunction(URI returnType) {
98 this.returnType = returnType;
99 }
100
101 /**
102 * Returns a <code>Set</code> containing all the function identifiers
103 * supported by this class.
104 *
105 * @return a <code>Set</code> of <code>String</code>s
106 */
107 public static Set getSupportedIdentifiers() {
108 Set set = new HashSet();
109
110 set.add(NAME_MAP);
111
112 return set;
113 }
114
115 /**
116 * Creates a new instance of the map function using the data found in
117 * the DOM node provided. This is called by a proxy when the factory
118 * is asked to create one of these functions.
119 *
120 * @param root the DOM node of the apply tag containing this function
121 *
122 * @return a <code>MapFunction</code> instance
123 *
124 * @throws ParsingException if the DOM data was incorrect
125 */
126 public static MapFunction getInstance(Node root) throws ParsingException {
127 URI returnType = null;
128
129 NodeList nodes = root.getChildNodes();
130 for (int i = 0; i < nodes.getLength(); i++) {
131 Node node = nodes.item(i);
132
133 if (node.getNodeName().equals("Function")) {
134 String funcName = node.getAttributes().
135 getNamedItem("FunctionId").getNodeValue();
136 FunctionFactory factory = FunctionFactory.getGeneralInstance();
137 try {
138 Function function = factory.createFunction(funcName);
139 returnType = function.getReturnType();
140 break;
141 } catch (FunctionTypeException fte) {
142 // try to get this as an abstract function
143 try {
144 Function function = factory.
145 createAbstractFunction(funcName, root);
146 returnType = function.getReturnType();
147 break;
148 } catch (Exception e) {
149 // any exception here is an error
150 throw new ParsingException("invalid abstract map", e);
151 }
152 } catch (Exception e) {
153 // any exception that's not function type is an error
154 throw new ParsingException("couldn't parse map body", e);
155 }
156 }
157 }
158
159 // see if we found the return type
160 if (returnType == null)
161 throw new ParsingException("couldn't find the return type");
162
163 return new MapFunction(returnType);
164 }
165
166 /**
167 * Returns the full identifier of this function, as known by the factories.
168 *
169 * @return the function's identifier
170 */
171 public URI getIdentifier() {
172 // strictly speaking, this should never happen
173 if (earlyException != null)
174 throw earlyException;
175
176 return identifier;
177 }
178
179 /**
180 * Returns the attribute type returned by this function.
181 *
182 * @return the return type
183 */
184 public URI getReturnType() {
185 return returnType;
186 }
187
188 /**
189 * Returns <code>true</code>, since the map function always returns a bag
190 *
191 * @return true
192 */
193 public boolean returnsBag() {
194 return true;
195 }
196
197 /**
198 * Helper function to create a processing error message.
199 */
200 private static EvaluationResult makeProcessingError(String message) {
201 ArrayList code = new ArrayList();
202 code.add(Status.STATUS_PROCESSING_ERROR);
203 return new EvaluationResult(new Status(code, message));
204 }
205
206 /**
207 * Evaluates the function given the input data. Map expects a
208 * <code>Function</code> followed by a <code>BagAttribute</code>.
209 *
210 * @param inputs the input agrument list
211 * @param context the representation of the request
212 *
213 * @return the result of evaluation
214 */
215 public EvaluationResult evaluate(List inputs, EvaluationCtx context) {
216
217 // get the inputs, which we expect to be correct
218 Iterator iterator = inputs.iterator();
219 Function function = (Function)(iterator.next());
220 BagAttribute bag = (BagAttribute)(iterator.next());
221
222 // param: function, bag
223 // return: bag
224 // for each value in the bag evaluate the given function with
225 // the value and put the function result in a new bag that
226 // is ultimately returned
227
228 Iterator it = bag.iterator();
229 List outputs = new ArrayList();
230
231 while (it.hasNext()) {
232 List params = new ArrayList();
233 params.add(it.next());
234 EvaluationResult result = function.evaluate(params, context);
235
236 if (result.indeterminate())
237 return result;
238
239 outputs.add(result.getAttributeValue());
240 }
241
242 return new EvaluationResult(new BagAttribute(returnType, outputs));
243 }
244
245 /**
246 * Checks that the input list is valid for evaluation.
247 *
248 * @param inputs a <code>List</code> of inputs
249 *
250 * @throws IllegalArgumentException if the inputs cannot be evaluated
251 */
252 public void checkInputs(List inputs) throws IllegalArgumentException {
253 Object [] list = inputs.toArray();
254
255 // check that we've got the right number of arguments
256 if (list.length != 2)
257 throw new IllegalArgumentException("map requires two inputs");
258
259 // now check that we've got the right types for map
260 if (! (list[0] instanceof Function))
261 throw new IllegalArgumentException("first argument to map must " +
262 "be a Function");
263 Evaluatable eval = (Evaluatable)(list[1]);
264 if (! eval.evaluatesToBag())
265 throw new IllegalArgumentException("second argument to map must " +
266 "be a bag");
267
268 // finally, check that the type in the bag is right for the function
269 List input = new ArrayList();
270 input.add(list[1]);
271 ((Function)(list[0])).checkInputsNoBag(input);
272 }
273
274 /**
275 * Always throws <code>IllegalArgumentException</code> since map needs
276 * to work on a bag
277 *
278 * @param inputs a <code>List</code> of inputs
279 *
280 * @throws IllegalArgumentException always
281 */
282 public void checkInputsNoBag(List inputs) throws IllegalArgumentException {
283 throw new IllegalArgumentException("map requires a bag");
284 }
285
286 }