Source code: com/sun/xacml/cond/FunctionBase.java
1
2 /*
3 * @(#)FunctionBase.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
41 import com.sun.xacml.attr.AttributeValue;
42
43 import com.sun.xacml.ctx.Status;
44
45 import java.net.URI;
46 import java.net.URISyntaxException;
47
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.Collection;
51 import java.util.Collections;
52 import java.util.HashMap;
53 import java.util.HashSet;
54 import java.util.Iterator;
55 import java.util.List;
56 import java.util.Map;
57
58
59 /**
60 * An abstract utility superclass for functions. Supplies several useful
61 * methods, making it easier to implement a <code>Function</code>. You can
62 * extend this class or implement <code>Function</code> directly, depending
63 * on your needs.
64 *
65 * @since 1.0
66 * @author Steve Hanna
67 * @author Seth Proctor
68 */
69 public abstract class FunctionBase implements Function
70 {
71
72 /**
73 * The standard namespace where all the spec-defined functions live
74 */
75 public static final String FUNCTION_NS =
76 "urn:oasis:names:tc:xacml:1.0:function:";
77
78 // A List used by makeProcessingError() to save some steps.
79 private static List processingErrList = null;
80
81 // the name of this function
82 private String functionName;
83
84 // the id used by this function
85 private int functionId;
86
87 // the return type of this function, and whether it's a bag
88 private String returnType;
89 private boolean returnsBag;
90
91 // flag that tells us which of the two constructors was used
92 private boolean singleType;
93
94 // parameter data if we're only using a single type
95 private String paramType;
96 private boolean paramIsBag;
97 private int numParams;
98 private int minParams;
99
100 // paramater data if we're using different types
101 private String [] paramTypes;
102 private boolean [] paramsAreBags;
103
104 /**
105 * Constructor that sets up the function as having some number of
106 * parameters all of the same given type. If <code>numParams</code> is
107 * -1, then the length is variable
108 *
109 * @param functionName the name of this function as used by the factory
110 * and any XACML policies
111 * @param functionId an optional identifier that can be used by your
112 * code for convenience
113 * @param paramType the type of all parameters to this function, as used
114 * by the factory and any XACML documents
115 * @param paramIsBag whether or not every parameter is actually a bag
116 * of values
117 * @param numParams the number of parameters required by this function,
118 * or -1 if any number are allowed
119 * @param returnType the type returned by this function, as used by
120 * the factory and any XACML documents
121 * @param returnsBag whether or not this function returns a bag of values
122 */
123 public FunctionBase(String functionName, int functionId, String paramType,
124 boolean paramIsBag, int numParams,
125 String returnType, boolean returnsBag) {
126 this(functionName, functionId, returnType, returnsBag);
127
128 singleType = true;
129
130 this.paramType = paramType;
131 this.paramIsBag = paramIsBag;
132 this.numParams = numParams;
133 this.minParams = 0;
134 }
135
136 /**
137 * Constructor that sets up the function as having some number of
138 * parameters all of the same given type. If <code>numParams</code> is
139 * -1, then the length is variable, and then <code>minParams</code> may
140 * be used to specify a minimum number of parameters. If
141 * <code>numParams</code> is not -1, then <code>minParams</code> is
142 * ignored.
143 *
144 * @param functionName the name of this function as used by the factory
145 * and any XACML policies
146 * @param functionId an optional identifier that can be used by your
147 * code for convenience
148 * @param paramType the type of all parameters to this function, as used
149 * by the factory and any XACML documents
150 * @param paramIsBag whether or not every parameter is actually a bag
151 * of values
152 * @param numParams the number of parameters required by this function,
153 * or -1 if any number are allowed
154 * @param minParams the minimum number of parameters required if
155 * <code>numParams</code> is -1
156 * @param returnType the type returned by this function, as used by
157 * the factory and any XACML documents
158 * @param returnsBag whether or not this function returns a bag of values
159 */
160 public FunctionBase(String functionName, int functionId, String paramType,
161 boolean paramIsBag, int numParams, int minParams,
162 String returnType, boolean returnsBag) {
163 this(functionName, functionId, returnType, returnsBag);
164
165 singleType = true;
166
167 this.paramType = paramType;
168 this.paramIsBag = paramIsBag;
169 this.numParams = numParams;
170 this.minParams = minParams;
171 }
172
173
174 /**
175 * Constructor that sets up the function as having different types for
176 * each given parameter.
177 *
178 * @param functionName the name of this function as used by the factory
179 * and any XACML policies
180 * @param functionId an optional identifier that can be used by your
181 * code for convenience
182 * @param paramTypes the type of each parameter, in order, required by
183 * this function, as used by the factory and any XACML
184 * documents
185 * @param paramIsBag whether or not each parameter is actually a bag
186 * of values
187 * @param returnType the type returned by this function, as used by
188 * the factory and any XACML documents
189 * @param returnsBag whether or not this function returns a bag of values
190 */
191 public FunctionBase(String functionName, int functionId,
192 String [] paramTypes, boolean [] paramIsBag,
193 String returnType, boolean returnsBag) {
194 this(functionName, functionId, returnType, returnsBag);
195
196 singleType = false;
197
198 this.paramTypes = paramTypes;
199 this.paramsAreBags = paramIsBag;
200 }
201
202 /**
203 * Constructor that sets up some basic values for functions that will
204 * take care of parameter checking on their own. If you use this
205 * constructor for your function class, then you must override the
206 * two check methods to make sure that parameters are correct.
207 *
208 * @param functionName the name of this function as used by the factory
209 * and any XACML policies
210 * @param functionId an optional identifier that can be used by your
211 * code for convenience
212 * @param returnType the type returned by this function, as used by
213 * the factory and any XACML documents
214 * @param returnsBag whether or not this function returns a bag of values
215 */
216 public FunctionBase(String functionName, int functionId,
217 String returnType, boolean returnsBag) {
218 this.functionName = functionName;
219 this.functionId = functionId;
220 this.returnType = returnType;
221 this.returnsBag = returnsBag;
222 }
223
224 /**
225 * Returns the full identifier of this function, as known by the factories.
226 *
227 * @return the function's identifier
228 *
229 * @throws IllegalArgumentException if the identifier isn't a valid URI
230 */
231 public URI getIdentifier() {
232 // this is to get around the exception handling problems, but may
233 // change if this code changes to include exceptions from the
234 // constructors
235 try {
236 return new URI(functionName);
237 } catch (URISyntaxException use) {
238 throw new IllegalArgumentException("invalid URI");
239 }
240 }
241
242 /**
243 * Returns the name of the function to be handled by this particular
244 * object.
245 *
246 * @return the function name
247 */
248 public String getFunctionName() {
249 return functionName;
250 }
251
252 /**
253 * Returns the Identifier of the function to be handled by this
254 * particular object.
255 *
256 * @return the function Id
257 */
258 public int getFunctionId() {
259 return functionId;
260 }
261
262 /**
263 * Get the attribute type returned by this function.
264 *
265 * @return a <code>URI</code> indicating the attribute type
266 * returned by this function
267 */
268 public URI getReturnType() {
269 try {
270 return new URI(returnType);
271 } catch (Exception e) {
272 return null;
273 }
274 }
275
276 /**
277 * Returns true if this function returns a bag of values.
278 *
279 * @return true if the function returns a bag, false otherwise
280 */
281 public boolean returnsBag() {
282 return returnsBag;
283 }
284
285 /**
286 * Returns the return type for this particular object.
287 *
288 * @return the return type
289 */
290 public String getReturnTypeAsString() {
291 return returnType;
292 }
293
294 /**
295 * Create an <code>EvaluationResult</code> that indicates a
296 * processing error with the specified message. This method
297 * may be useful to subclasses.
298 *
299 * @param message a description of the error
300 * (<code>null</code> if none)
301 * @return the desired <code>EvaluationResult</code>
302 */
303 protected static EvaluationResult makeProcessingError(String message) {
304 // Build up the processing error Status.
305 if (processingErrList == null) {
306 String [] errStrings = { Status.STATUS_PROCESSING_ERROR };
307 processingErrList = Arrays.asList(errStrings);
308 }
309 Status errStatus = new Status(processingErrList, message);
310 EvaluationResult processingError = new EvaluationResult(errStatus);
311
312 return processingError;
313 }
314
315 /**
316 * Evaluates each of the parameters, in order, filling in the argument
317 * array with the resulting values. If any error occurs, this method
318 * returns the error, otherwise null is returned, signalling that
319 * evaluation was successful for all inputs, and the resulting argument
320 * list can be used.
321 *
322 * @param params a <code>List</code> of <code>Evaluatable</code>
323 * objects representing the parameters to evaluate
324 * @param context the representation of the request
325 * @param args an array as long as the params <code>List</code> that
326 * will, on return, contain the <code>AttributeValue</code>s
327 * generated from evaluating all parameters
328 *
329 * @return <code>null</code> if no errors were encountered, otherwise
330 * an <code>EvaluationResult</code> representing the error
331 */
332 protected EvaluationResult evalArgs(List params, EvaluationCtx context,
333 AttributeValue [] args) {
334 Iterator it = params.iterator();
335 int index = 0;
336
337 while (it.hasNext()) {
338 // get and evaluate the next parameter
339 Evaluatable eval = (Evaluatable)(it.next());
340 EvaluationResult result = eval.evaluate(context);
341
342 // If there was an error, pass it back...
343 if (result.indeterminate())
344 return result;
345
346 // ...otherwise save it and keep going
347 args[index++] = result.getAttributeValue();
348 }
349
350 // if no error occurred then we got here, so we return no errors
351 return null;
352 }
353
354 /**
355 * Default handling of input checking. This does some simple checking
356 * based on the type of constructor used. If you need anything more
357 * complex, or if you used the simple constructor, then you must
358 * override this method.
359 *
360 * @param inputs a <code>List></code> of <code>Evaluatable</code>s
361 *
362 * @throws IllegalArgumentException if the inputs won't work
363 */
364 public void checkInputs(List inputs) throws IllegalArgumentException {
365 // first off, see what kind of function we are
366 if (singleType) {
367 // first, check the length of the inputs, if appropriate
368 if (numParams != -1) {
369 if (inputs.size() != numParams)
370 throw new IllegalArgumentException("wrong number of args" +
371 " to " + functionName);
372 } else {
373 if (inputs.size() < minParams)
374 throw new IllegalArgumentException("not enough args" +
375 " to " + functionName);
376 }
377
378 // now, make sure everything is of the same, correct type
379 Iterator it = inputs.iterator();
380 while (it.hasNext()) {
381 Evaluatable eval = (Evaluatable)(it.next());
382
383 if ((! eval.getType().toString().equals(paramType)) ||
384 (eval.evaluatesToBag() != paramIsBag))
385 throw new IllegalArgumentException("illegal parameter");
386 }
387 } else {
388 // first, check the length of the inputs
389 if (paramTypes.length != inputs.size())
390 throw new IllegalArgumentException("wrong number of args" +
391 " to " + functionName);
392
393 // now, make sure everything is of the same, correct type
394 Iterator it = inputs.iterator();
395 int i = 0;
396 while (it.hasNext()) {
397 Evaluatable eval = (Evaluatable)(it.next());
398
399 if ((! eval.getType().toString().equals(paramTypes[i])) ||
400 (eval.evaluatesToBag() != paramsAreBags[i]))
401 throw new IllegalArgumentException("illegal parameter");
402
403 i++;
404 }
405 }
406 }
407
408 /**
409 * Default handling of input checking. This does some simple checking
410 * based on the type of constructor used. If you need anything more
411 * complex, or if you used the simple constructor, then you must
412 * override this method.
413 *
414 * @param inputs a <code>List></code> of <code>Evaluatable</code>s
415 *
416 * @throws IllegalArgumentException if the inputs won't work
417 */
418 public void checkInputsNoBag(List inputs) throws IllegalArgumentException {
419 // first off, see what kind of function we are
420 if (singleType) {
421 // first check to see if we need bags
422 if (paramIsBag)
423 throw new IllegalArgumentException(functionName + "needs" +
424 "bags on input");
425
426 // now check on the length
427 if (numParams != -1) {
428 if (inputs.size() != numParams)
429 throw new IllegalArgumentException("wrong number of args" +
430 " to " + functionName);
431 } else {
432 if (inputs.size() < minParams)
433 throw new IllegalArgumentException("not enough args" +
434 " to " + functionName);
435 }
436
437 // finally check param list
438 Iterator it = inputs.iterator();
439 while (it.hasNext()) {
440 Evaluatable eval = (Evaluatable)(it.next());
441
442 if (! eval.getType().toString().equals(paramType))
443 throw new IllegalArgumentException("illegal parameter");
444 }
445 } else {
446 // first, check the length of the inputs
447 if (paramTypes.length != inputs.size())
448 throw new IllegalArgumentException("wrong number of args" +
449 " to " + functionName);
450
451 // now, make sure everything is of the same, correct type
452 Iterator it = inputs.iterator();
453 int i = 0;
454 while (it.hasNext()) {
455 Evaluatable eval = (Evaluatable)(it.next());
456
457 if ((! eval.getType().toString().equals(paramTypes[i])) ||
458 (paramsAreBags[i]))
459 throw new IllegalArgumentException("illegal parameter");
460
461 i++;
462 }
463 }
464 }
465
466 }