Line | Hits | Source |
---|---|---|
1 | /* | |
2 | Chrysalis Web Framework [http://chrysalis.sourceforge.net] | |
3 | Copyright (c) 2002, 2003, 2004, Paul Strack | |
4 | ||
5 | 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. Redistributions of source code must retain the above copyright notice, this | |
11 | list of conditions and the following disclaimer. | |
12 | ||
13 | 2. Redistributions in binary form must reproduce the above copyright notice, | |
14 | this list of conditions and the following disclaimer in the documentation | |
15 | and/or other materials provided with the distribution. | |
16 | ||
17 | 3. Neither the name of the copyright holder nor the names of its contributors | |
18 | may be used to endorse or promote products derived from this software without | |
19 | specific prior written permission. | |
20 | ||
21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | |
25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |
28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
31 | */ | |
32 | ||
33 | package org.chwf.resources; | |
34 | ||
35 | import java.util.HashMap; | |
36 | import java.util.Iterator; | |
37 | import java.util.Map; | |
38 | ||
39 | import org.chwf.i18n.Message; | |
40 | ||
41 | /** | |
42 | * A locator for resources. It delegates is calls to the appropriate | |
43 | * [@link ResourceFactory}. | |
44 | * | |
45 | * @author Paul Strack | |
46 | */ | |
47 | 2 | public class ResourceLocator { |
48 | ||
49 | /** Empty array. */ | |
50 | 2 | private static final Object[] EMPTY_ARRAY = new Object[0]; |
51 | ||
52 | /** The resource factories, indexed by ResourceID. */ | |
53 | 1 | private static final Map RESOURCE_FACTORIES = initResourceFactories(); |
54 | ||
55 | /** A thread local variable for caching managed resources. */ | |
56 | 1 | private static final ThreadLocal MANAGED_RESOURCES = new ThreadLocal(); |
57 | ||
58 | /** | |
59 | * True if the resource has a (default) factory. | |
60 | * | |
61 | * @param resource The resource class. | |
62 | * @return True if the resource has a factory. | |
63 | */ | |
64 | public static boolean hasFactory(Class resource) { | |
65 | 2 | return hasFactory(resource, ResourceManagerConfig.DEFAULT_FACTORY); |
66 | } | |
67 | ||
68 | /** | |
69 | * True if the resource has a factory with the given name. | |
70 | * | |
71 | * @param resource The resource class. | |
72 | * @param factoryName The factory name. | |
73 | * @return True if the resource has a factory with the given name. | |
74 | */ | |
75 | public static boolean hasFactory(Class resource, String factoryName) { | |
76 | 5 | if (factoryName == null) { |
77 | 1 | factoryName = ResourceManagerConfig.DEFAULT_FACTORY; |
78 | } | |
79 | 5 | ResourceID pair = new ResourceID(resource, factoryName); |
80 | 5 | return (RESOURCE_FACTORIES.get(pair) != null); |
81 | } | |
82 | ||
83 | /** | |
84 | * True if this resource is managed for the default factory. | |
85 | * | |
86 | * @param resource The resource class. | |
87 | * @return True if this resource is managed by the default factory. | |
88 | */ | |
89 | public static boolean isManaged(Class resource) { | |
90 | 1 | return isManaged(resource, ResourceManagerConfig.DEFAULT_FACTORY); |
91 | } | |
92 | ||
93 | /** | |
94 | * True if this resource is managed for the given named factory. | |
95 | * | |
96 | * @param resource The resource class. | |
97 | * @param factoryName The factory name. | |
98 | * @return True if this resource is managed for the given named factory. | |
99 | */ | |
100 | public static boolean isManaged(Class resource, String factoryName) { | |
101 | 3 | if (factoryName == null) { |
102 | 1 | factoryName = ResourceManagerConfig.DEFAULT_FACTORY; |
103 | } | |
104 | 3 | ResourceID pair = new ResourceID(resource, factoryName); |
105 | 3 | Object factory = RESOURCE_FACTORIES.get(pair); |
106 | 3 | return ((factory != null) && (factory instanceof ManagedResourceFactory)); |
107 | } | |
108 | ||
109 | /** | |
110 | * Get a resource from its default factory. | |
111 | * | |
112 | * @param type The resource type. | |
113 | * @return The resource. | |
114 | * @throws ResourceException If there is no factory for this resource. | |
115 | * @throws ResourceInitException If the factory cannot be found. | |
116 | */ | |
117 | public static Object getResource(Class type) | |
118 | throws ResourceException, ResourceInitException { | |
119 | 2 | return getResource(type, ResourceManagerConfig.DEFAULT_FACTORY); |
120 | } | |
121 | ||
122 | /** | |
123 | * Get a resource from a named factory. | |
124 | * | |
125 | * @param type The resource type. | |
126 | * @param factoryName The factory name. | |
127 | * @return The resource. | |
128 | * @throws ResourceException If there is no factory with this name. | |
129 | * @throws ResourceInitException If the factory cannot be found. | |
130 | */ | |
131 | public static Object getResource(Class type, String factoryName) | |
132 | throws ResourceException, ResourceInitException { | |
133 | ||
134 | 11 | if (factoryName == null) { |
135 | 1 | factoryName = ResourceManagerConfig.DEFAULT_FACTORY; |
136 | } | |
137 | 11 | ResourceFactory factory = ResourceLocator.getFactory(type, factoryName); |
138 | 10 | if (factory instanceof ManagedResourceFactory) { |
139 | 8 | ManagedResourceFactory managedFactory = (ManagedResourceFactory) factory; |
140 | 8 | return getManagedResource(type, factoryName, managedFactory); |
141 | } else { | |
142 | 2 | return factory.getResource(); |
143 | } | |
144 | } | |
145 | ||
146 | /** | |
147 | * True if management is initialized. | |
148 | * | |
149 | * @return True if management is initialized. | |
150 | */ | |
151 | public static boolean isManagementActive() { | |
152 | 973 | return (MANAGED_RESOURCES.get() != null); |
153 | } | |
154 | ||
155 | /** | |
156 | * Initialize resource management for this thread. Developers should not call | |
157 | * this method except for testing. This method can only be called once until | |
158 | * the release() method is called. | |
159 | * | |
160 | * @throws ResourceInitException If called while initialized. | |
161 | */ | |
162 | static void init() throws ResourceInitException { | |
163 | 472 | if (!isManagementActive()) { |
164 | 471 | MANAGED_RESOURCES.set(new HashMap()); |
165 | } else { | |
166 | 1 | throw new ResourceInitException( |
167 | ResourceInitException.MESSAGE_ALREADY_INITIALIZED); | |
168 | } | |
169 | 471 | } |
170 | ||
171 | /** | |
172 | * Release all managed resources, and terminate resource management for this | |
173 | * thread. Developers should not call this method except for testing. All | |
174 | * resources are released, even if there are failures during the release | |
175 | * process. The resources are not released in any particular order, however. | |
176 | * | |
177 | * @param error Error status for the thread of execution (null if there were | |
178 | * no errors). | |
179 | * @throws ResourceException If there were failures during the release. | |
180 | * This is a chained exception; the full set of release errors can | |
181 | * be retrieved via {@link ResourceException#getNextException()} | |
182 | * @throws ResourceInitException If called when not initialized. | |
183 | */ | |
184 | static void release(Throwable error) | |
185 | throws ResourceException, ResourceInitException { | |
186 | ||
187 | 472 | if (isManagementActive()) { |
188 | 471 | ResourceException errors = null; |
189 | 471 | Iterator resources = getManagedResources().values().iterator(); |
190 | 948 | while (resources.hasNext()) { |
191 | try { | |
192 | 6 | ManagedResource resource = (ManagedResource) resources.next(); |
193 | 6 | resource.release(error); |
194 | 4 | } catch (ResourceException ex) { |
195 | 1 | ex.setNextException(errors); |
196 | 1 | errors = ex; |
197 | 1 | } catch (Throwable ex) { |
198 | 1 | ResourceException rex = new ResourceException(ex); |
199 | 1 | rex.setNextException(errors); |
200 | 1 | errors = rex; |
201 | } | |
202 | } | |
203 | 471 | MANAGED_RESOURCES.set(null); |
204 | 471 | if (errors != null) { |
205 | 2 | Message msg = |
206 | Message.getMessage( | |
207 | ResourceException.MESSAGE_RESOURCE_RELEASE_FAILURE, | |
208 | EMPTY_ARRAY, | |
209 | ResourceException.class); | |
210 | 2 | ResourceException ex = new ResourceException(msg.toString()); |
211 | 2 | ex.setNextException(errors); |
212 | 2 | throw ex; |
213 | } | |
214 | } else { | |
215 | 1 | throw new ResourceInitException( |
216 | ResourceInitException.MESSAGE_NOT_INITIALIZED); | |
217 | } | |
218 | 469 | } |
219 | ||
220 | /** | |
221 | * Initialize all resource factories. | |
222 | * | |
223 | * @return The map containing the resource factories. | |
224 | * @throws ResourceInitException If a factory class cannot be initialized. | |
225 | */ | |
226 | private static Map initResourceFactories() throws ResourceInitException { | |
227 | 1 | Map map = new HashMap(); |
228 | 1 | ResourceManagerConfig config = ResourceManagerConfig.getConfig(); |
229 | 1 | String[] resourceClasses = config.getResourceClasses(); |
230 | 3 | for (int i = 0; i < resourceClasses.length; i++) { |
231 | 2 | String resource = resourceClasses[i]; |
232 | 2 | Class resourceClass = deriveResourceClass(resource); |
233 | 2 | Map factoryClasses = config.getFactoryClasses(resource); |
234 | 2 | Iterator iterator = factoryClasses.keySet().iterator(); |
235 | 10 | while (iterator.hasNext()) { |
236 | 6 | String factoryName = iterator.next().toString(); |
237 | 6 | String factoryClassName = factoryClasses.get(factoryName).toString(); |
238 | 6 | ResourceFactory factory = createFactory(factoryClassName, resource); |
239 | 6 | if (!resourceClass.equals(factory.getType())) { |
240 | 0 | Object[] args = { factoryName, resource }; |
241 | 0 | throw new ResourceInitException( |
242 | ResourceInitException.MESSAGE_WRONG_FACTORY_TYPE, | |
243 | args); | |
244 | } | |
245 | 6 | Map factoryProperties = |
246 | config.getFactoryProperties(resource, factoryName); | |
247 | 6 | ResourceFactoryConfigImpl factoryConfig = |
248 | new ResourceFactoryConfigImpl(factoryName, factoryProperties); | |
249 | try { | |
250 | 6 | factory.init(factoryConfig); |
251 | 6 | } catch (Exception ex) { |
252 | 0 | Object[] args = { factoryName, resource, ex }; |
253 | 0 | throw new ResourceInitException( |
254 | ResourceInitException.MESSAGE_FACTORY_INIT_FAILED, | |
255 | args); | |
256 | } | |
257 | 6 | ResourceID id = new ResourceID(resourceClass, factoryName); |
258 | 6 | map.put(id, factory); |
259 | } | |
260 | } | |
261 | 1 | return map; |
262 | } | |
263 | ||
264 | /** | |
265 | * Derive resource class for the given class name. | |
266 | * | |
267 | * @param className The class name. | |
268 | * @return The class. | |
269 | * @throws ResourceInitException If the factory class is not found. | |
270 | */ | |
271 | private static Class deriveResourceClass(String className) | |
272 | throws ResourceInitException { | |
273 | try { | |
274 | 2 | return Class.forName(className); |
275 | } catch (ClassNotFoundException ex) { | |
276 | 0 | Object[] args = { className }; |
277 | 0 | throw new ResourceInitException( |
278 | ResourceInitException.MESSAGE_RESOURCE_CLASS_NOT_FOUND, | |
279 | args); | |
280 | } | |
281 | } | |
282 | ||
283 | /** | |
284 | * Derive resource factory class for the given class name. | |
285 | * | |
286 | * @param className The factory class name. | |
287 | * @param resource The resource name. | |
288 | * @return The class. | |
289 | * @throws ResourceInitException If the factory class is not found. | |
290 | */ | |
291 | private static Class deriveFactoryClass(String className, String resource) | |
292 | throws ResourceInitException { | |
293 | try { | |
294 | 6 | return Class.forName(className); |
295 | } catch (ClassNotFoundException ex) { | |
296 | 0 | Object[] args = { className, resource }; |
297 | 0 | throw new ResourceInitException( |
298 | ResourceInitException.MESSAGE_FACTORY_CLASS_NOT_FOUND, | |
299 | args); | |
300 | } | |
301 | } | |
302 | ||
303 | /** | |
304 | * Create resource factory for the given class name. | |
305 | * | |
306 | * @param className The factory class name. | |
307 | * @param resource The resource name. | |
308 | * @return The factory. | |
309 | * @throws ResourceInitException If the factory cannot be created. | |
310 | */ | |
311 | private static ResourceFactory createFactory( | |
312 | String className, | |
313 | String resource) | |
314 | throws ResourceInitException { | |
315 | 6 | Class factoryClass = deriveFactoryClass(className, resource); |
316 | try { | |
317 | 6 | return (ResourceFactory) factoryClass.newInstance(); |
318 | } catch (ClassCastException ex) { | |
319 | 0 | Object[] args = { factoryClass.getName(), resource }; |
320 | 0 | throw new ResourceInitException( |
321 | ResourceInitException.MESSAGE_NOT_A_RESOURCE_FACTORY, | |
322 | args); | |
323 | } catch (Exception ex) { | |
324 | 0 | Object[] args = { factoryClass.getName(), resource, ex }; |
325 | 0 | throw new ResourceInitException( |
326 | ResourceInitException.MESSAGE_FACTORY_NOT_CREATED, | |
327 | args); | |
328 | } | |
329 | } | |
330 | ||
331 | /** | |
332 | * Retrieve the factory for the given resource type. | |
333 | * | |
334 | * @param type The resource type. | |
335 | * @param name The factory name. | |
336 | * @return The factory. | |
337 | * @throws ResourceInitException If the factory is not found. | |
338 | */ | |
339 | private static ResourceFactory getFactory(Class type, String name) | |
340 | throws ResourceInitException { | |
341 | ||
342 | 11 | ResourceID pair = new ResourceID(type, name); |
343 | 11 | ResourceFactory factory = (ResourceFactory) RESOURCE_FACTORIES.get(pair); |
344 | 11 | if (factory == null) { |
345 | 1 | Object[] args = { name, type }; |
346 | 1 | throw new ResourceInitException( |
347 | ResourceInitException.MESSAGE_FACTORY_NOT_FOUND, | |
348 | args); | |
349 | } | |
350 | 10 | return factory; |
351 | } | |
352 | ||
353 | /** | |
354 | * Retrieve a managed resource. | |
355 | * | |
356 | * @param type The resource type. | |
357 | * @param name The factory name. | |
358 | * @param factory The factory. | |
359 | * @return The managed resource. | |
360 | * @throws ResourceException If the resource cannot be retrieved. | |
361 | * @throws ResourceInitException If the factory is not initialized. | |
362 | */ | |
363 | private static Object getManagedResource( | |
364 | Class type, | |
365 | String name, | |
366 | ManagedResourceFactory factory) | |
367 | throws ResourceException, ResourceInitException { | |
368 | ||
369 | 8 | if (!isManagementActive()) { |
370 | 1 | Object[] args = { type.getName(), name }; |
371 | 1 | throw new ResourceInitException( |
372 | ResourceInitException.MESSAGE_MANAGEMENT_NOT_INITIALIZED, | |
373 | args); | |
374 | } | |
375 | 7 | ResourceID id = new ResourceID(type, name); |
376 | 7 | Map managedResources = getManagedResources(); |
377 | 7 | ManagedResource managed = (ManagedResource) managedResources.get(id); |
378 | 7 | if (managed == null) { |
379 | 7 | managed = new ManagedResource(factory, factory.getResource()); |
380 | 6 | managedResources.put(id, managed); |
381 | } | |
382 | 6 | return managed.getResource(); |
383 | } | |
384 | ||
385 | /** | |
386 | * The list of managed resources. | |
387 | * | |
388 | * @return The list of managed resources. | |
389 | */ | |
390 | private static Map getManagedResources() { | |
391 | 478 | return (Map) MANAGED_RESOURCES.get(); |
392 | } | |
393 | ||
394 | /** | |
395 | * A class for map values for managed resources. | |
396 | * | |
397 | * @author Paul Strack | |
398 | */ | |
399 | private static class ManagedResource { | |
400 | ||
401 | /** The factory. */ | |
402 | private final ManagedResourceFactory factory; | |
403 | ||
404 | /** The resource. */ | |
405 | private final Object resource; | |
406 | ||
407 | /** | |
408 | * Constructor. | |
409 | * | |
410 | * @param factory The factory. | |
411 | * @param resource The resource. | |
412 | */ | |
413 | ManagedResource(ManagedResourceFactory factory, Object resource) { | |
414 | this.factory = factory; | |
415 | this.resource = resource; | |
416 | } | |
417 | ||
418 | /** | |
419 | * The resource. | |
420 | * | |
421 | * @return The resource. | |
422 | */ | |
423 | Object getResource() { | |
424 | return resource; | |
425 | } | |
426 | ||
427 | /** | |
428 | * Release the resource. | |
429 | * | |
430 | * @param error An error message (or null if there were no errors). | |
431 | * @throws ResourceException If the release fails. | |
432 | */ | |
433 | void release(Throwable error) throws ResourceException { | |
434 | factory.release(resource, error); | |
435 | } | |
436 | } | |
437 | } |
this report was generated by version 1.0.5 of jcoverage. |
copyright © 2003, jcoverage ltd. all rights reserved. |