Source code: com/sun/xacml/cond/BaseFunctionFactory.java
1
2 /*
3 * @(#)BaseCombiningAlgFactory.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.ParsingException;
40 import com.sun.xacml.UnknownIdentifierException;
41
42 import java.net.URI;
43
44 import java.util.HashMap;
45 import java.util.HashSet;
46 import java.util.Iterator;
47 import java.util.Map;
48 import java.util.Set;
49
50 import org.w3c.dom.Node;
51
52
53 /**
54 * This is a basic implementation of <code>FunctionFactory</code>. It
55 * implements the insertion and retrieval methods, but it doesn't actually
56 * setup the factory with any functions. It also assumes a certain model
57 * with regard to the different kinds of functions (Target, Condition, and
58 * General). For this reason, you may want to re-use this class, or you
59 * may want to extend FunctionFactory directly, if you're writing a new
60 * factory implementation.
61 * <p>
62 * Note that while this class is thread-safe on all creation methods, it
63 * is not safe to add support for a new function while creating an instance
64 * of a function. This follows from the assumption that most people will
65 * initialize these factories up-front, and then start processing without
66 * ever modifying the factories. If you need these mutual operations to
67 * be thread-safe, then you should write a wrapper class that implements
68 * the right synchronization.
69 *
70 * @since 1.2
71 * @author Seth Proctor
72 */
73 public class BaseFunctionFactory extends FunctionFactory
74 {
75
76 // the backing maps for the Function objects
77 private HashMap functionMap = null;
78
79 // the superset factory chained to this factory
80 private FunctionFactory superset = null;
81
82 /**
83 * Default constructor. No superset factory is used.
84 */
85 public BaseFunctionFactory() {
86 this(null);
87 }
88
89 /**
90 * Constructor that sets a "superset factory". This is useful since
91 * the different function factories (Target, Condition, and General)
92 * have a superset relationship (Condition functions are a superset
93 * of Target functions, etc.). Adding a function to this factory will
94 * automatically add the same function to the superset factory.
95 *
96 * @param superset the superset factory or null
97 */
98 public BaseFunctionFactory(FunctionFactory superset) {
99 functionMap = new HashMap();
100
101 this.superset = superset;
102 }
103
104 /**
105 * Constructor that defines the initial functions supported by this
106 * factory but doesn't use a superset factory.
107 *
108 * @param supportedFunctions a <code>Set</code> of <code>Function</code>s
109 * @param supportedAbstractFunctions a mapping from <code>URI</code> to
110 * <code>FunctionProxy</code>
111 */
112 public BaseFunctionFactory(Set supportedFunctions,
113 Map supportedAbstractFunctions) {
114 this(null, supportedFunctions, supportedAbstractFunctions);
115 }
116
117 /**
118 * Constructor that defines the initial functions supported by this
119 * factory and uses a superset factory. Note that the functions
120 * supplied here are not propagated up to the superset factory, so
121 * you must either make sure the superst factory is correctly
122 * initialized or use <code>BaseFunctionFactory(FunctionFactory)</code>
123 * and then manually add each function.
124 *
125 * @param superset the superset factory or null
126 * @param supportedFunctions a <code>Set</code> of <code>Function</code>s
127 * @param supportedAbstractFunctions a mapping from <code>URI</code> to
128 * <code>FunctionProxy</code>
129 */
130 public BaseFunctionFactory(FunctionFactory superset,
131 Set supportedFunctions,
132 Map supportedAbstractFunctions) {
133 this(superset);
134
135 Iterator it = supportedFunctions.iterator();
136 while (it.hasNext()) {
137 Function function = (Function)(it.next());
138 functionMap.put(function.getIdentifier().toString(), function);
139 }
140
141 it = supportedAbstractFunctions.keySet().iterator();
142 while (it.hasNext()) {
143 URI id = (URI)(it.next());
144 FunctionProxy proxy =
145 (FunctionProxy)(supportedAbstractFunctions.get(id));
146 functionMap.put(id.toString(), proxy);
147 }
148 }
149
150 /**
151 * Adds the function to the factory. Most functions have no state, so
152 * the singleton model used here is typically desireable. The factory will
153 * not enforce the requirement that a Target or Condition matching function
154 * must be boolean.
155 *
156 * @param function the <code>Function</code> to add to the factory
157 *
158 * @throws IllegalArgumentException if the function's identifier is already
159 * used or if the function is non-boolean
160 * (when this is a Target or Condition
161 * factory)
162 */
163 public void addFunction(Function function)
164 throws IllegalArgumentException
165 {
166 String id = function.getIdentifier().toString();
167
168 // make sure this doesn't already exist
169 if (functionMap.containsKey(id))
170 throw new IllegalArgumentException("function already exists");
171
172 // add to the superset factory
173 if (superset != null)
174 superset.addFunction(function);
175
176 // finally, add to this factory
177 functionMap.put(id, function);
178 }
179
180 /**
181 * Adds the abstract function proxy to the factory. This is used for
182 * those functions which have state, or change behavior (for instance
183 * the standard map function, which changes its return type based on
184 * how it is used).
185 *
186 * @param proxy the <code>FunctionProxy</code> to add to the factory
187 * @param identity the function's identifier
188 *
189 * @throws IllegalArgumentException if the function's identifier is already
190 * used
191 */
192 public void addAbstractFunction(FunctionProxy proxy,
193 URI identity)
194 throws IllegalArgumentException
195 {
196 String id = identity.toString();
197
198 // make sure this doesn't already exist
199 if (functionMap.containsKey(id))
200 throw new IllegalArgumentException("function already exists");
201
202 // add to the superset factory
203 if (superset != null)
204 superset.addAbstractFunction(proxy, identity);
205
206 // finally, add to this factory
207 functionMap.put(id, proxy);
208 }
209
210 /**
211 * Returns the function identifiers supported by this factory.
212 *
213 * @return a <code>Set</code> of <code>String</code>s
214 */
215 public Set getSupportedFunctions() {
216 Set set = new HashSet(functionMap.keySet());
217
218 if (superset != null)
219 set.addAll(superset.getSupportedFunctions());
220
221 return set;
222 }
223
224 /**
225 * Tries to get an instance of the specified function.
226 *
227 * @param identity the name of the function
228 *
229 * @throws UnknownIdentifierException if the name isn't known
230 * @throws FunctionTypeException if the name is known to map to an
231 * abstract function, and should therefore
232 * be created through createAbstractFunction
233 */
234 public Function createFunction(URI identity)
235 throws UnknownIdentifierException, FunctionTypeException
236 {
237 return createFunction(identity.toString());
238 }
239
240 /**
241 * Tries to get an instance of the specified function.
242 *
243 * @param identity the name of the function
244 *
245 * @throws UnknownIdentifierException if the name isn't known
246 * @throws FunctionTypeException if the name is known to map to an
247 * abstract function, and should therefore
248 * be created through createAbstractFunction
249 */
250 public Function createFunction(String identity)
251 throws UnknownIdentifierException, FunctionTypeException
252 {
253 Object entry = functionMap.get(identity);
254
255 if (entry != null) {
256 if (entry instanceof Function) {
257 return (Function)entry;
258 } else {
259 // this is actually a proxy, which means the other create
260 // method should have been called
261 throw new FunctionTypeException("function is abstract");
262 }
263 } else {
264 // we couldn't find a match
265 throw new UnknownIdentifierException("functions of type " +
266 identity + " are not "+
267 "supported by this factory");
268 }
269 }
270
271 /**
272 * Tries to get an instance of the specified abstract function.
273 *
274 * @param identity the name of the function
275 * @param root the DOM root containing info used to create the function
276 *
277 * @throws UnknownIdentifierException if the name isn't known
278 * @throws FunctionTypeException if the name is known to map to a
279 * concrete function, and should therefore
280 * be created through createFunction
281 * @throws ParsingException if the function can't be created with the
282 * given inputs
283 */
284 public Function createAbstractFunction(URI identity, Node root)
285 throws UnknownIdentifierException, ParsingException,
286 FunctionTypeException
287 {
288 return createAbstractFunction(identity.toString(), root, null);
289 }
290
291 /**
292 * Tries to get an instance of the specified abstract function.
293 *
294 * @param identity the name of the function
295 * @param root the DOM root containing info used to create the function
296 * @param xpathVersion the version specified in the contianing policy, or
297 * null if no version was specified
298 *
299 * @throws UnknownIdentifierException if the name isn't known
300 * @throws FunctionTypeException if the name is known to map to a
301 * concrete function, and should therefore
302 * be created through createFunction
303 * @throws ParsingException if the function can't be created with the
304 * given inputs
305 */
306 public Function createAbstractFunction(URI identity, Node root,
307 String xpathVersion)
308 throws UnknownIdentifierException, ParsingException,
309 FunctionTypeException
310 {
311 return createAbstractFunction(identity.toString(), root, xpathVersion);
312 }
313
314 /**
315 * Tries to get an instance of the specified abstract function.
316 *
317 * @param identity the name of the function
318 * @param root the DOM root containing info used to create the function
319 *
320 * @throws UnknownIdentifierException if the name isn't known
321 * @throws FunctionTypeException if the name is known to map to a
322 * concrete function, and should therefore
323 * be created through createFunction
324 * @throws ParsingException if the function can't be created with the
325 * given inputs
326 */
327 public Function createAbstractFunction(String identity, Node root)
328 throws UnknownIdentifierException, ParsingException,
329 FunctionTypeException
330 {
331 return createAbstractFunction(identity, root, null);
332 }
333
334 /**
335 * Tries to get an instance of the specified abstract function.
336 *
337 * @param identity the name of the function
338 * @param root the DOM root containing info used to create the function
339 * @param xpathVersion the version specified in the contianing policy, or
340 * null if no version was specified
341 *
342 * @throws UnknownIdentifierException if the name isn't known
343 * @throws FunctionTypeException if the name is known to map to a
344 * concrete function, and should therefore
345 * be created through createFunction
346 * @throws ParsingException if the function can't be created with the
347 * given inputs
348 */
349 public Function createAbstractFunction(String identity, Node root,
350 String xpathVersion)
351 throws UnknownIdentifierException, ParsingException,
352 FunctionTypeException
353 {
354 Object entry = functionMap.get(identity);
355
356 if (entry != null) {
357 if (entry instanceof FunctionProxy) {
358 try {
359 return ((FunctionProxy)entry).getInstance(root,
360 xpathVersion);
361 } catch (Exception e) {
362 throw new ParsingException("couldn't create abstract" +
363 " function " + identity, e);
364 }
365 } else {
366 // this is actually a concrete function, which means that
367 // the other create method should have been called
368 throw new FunctionTypeException("function is concrete");
369 }
370 } else {
371 // we couldn't find a match
372 throw new UnknownIdentifierException("abstract functions of " +
373 "type " + identity +
374 " are not supported by " +
375 "this factory");
376 }
377 }
378
379 }