%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.turbine.services.factory.TurbineFactoryService |
|
|
1 | package org.apache.turbine.services.factory; |
|
2 | ||
3 | /* |
|
4 | * Copyright 2001-2005 The Apache Software Foundation. |
|
5 | * |
|
6 | * Licensed under the Apache License, Version 2.0 (the "License") |
|
7 | * you may not use this file except in compliance with the License. |
|
8 | * You may obtain a copy of the License at |
|
9 | * |
|
10 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
11 | * |
|
12 | * Unless required by applicable law or agreed to in writing, software |
|
13 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
15 | * See the License for the specific language governing permissions and |
|
16 | * limitations under the License. |
|
17 | */ |
|
18 | ||
19 | import java.io.ByteArrayInputStream; |
|
20 | import java.io.ByteArrayOutputStream; |
|
21 | import java.io.ObjectOutputStream; |
|
22 | import java.util.ArrayList; |
|
23 | import java.util.HashMap; |
|
24 | import java.util.Iterator; |
|
25 | import java.util.List; |
|
26 | ||
27 | import org.apache.commons.configuration.Configuration; |
|
28 | ||
29 | import org.apache.turbine.services.InitializationException; |
|
30 | import org.apache.turbine.services.TurbineBaseService; |
|
31 | import org.apache.turbine.util.TurbineException; |
|
32 | import org.apache.turbine.util.pool.ObjectInputStreamForContext; |
|
33 | ||
34 | /** |
|
35 | * The Factory Service instantiates objects using specified |
|
36 | * class loaders. If none is specified, the default one |
|
37 | * will be used. |
|
38 | * |
|
39 | * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a> |
|
40 | * @version $Id: TurbineFactoryService.java 264148 2005-08-29 14:21:04Z henning $ |
|
41 | */ |
|
42 | public class TurbineFactoryService |
|
43 | extends TurbineBaseService |
|
44 | implements FactoryService |
|
45 | { |
|
46 | /** |
|
47 | * The property specifying a set of additional class loaders. |
|
48 | */ |
|
49 | public static final String CLASS_LOADERS = "class.loaders"; |
|
50 | ||
51 | /** |
|
52 | * The property prefix specifying additional object factories. |
|
53 | */ |
|
54 | public static final String OBJECT_FACTORY = "factory."; |
|
55 | ||
56 | /** |
|
57 | * Primitive classes for reflection of constructors. |
|
58 | */ |
|
59 | private static HashMap primitiveClasses; |
|
60 | ||
61 | { |
|
62 | 48 | primitiveClasses = new HashMap(8); |
63 | 48 | primitiveClasses.put(Boolean.TYPE.toString(), Boolean.TYPE); |
64 | 48 | primitiveClasses.put(Character.TYPE.toString(), Character.TYPE); |
65 | 48 | primitiveClasses.put(Byte.TYPE.toString(), Byte.TYPE); |
66 | 48 | primitiveClasses.put(Short.TYPE.toString(), Short.TYPE); |
67 | 48 | primitiveClasses.put(Integer.TYPE.toString(), Integer.TYPE); |
68 | 48 | primitiveClasses.put(Long.TYPE.toString(), Long.TYPE); |
69 | 48 | primitiveClasses.put(Float.TYPE.toString(), Float.TYPE); |
70 | 48 | primitiveClasses.put(Double.TYPE.toString(), Double.TYPE); |
71 | } |
|
72 | ||
73 | /** |
|
74 | * Additional class loaders. |
|
75 | */ |
|
76 | 48 | private ArrayList classLoaders = new ArrayList(); |
77 | ||
78 | /** |
|
79 | * Customized object factories. |
|
80 | */ |
|
81 | 48 | private HashMap objectFactories = new HashMap(); |
82 | ||
83 | /** |
|
84 | * Gets the class of a primitive type. |
|
85 | * |
|
86 | * @param type a primitive type. |
|
87 | * @return the corresponding class, or null. |
|
88 | */ |
|
89 | protected static Class getPrimitiveClass(String type) |
|
90 | { |
|
91 | 40 | return (Class) primitiveClasses.get(type); |
92 | } |
|
93 | ||
94 | /** |
|
95 | * Constructs a Factory Service. |
|
96 | */ |
|
97 | public TurbineFactoryService() |
|
98 | 48 | { |
99 | 48 | } |
100 | ||
101 | /** |
|
102 | * Initializes the service by loading default class loaders |
|
103 | * and customized object factories. |
|
104 | * |
|
105 | * @throws InitializationException if initialization fails. |
|
106 | */ |
|
107 | public void init() throws InitializationException |
|
108 | { |
|
109 | 50 | Configuration conf = getConfiguration(); |
110 | 50 | if (conf != null) |
111 | { |
|
112 | 50 | List loaders = conf.getList(CLASS_LOADERS); |
113 | 50 | if (loaders != null) |
114 | { |
|
115 | 50 | for (int i = 0; i < loaders.size(); i++) |
116 | { |
|
117 | try |
|
118 | { |
|
119 | 0 | classLoaders.add( |
120 | loadClass((String) loaders.get(i)).newInstance()); |
|
121 | } |
|
122 | 0 | catch (Exception x) |
123 | { |
|
124 | 0 | throw new InitializationException( |
125 | "No such class loader '" + |
|
126 | (String) loaders.get(i) + |
|
127 | "' for TurbineFactoryService", x); |
|
128 | 0 | } |
129 | } |
|
130 | } |
|
131 | ||
132 | String key,factory; |
|
133 | 75 | for (Iterator i = conf.getKeys(OBJECT_FACTORY); i.hasNext();) |
134 | { |
|
135 | 0 | key = (String) i.next(); |
136 | 0 | factory = conf.getString(key); |
137 | ||
138 | /* |
|
139 | * Store the factory to the table as a string and |
|
140 | * instantiate it by using the service when needed. |
|
141 | */ |
|
142 | 0 | objectFactories.put( |
143 | key.substring(OBJECT_FACTORY.length()), factory); |
|
144 | } |
|
145 | } |
|
146 | 50 | setInit(true); |
147 | 50 | } |
148 | ||
149 | /** |
|
150 | * Gets an instance of a named class. |
|
151 | * |
|
152 | * @param className the name of the class. |
|
153 | * @return the instance. |
|
154 | * @throws TurbineException if instantiation fails. |
|
155 | */ |
|
156 | public Object getInstance(String className) |
|
157 | throws TurbineException |
|
158 | { |
|
159 | 324 | if (className == null) |
160 | { |
|
161 | 0 | throw new TurbineException( |
162 | new NullPointerException("String className")); |
|
163 | } |
|
164 | ||
165 | 324 | Factory factory = getFactory(className); |
166 | 324 | if (factory == null) |
167 | { |
|
168 | Class clazz; |
|
169 | try |
|
170 | { |
|
171 | 324 | clazz = loadClass(className); |
172 | 162 | } |
173 | 0 | catch (ClassNotFoundException x) |
174 | { |
|
175 | 0 | throw new TurbineException( |
176 | "Instantiation failed for class " + className, x); |
|
177 | 162 | } |
178 | 324 | return getInstance(clazz); |
179 | } |
|
180 | else |
|
181 | { |
|
182 | 0 | return factory.getInstance(); |
183 | } |
|
184 | } |
|
185 | ||
186 | /** |
|
187 | * Gets an instance of a named class using a specified class loader. |
|
188 | * |
|
189 | * <p>Class loaders are supported only if the isLoaderSupported |
|
190 | * method returns true. Otherwise the loader parameter is ignored. |
|
191 | * |
|
192 | * @param className the name of the class. |
|
193 | * @param loader the class loader. |
|
194 | * @return the instance. |
|
195 | * @throws TurbineException if instantiation fails. |
|
196 | */ |
|
197 | public Object getInstance(String className, |
|
198 | ClassLoader loader) |
|
199 | throws TurbineException |
|
200 | { |
|
201 | 0 | if (className == null) |
202 | { |
|
203 | 0 | throw new TurbineException( |
204 | new NullPointerException("String className")); |
|
205 | } |
|
206 | ||
207 | 0 | Factory factory = getFactory(className); |
208 | 0 | if (factory == null) |
209 | { |
|
210 | 0 | if (loader != null) |
211 | { |
|
212 | Class clazz; |
|
213 | try |
|
214 | { |
|
215 | 0 | clazz = loadClass(className, loader); |
216 | } |
|
217 | 0 | catch (ClassNotFoundException x) |
218 | { |
|
219 | 0 | throw new TurbineException( |
220 | "Instantiation failed for class " + className, x); |
|
221 | 0 | } |
222 | 0 | return getInstance(clazz); |
223 | } |
|
224 | else |
|
225 | { |
|
226 | 0 | return getInstance(className); |
227 | } |
|
228 | } |
|
229 | else |
|
230 | { |
|
231 | 0 | return factory.getInstance(loader); |
232 | } |
|
233 | } |
|
234 | ||
235 | /** |
|
236 | * Gets an instance of a named class. |
|
237 | * Parameters for its constructor are given as an array of objects, |
|
238 | * primitive types must be wrapped with a corresponding class. |
|
239 | * |
|
240 | * @param className the name of the class. |
|
241 | * @param params an array containing the parameters of the constructor. |
|
242 | * @param signature an array containing the signature of the constructor. |
|
243 | * @return the instance. |
|
244 | * @throws TurbineException if instantiation fails. |
|
245 | */ |
|
246 | public Object getInstance(String className, |
|
247 | Object[] params, |
|
248 | String[] signature) |
|
249 | throws TurbineException |
|
250 | { |
|
251 | 20 | if (className == null) |
252 | { |
|
253 | 0 | throw new TurbineException( |
254 | new NullPointerException("String className")); |
|
255 | } |
|
256 | ||
257 | 20 | Factory factory = getFactory(className); |
258 | 20 | if (factory == null) |
259 | { |
|
260 | Class clazz; |
|
261 | try |
|
262 | { |
|
263 | 20 | clazz = loadClass(className); |
264 | 10 | } |
265 | 0 | catch (ClassNotFoundException x) |
266 | { |
|
267 | 0 | throw new TurbineException( |
268 | "Instantiation failed for class " + className, x); |
|
269 | 10 | } |
270 | 20 | return getInstance(clazz, params, signature); |
271 | } |
|
272 | else |
|
273 | { |
|
274 | 0 | return factory.getInstance(params, signature); |
275 | } |
|
276 | } |
|
277 | ||
278 | /** |
|
279 | * Gets an instance of a named class using a specified class loader. |
|
280 | * Parameters for its constructor are given as an array of objects, |
|
281 | * primitive types must be wrapped with a corresponding class. |
|
282 | * |
|
283 | * <p>Class loaders are supported only if the isLoaderSupported |
|
284 | * method returns true. Otherwise the loader parameter is ignored. |
|
285 | * |
|
286 | * @param className the name of the class. |
|
287 | * @param loader the class loader. |
|
288 | * @param params an array containing the parameters of the constructor. |
|
289 | * @param signature an array containing the signature of the constructor. |
|
290 | * @return the instance. |
|
291 | * @throws TurbineException if instantiation fails. |
|
292 | */ |
|
293 | public Object getInstance(String className, |
|
294 | ClassLoader loader, |
|
295 | Object[] params, |
|
296 | String[] signature) |
|
297 | throws TurbineException |
|
298 | { |
|
299 | 0 | if (className == null) |
300 | { |
|
301 | 0 | throw new TurbineException( |
302 | new NullPointerException("String className")); |
|
303 | } |
|
304 | ||
305 | 0 | Factory factory = getFactory(className); |
306 | 0 | if (factory == null) |
307 | { |
|
308 | 0 | if (loader != null) |
309 | { |
|
310 | Class clazz; |
|
311 | try |
|
312 | { |
|
313 | 0 | clazz = loadClass(className, loader); |
314 | } |
|
315 | 0 | catch (ClassNotFoundException x) |
316 | { |
|
317 | 0 | throw new TurbineException( |
318 | "Instantiation failed for class " + className, x); |
|
319 | 0 | } |
320 | 0 | return getInstance(clazz, params, signature); |
321 | } |
|
322 | else |
|
323 | { |
|
324 | 0 | return getInstance(className, params, signature); |
325 | } |
|
326 | } |
|
327 | else |
|
328 | { |
|
329 | 0 | return factory.getInstance(loader, params, signature); |
330 | } |
|
331 | } |
|
332 | ||
333 | /** |
|
334 | * Tests if specified class loaders are supported for a named class. |
|
335 | * |
|
336 | * @param className the name of the class. |
|
337 | * @return true if class loaders are supported, false otherwise. |
|
338 | * @throws TurbineException if test fails. |
|
339 | */ |
|
340 | public boolean isLoaderSupported(String className) |
|
341 | throws TurbineException |
|
342 | { |
|
343 | 0 | Factory factory = getFactory(className); |
344 | 0 | return factory != null ? |
345 | factory.isLoaderSupported() : true; |
|
346 | } |
|
347 | ||
348 | /** |
|
349 | * Gets an instance of a specified class. |
|
350 | * |
|
351 | * @param clazz the class. |
|
352 | * @return the instance. |
|
353 | * @throws TurbineException if instantiation fails. |
|
354 | */ |
|
355 | protected Object getInstance(Class clazz) |
|
356 | throws TurbineException |
|
357 | { |
|
358 | try |
|
359 | { |
|
360 | 324 | return clazz.newInstance(); |
361 | } |
|
362 | 0 | catch (Exception x) |
363 | { |
|
364 | 0 | throw new TurbineException( |
365 | "Instantiation failed for " + clazz.getName(), x); |
|
366 | } |
|
367 | } |
|
368 | ||
369 | /** |
|
370 | * Gets an instance of a specified class. |
|
371 | * Parameters for its constructor are given as an array of objects, |
|
372 | * primitive types must be wrapped with a corresponding class. |
|
373 | * |
|
374 | * @param clazz the class. |
|
375 | * @param params an array containing the parameters of the constructor. |
|
376 | * @param signature an array containing the signature of the constructor. |
|
377 | * @return the instance. |
|
378 | * @throws TurbineException if instantiation fails. |
|
379 | */ |
|
380 | protected Object getInstance(Class clazz, |
|
381 | Object params[], |
|
382 | String signature[]) |
|
383 | throws TurbineException |
|
384 | { |
|
385 | /* Try to construct. */ |
|
386 | try |
|
387 | { |
|
388 | 20 | Class[] sign = getSignature(clazz, params, signature); |
389 | 20 | return clazz.getConstructor(sign).newInstance(params); |
390 | } |
|
391 | 0 | catch (Exception x) |
392 | { |
|
393 | 0 | throw new TurbineException( |
394 | "Instantiation failed for " + clazz.getName(), x); |
|
395 | } |
|
396 | } |
|
397 | ||
398 | /** |
|
399 | * Gets the signature classes for parameters of a method of a class. |
|
400 | * |
|
401 | * @param clazz the class. |
|
402 | * @param params an array containing the parameters of the method. |
|
403 | * @param signature an array containing the signature of the method. |
|
404 | * @return an array of signature classes. Note that in some cases |
|
405 | * objects in the parameter array can be switched to the context |
|
406 | * of a different class loader. |
|
407 | * @throws ClassNotFoundException if any of the classes is not found. |
|
408 | */ |
|
409 | public Class[] getSignature(Class clazz, |
|
410 | Object params[], |
|
411 | String signature[]) |
|
412 | throws ClassNotFoundException |
|
413 | { |
|
414 | 20 | if (signature != null) |
415 | { |
|
416 | /* We have parameters. */ |
|
417 | ClassLoader tempLoader; |
|
418 | 20 | ClassLoader loader = clazz.getClassLoader(); |
419 | 20 | Class[] sign = new Class[signature.length]; |
420 | 60 | for (int i = 0; i < signature.length; i++) |
421 | { |
|
422 | /* Check primitive types. */ |
|
423 | 40 | sign[i] = getPrimitiveClass(signature[i]); |
424 | 40 | if (sign[i] == null) |
425 | { |
|
426 | /* Not a primitive one, continue building. */ |
|
427 | 40 | if (loader != null) |
428 | { |
|
429 | /* Use the class loader of the target object. */ |
|
430 | 40 | sign[i] = loader.loadClass(signature[i]); |
431 | 40 | tempLoader = sign[i].getClassLoader(); |
432 | 40 | if ((params[i] != null) && |
433 | (tempLoader != null) && |
|
434 | !tempLoader.equals(params[i].getClass().getClassLoader())) |
|
435 | { |
|
436 | /* |
|
437 | * The class uses a different class loader, |
|
438 | * switch the parameter. |
|
439 | */ |
|
440 | 0 | params[i] = switchObjectContext(params[i], loader); |
441 | } |
|
442 | } |
|
443 | else |
|
444 | { |
|
445 | /* Use the default class loader. */ |
|
446 | 0 | sign[i] = loadClass(signature[i]); |
447 | } |
|
448 | } |
|
449 | } |
|
450 | 20 | return sign; |
451 | } |
|
452 | else |
|
453 | { |
|
454 | 0 | return null; |
455 | } |
|
456 | } |
|
457 | ||
458 | /** |
|
459 | * Switches an object into the context of a different class loader. |
|
460 | * |
|
461 | * @param object an object to switch. |
|
462 | * @param loader the loader of the new context. |
|
463 | */ |
|
464 | protected Object switchObjectContext(Object object, |
|
465 | ClassLoader loader) |
|
466 | { |
|
467 | 0 | ByteArrayOutputStream bout = |
468 | new ByteArrayOutputStream(); |
|
469 | try |
|
470 | { |
|
471 | 0 | ObjectOutputStream out = |
472 | new ObjectOutputStream(bout); |
|
473 | 0 | out.writeObject(object); |
474 | 0 | out.flush(); |
475 | } |
|
476 | 0 | catch (Exception x) |
477 | { |
|
478 | 0 | return object; |
479 | 0 | } |
480 | ||
481 | try |
|
482 | { |
|
483 | 0 | ByteArrayInputStream bin = |
484 | new ByteArrayInputStream(bout.toByteArray()); |
|
485 | 0 | ObjectInputStreamForContext in = |
486 | new ObjectInputStreamForContext(bin, loader); |
|
487 | ||
488 | 0 | return in.readObject(); |
489 | } |
|
490 | 0 | catch (Exception x) |
491 | { |
|
492 | 0 | return object; |
493 | } |
|
494 | } |
|
495 | ||
496 | /** |
|
497 | * Loads the named class using the default class loader. |
|
498 | * |
|
499 | * @param className the name of the class to load. |
|
500 | * @return the loaded class. |
|
501 | * @throws ClassNotFoundException if the class was not found. |
|
502 | */ |
|
503 | protected Class loadClass(String className) |
|
504 | throws ClassNotFoundException |
|
505 | { |
|
506 | 344 | ClassLoader loader = this.getClass().getClassLoader(); |
507 | try |
|
508 | { |
|
509 | 344 | return loader != null ? |
510 | loader.loadClass(className) : Class.forName(className); |
|
511 | } |
|
512 | 0 | catch (ClassNotFoundException x) |
513 | { |
|
514 | /* Go through additional loaders. */ |
|
515 | 0 | for (Iterator i = classLoaders.iterator(); i.hasNext();) |
516 | { |
|
517 | try |
|
518 | { |
|
519 | 0 | return ((ClassLoader) i.next()).loadClass(className); |
520 | } |
|
521 | 0 | catch (ClassNotFoundException xx) |
522 | { |
|
523 | 0 | } |
524 | } |
|
525 | ||
526 | /* Give up. */ |
|
527 | 0 | throw x; |
528 | } |
|
529 | } |
|
530 | ||
531 | /** |
|
532 | * Loads the named class using a specified class loader. |
|
533 | * |
|
534 | * @param className the name of the class to load. |
|
535 | * @param loader the loader to use. |
|
536 | * @return the loaded class. |
|
537 | * @throws ClassNotFoundException if the class was not found. |
|
538 | */ |
|
539 | protected Class loadClass(String className, |
|
540 | ClassLoader loader) |
|
541 | throws ClassNotFoundException |
|
542 | { |
|
543 | 0 | return loader != null ? |
544 | loader.loadClass(className) : loadClass(className); |
|
545 | } |
|
546 | ||
547 | /** |
|
548 | * Gets a customized factory for a named class. |
|
549 | * |
|
550 | * @param className the name of the class to load. |
|
551 | * @return the factory or null if not specified. |
|
552 | * @throws TurbineException if instantiation of the factory fails. |
|
553 | */ |
|
554 | protected Factory getFactory(String className) |
|
555 | throws TurbineException |
|
556 | { |
|
557 | 344 | HashMap factories = objectFactories; |
558 | 344 | Object factory = factories.get(className); |
559 | 344 | if (factory != null) |
560 | { |
|
561 | 0 | if (factory instanceof String) |
562 | { |
|
563 | /* Not yet instantiated... */ |
|
564 | try |
|
565 | { |
|
566 | 0 | factory = (Factory) getInstance((String) factory); |
567 | 0 | ((Factory) factory).init(className); |
568 | } |
|
569 | 0 | catch (TurbineException x) |
570 | { |
|
571 | 0 | throw x; |
572 | } |
|
573 | 0 | catch (ClassCastException x) |
574 | { |
|
575 | 0 | throw new TurbineException( |
576 | "Incorrect factory " + (String) factory + |
|
577 | " for class " + className, x); |
|
578 | 0 | } |
579 | 0 | factories = (HashMap) factories.clone(); |
580 | 0 | factories.put(className, factory); |
581 | 0 | objectFactories = factories; |
582 | } |
|
583 | 0 | return (Factory) factory; |
584 | } |
|
585 | else |
|
586 | { |
|
587 | 344 | return null; |
588 | } |
|
589 | } |
|
590 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |