Source code: com/sun/xacml/cond/StandardFunctionFactory.java
1
2 /*
3 * @(#)StandardFunctionFactory.java
4 *
5 * Copyright 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.cond.cluster.AbsFunctionCluster;
40 import com.sun.xacml.cond.cluster.AddFunctionCluster;
41 import com.sun.xacml.cond.cluster.ComparisonFunctionCluster;
42 import com.sun.xacml.cond.cluster.ConditionBagFunctionCluster;
43 import com.sun.xacml.cond.cluster.ConditionSetFunctionCluster;
44 import com.sun.xacml.cond.cluster.DateMathFunctionCluster;
45 import com.sun.xacml.cond.cluster.DivideFunctionCluster;
46 import com.sun.xacml.cond.cluster.EqualFunctionCluster;
47 import com.sun.xacml.cond.cluster.FloorFunctionCluster;
48 import com.sun.xacml.cond.cluster.GeneralBagFunctionCluster;
49 import com.sun.xacml.cond.cluster.GeneralSetFunctionCluster;
50 import com.sun.xacml.cond.cluster.HigherOrderFunctionCluster;
51 import com.sun.xacml.cond.cluster.LogicalFunctionCluster;
52 import com.sun.xacml.cond.cluster.MatchFunctionCluster;
53 import com.sun.xacml.cond.cluster.ModFunctionCluster;
54 import com.sun.xacml.cond.cluster.MultiplyFunctionCluster;
55 import com.sun.xacml.cond.cluster.NOfFunctionCluster;
56 import com.sun.xacml.cond.cluster.NotFunctionCluster;
57 import com.sun.xacml.cond.cluster.NumericConvertFunctionCluster;
58 import com.sun.xacml.cond.cluster.RoundFunctionCluster;
59 import com.sun.xacml.cond.cluster.StringNormalizeFunctionCluster;
60 import com.sun.xacml.cond.cluster.SubtractFunctionCluster;
61
62 import java.net.URI;
63 import java.net.URISyntaxException;
64
65 import java.util.Collections;
66 import java.util.HashSet;
67 import java.util.HashMap;
68 import java.util.Iterator;
69 import java.util.Map;
70 import java.util.Set;
71
72 import java.util.logging.Logger;
73
74
75 /**
76 * This factory supports the standard set of functions specified in XACML
77 * 1.0 and 1.1. It is the default factory used by the system, and imposes
78 * a singleton pattern insuring that there is only ever one instance of
79 * this class.
80 * <p>
81 * Note that because this supports only the standard functions, this
82 * factory does not allow the addition of any other functions. If you call
83 * <code>addFunction</code> on an instance of this class, an exception
84 * will be thrown. If you need a standard factory that is modifiable,
85 * you can either create a new <code>BaseFunctionFactory</code> (or some
86 * other implementation of <code>FunctionFactory</code>) populated with
87 * the standard functions from <code>getStandardFunctions</code> or
88 * you can use <code>getNewFactoryProxy</code> to get a proxy containing
89 * a new, modifiable set of factories.
90 *
91 * @since 1.2
92 * @author Seth Proctor
93 */
94 public class StandardFunctionFactory extends BaseFunctionFactory
95 {
96
97 // the three singleton instances
98 private static StandardFunctionFactory targetFactory = null;
99 private static StandardFunctionFactory conditionFactory = null;
100 private static StandardFunctionFactory generalFactory = null;
101
102 // the three function sets/maps that we use internally
103 private static Set targetFunctions = null;
104 private static Set conditionFunctions = null;
105 private static Set generalFunctions = null;
106
107 private static Map targetAbstractFunctions = null;
108 private static Map conditionAbstractFunctions = null;
109 private static Map generalAbstractFunctions = null;
110
111 // the set/map used by each singleton factory instance
112 private Set supportedFunctions = null;
113 private Map supportedAbstractFunctions = null;
114
115 // the logger we'll use for all messages
116 private static final Logger logger =
117 Logger.getLogger(StandardFunctionFactory.class.getName());
118
119 /**
120 * Creates a new StandardFunctionFactory, making sure that the default
121 * maps are initialized correctly. Standard factories can't be modified,
122 * so there is no notion of supersetting since that's only used for
123 * correctly propagating new functions.
124 */
125 private StandardFunctionFactory(Set supportedFunctions,
126 Map supportedAbstractFunctions) {
127 super(supportedFunctions, supportedAbstractFunctions);
128
129 this.supportedFunctions = supportedFunctions;
130 this.supportedAbstractFunctions = supportedAbstractFunctions;
131 }
132
133 /**
134 * Private initializer for the target functions. This is only ever
135 * called once.
136 */
137 private static void initTargetFunctions() {
138 logger.config("Initializing standard Target functions");
139
140 targetFunctions = new HashSet();
141
142 // add EqualFunction
143 targetFunctions.addAll((new EqualFunctionCluster()).
144 getSupportedFunctions());
145 // add LogicalFunction
146 targetFunctions.addAll((new LogicalFunctionCluster()).
147 getSupportedFunctions());
148 // add NOfFunction
149 targetFunctions.addAll((new NOfFunctionCluster()).
150 getSupportedFunctions());
151 // add NotFunction
152 targetFunctions.addAll((new NotFunctionCluster()).
153 getSupportedFunctions());
154 // add ComparisonFunction
155 targetFunctions.addAll((new ComparisonFunctionCluster()).
156 getSupportedFunctions());
157 // add MatchFunction
158 targetFunctions.addAll((new MatchFunctionCluster()).
159 getSupportedFunctions());
160
161 targetAbstractFunctions = new HashMap();
162 }
163
164 /**
165 * Private initializer for the condition functions. This is only ever
166 * called once.
167 */
168 private static void initConditionFunctions() {
169 logger.config("Initializing standard Condition functions");
170
171 if (targetFunctions == null)
172 initTargetFunctions();
173
174 conditionFunctions = new HashSet(targetFunctions);
175
176 // add condition functions from BagFunction
177 conditionFunctions.addAll((new ConditionBagFunctionCluster()).
178 getSupportedFunctions());
179 // add condition functions from SetFunction
180 conditionFunctions.addAll((new ConditionSetFunctionCluster()).
181 getSupportedFunctions());
182 // add condition functions from HigherOrderFunction
183 conditionFunctions.addAll((new HigherOrderFunctionCluster()).
184 getSupportedFunctions());
185
186 conditionAbstractFunctions = new HashMap(targetAbstractFunctions);
187 }
188
189 /**
190 * Private initializer for the general functions. This is only ever
191 * called once.
192 */
193 private static void initGeneralFunctions() {
194 logger.config("Initializing standard General functions");
195
196 if (conditionFunctions == null)
197 initConditionFunctions();
198
199 generalFunctions = new HashSet(conditionFunctions);
200
201 // add AddFunction
202 generalFunctions.addAll((new AddFunctionCluster()).
203 getSupportedFunctions());
204 // add SubtractFunction
205 generalFunctions.addAll((new SubtractFunctionCluster()).
206 getSupportedFunctions());
207 // add MultiplyFunction
208 generalFunctions.addAll((new MultiplyFunctionCluster()).
209 getSupportedFunctions());
210 // add DivideFunction
211 generalFunctions.addAll((new DivideFunctionCluster()).
212 getSupportedFunctions());
213 // add ModFunction
214 generalFunctions.addAll((new ModFunctionCluster()).
215 getSupportedFunctions());
216 // add AbsFunction
217 generalFunctions.addAll((new AbsFunctionCluster()).
218 getSupportedFunctions());
219 // add RoundFunction
220 generalFunctions.addAll((new RoundFunctionCluster()).
221 getSupportedFunctions());
222 // add FloorFunction
223 generalFunctions.addAll((new FloorFunctionCluster()).
224 getSupportedFunctions());
225 // add DateMathFunction
226 generalFunctions.addAll((new DateMathFunctionCluster()).
227 getSupportedFunctions());
228 // add general functions from BagFunction
229 generalFunctions.addAll((new GeneralBagFunctionCluster()).
230 getSupportedFunctions());
231 // add NumericConvertFunction
232 generalFunctions.addAll((new NumericConvertFunctionCluster()).
233 getSupportedFunctions());
234 // add StringNormalizeFunction
235 generalFunctions.addAll((new StringNormalizeFunctionCluster()).
236 getSupportedFunctions());
237 // add general functions from SetFunction
238 generalFunctions.addAll((new GeneralSetFunctionCluster()).
239 getSupportedFunctions());
240
241 generalAbstractFunctions = new HashMap(conditionAbstractFunctions);
242
243 // add the map function's proxy
244 try {
245 generalAbstractFunctions.put(new URI(MapFunction.NAME_MAP),
246 new MapFunctionProxy());
247 } catch (URISyntaxException e) {
248 // this shouldn't ever happen, but just in case...
249 throw new IllegalArgumentException("invalid function name");
250 }
251 }
252
253 /**
254 * Returns a FunctionFactory that will only provide those functions that
255 * are usable in Target matching. This method enforces a singleton
256 * model, meaning that this always returns the same instance, creating
257 * the factory if it hasn't been requested before. This is the default
258 * model used by the <code>FunctionFactory</code>, ensuring quick
259 * access to this factory.
260 *
261 * @return a <code>FunctionFactory</code> for target functions
262 */
263 public static StandardFunctionFactory getTargetFactory() {
264 if (targetFactory == null) {
265 synchronized (StandardFunctionFactory.class) {
266 if (targetFunctions == null)
267 initTargetFunctions();
268 if (targetFactory == null)
269 targetFactory =
270 new StandardFunctionFactory(targetFunctions,
271 targetAbstractFunctions);
272 }
273 }
274
275 return targetFactory;
276 }
277
278 /**
279 * Returns a FuntionFactory that will only provide those functions that
280 * are usable in the root of the Condition. These Functions are a
281 * superset of the Target functions. This method enforces a singleton
282 * model, meaning that this always returns the same instance, creating
283 * the factory if it hasn't been requested before. This is the default
284 * model used by the <code>FunctionFactory</code>, ensuring quick
285 * access to this factory.
286 *
287 * @return a <code>FunctionFactory</code> for condition functions
288 */
289 public static StandardFunctionFactory getConditionFactory() {
290 if (conditionFactory == null) {
291 synchronized (StandardFunctionFactory.class) {
292 if (conditionFunctions == null)
293 initConditionFunctions();
294 if (conditionFactory == null)
295 conditionFactory =
296 new StandardFunctionFactory(conditionFunctions,
297 conditionAbstractFunctions);
298 }
299 }
300
301 return conditionFactory;
302 }
303
304 /**
305 * Returns a FunctionFactory that provides access to all the functions.
306 * These Functions are a superset of the Condition functions. This method
307 * enforces a singleton model, meaning that this always returns the same
308 * instance, creating the factory if it hasn't been requested before.
309 * This is the default model used by the <code>FunctionFactory</code>,
310 * ensuring quick access to this factory.
311 *
312 * @return a <code>FunctionFactory</code> for all functions
313 */
314 public static StandardFunctionFactory getGeneralFactory() {
315 if (generalFactory == null) {
316 synchronized (StandardFunctionFactory.class) {
317 if (generalFunctions == null) {
318 initGeneralFunctions();
319 generalFactory =
320 new StandardFunctionFactory(generalFunctions,
321 generalAbstractFunctions);
322 }
323 }
324 }
325
326 return generalFactory;
327 }
328
329 /**
330 * Returns the set of functions that this standard factory supports.
331 *
332 * @return a <code>Set</code> of <code>Function</code>s
333 */
334 public Set getStandardFunctions() {
335 return Collections.unmodifiableSet(supportedFunctions);
336 }
337
338 /**
339 * Returns the set of abstract functions that this standard factory
340 * supports as a mapping of identifier to proxy.
341 *
342 * @return a <code>Map</code> mapping <code>URI</code>s to
343 * <code>FunctionProxy</code>s
344 */
345 public Map getStandardAbstractFunctions() {
346 return Collections.unmodifiableMap(supportedAbstractFunctions);
347 }
348
349 /**
350 * A convenience method that returns a proxy containing newly created
351 * instances of <code>BaseFunctionFactory</code>s that are correctly
352 * supersetted and contain the standard functions and abstract functions.
353 * These factories allow adding support for new functions.
354 *
355 * @return a new proxy containing new factories supporting the standard
356 * functions
357 */
358 public static FunctionFactoryProxy getNewFactoryProxy() {
359 StandardFunctionFactory general =
360 StandardFunctionFactory.getGeneralFactory();
361 FunctionFactory newGeneral =
362 new BaseFunctionFactory(general.getStandardFunctions(),
363 general.getStandardAbstractFunctions());
364
365 StandardFunctionFactory condition =
366 StandardFunctionFactory.getConditionFactory();
367 FunctionFactory newCondition =
368 new BaseFunctionFactory(newGeneral,
369 condition.getStandardFunctions(),
370 condition.getStandardAbstractFunctions());
371
372 StandardFunctionFactory target =
373 StandardFunctionFactory.getTargetFactory();
374 FunctionFactory newTarget =
375 new BaseFunctionFactory(newCondition,
376 target.getStandardFunctions(),
377 target.getStandardAbstractFunctions());
378
379 return new BasicFunctionFactoryProxy(newTarget, newCondition,
380 newGeneral);
381 }
382
383 /**
384 * Always throws an exception, since support for new functions may not be
385 * added to a standard factory.
386 *
387 * @param function the <code>Function</code> to add to the factory
388 *
389 * @throws UnsupportedOperationException always
390 */
391 public void addFunction(Function function)
392 throws IllegalArgumentException
393 {
394 throw new UnsupportedOperationException("a standard factory cannot " +
395 "support new functions");
396 }
397
398 /**
399 * Always throws an exception, since support for new functions may not be
400 * added to a standard factory.
401 *
402 * @param proxy the <code>FunctionProxy</code> to add to the factory
403 * @param identity the function's identifier
404 *
405 * @throws UnsupportedOperationException always
406 */
407 public void addAbstractFunction(FunctionProxy proxy,
408 URI identity)
409 throws IllegalArgumentException
410 {
411 throw new UnsupportedOperationException("a standard factory cannot " +
412 "support new functions");
413 }
414
415 }