1 package org.apache.turbine.services.factory;
2
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2001 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" and
29 * "Apache Turbine" must not be used to endorse or promote products
30 * derived from this software without prior written permission. For
31 * written permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * "Apache Turbine", nor may "Apache" appear in their name, without
35 * prior written permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 */
56
57 import java.io.ByteArrayInputStream;
58 import java.io.ByteArrayOutputStream;
59 import java.io.ObjectOutputStream;
60 import java.util.ArrayList;
61 import java.util.HashMap;
62 import java.util.Iterator;
63 import java.util.Vector;
64 import org.apache.commons.configuration.Configuration;
65 import org.apache.turbine.services.InitializationException;
66 import org.apache.turbine.services.TurbineBaseService;
67 import org.apache.turbine.util.TurbineException;
68 import org.apache.turbine.util.pool.ObjectInputStreamForContext;
69
70 /***
71 * The Factory Service instantiates objects using specified
72 * class loaders. If none is specified, the default one
73 * will be used.
74 *
75 * @author <a href="mailto:ilkka.priha@simsoft.fi">Ilkka Priha</a>
76 * @version $Id: TurbineFactoryService.java,v 1.4 2002/07/11 16:53:28 mpoeschl Exp $
77 */
78 public class TurbineFactoryService
79 extends TurbineBaseService
80 implements FactoryService
81 {
82 /***
83 * The property specifying a set of additional class loaders.
84 */
85 public static final String CLASS_LOADERS = "class.loaders";
86
87 /***
88 * The property prefix specifying additional object factories.
89 */
90 public static final String OBJECT_FACTORY = "factory.";
91
92 /***
93 * Primitive classes for reflection of constructors.
94 */
95 private static HashMap primitiveClasses;
96
97 {
98 primitiveClasses = new HashMap(8);
99 primitiveClasses.put(Boolean.TYPE.toString(), Boolean.TYPE);
100 primitiveClasses.put(Character.TYPE.toString(), Character.TYPE);
101 primitiveClasses.put(Byte.TYPE.toString(), Byte.TYPE);
102 primitiveClasses.put(Short.TYPE.toString(), Short.TYPE);
103 primitiveClasses.put(Integer.TYPE.toString(), Integer.TYPE);
104 primitiveClasses.put(Long.TYPE.toString(), Long.TYPE);
105 primitiveClasses.put(Float.TYPE.toString(), Float.TYPE);
106 primitiveClasses.put(Double.TYPE.toString(), Double.TYPE);
107 }
108
109 /***
110 * Additional class loaders.
111 */
112 private ArrayList classLoaders = new ArrayList();
113
114 /***
115 * Customized object factories.
116 */
117 private HashMap objectFactories = new HashMap();
118
119 /***
120 * Gets the class of a primitive type.
121 *
122 * @param type a primitive type.
123 * @return the corresponding class, or null.
124 */
125 protected static Class getPrimitiveClass(String type)
126 {
127 return (Class) primitiveClasses.get(type);
128 }
129
130 /***
131 * Constructs a Factory Service.
132 */
133 public TurbineFactoryService()
134 {
135 }
136
137 /***
138 * Initializes the service by loading default class loaders
139 * and customized object factories.
140 *
141 * @throws InitializationException if initialization fails.
142 */
143 public void init() throws InitializationException
144 {
145 Configuration conf = getConfiguration();
146 if (conf != null)
147 {
148 Vector loaders = conf.getVector(CLASS_LOADERS);
149 if (loaders != null)
150 {
151 for (int i = 0; i < loaders.size(); i++)
152 {
153 try
154 {
155 classLoaders.add(
156 loadClass((String) loaders.get(i)).newInstance());
157 }
158 catch (Exception x)
159 {
160 throw new InitializationException(
161 "No such class loader '" +
162 (String) loaders.get(i) +
163 "' for TurbinbeFactoryService",x);
164 }
165 }
166 }
167
168 String key,factory;
169 for (Iterator i = conf.getKeys(OBJECT_FACTORY); i.hasNext();)
170 {
171 key = (String) i.next();
172 factory = conf.getString(key);
173
174 /*
175 * Store the factory to the table as a string and
176 * instantiate it by using the service when needed.
177 */
178 objectFactories.put(
179 key.substring(OBJECT_FACTORY.length()),factory);
180 }
181 }
182 setInit(true);
183 }
184
185 /***
186 * Gets an instance of a named class.
187 *
188 * @param className the name of the class.
189 * @return the instance.
190 * @throws TurbineException if instantiation fails.
191 */
192 public Object getInstance(String className)
193 throws TurbineException
194 {
195 if (className == null)
196 {
197 throw new TurbineException(
198 new NullPointerException("String className"));
199 }
200
201 Factory factory = getFactory(className);
202 if (factory == null)
203 {
204 Class clazz;
205 try
206 {
207 clazz = loadClass(className);
208 }
209 catch (ClassNotFoundException x)
210 {
211 throw new TurbineException(
212 "Instantiation failed for class " + className,x);
213 }
214 return getInstance(clazz);
215 }
216 else
217 {
218 return factory.getInstance();
219 }
220 }
221
222 /***
223 * Gets an instance of a named class using a specified class loader.
224 *
225 * <p>Class loaders are supported only if the isLoaderSupported
226 * method returns true. Otherwise the loader parameter is ignored.
227 *
228 * @param className the name of the class.
229 * @param loader the class loader.
230 * @return the instance.
231 * @throws TurbineException if instantiation fails.
232 */
233 public Object getInstance(String className,
234 ClassLoader loader)
235 throws TurbineException
236 {
237 if (className == null)
238 {
239 throw new TurbineException(
240 new NullPointerException("String className"));
241 }
242
243 Factory factory = getFactory(className);
244 if (factory == null)
245 {
246 if (loader != null)
247 {
248 Class clazz;
249 try
250 {
251 clazz = loadClass(className,loader);
252 }
253 catch (ClassNotFoundException x)
254 {
255 throw new TurbineException(
256 "Instantiation failed for class " + className,x);
257 }
258 return getInstance(clazz);
259 }
260 else
261 {
262 return getInstance(className);
263 }
264 }
265 else
266 {
267 return factory.getInstance(loader);
268 }
269 }
270
271 /***
272 * Gets an instance of a named class.
273 * Parameters for its constructor are given as an array of objects,
274 * primitive types must be wrapped with a corresponding class.
275 *
276 * @param className the name of the class.
277 * @param params an array containing the parameters of the constructor.
278 * @param signature an array containing the signature of the constructor.
279 * @return the instance.
280 * @throws TurbineException if instantiation fails.
281 */
282 public Object getInstance(String className,
283 Object[] params,
284 String[] signature)
285 throws TurbineException
286 {
287 if (className == null)
288 {
289 throw new TurbineException(
290 new NullPointerException("String className"));
291 }
292
293 Factory factory = getFactory(className);
294 if (factory == null)
295 {
296 Class clazz;
297 try
298 {
299 clazz = loadClass(className);
300 }
301 catch (ClassNotFoundException x)
302 {
303 throw new TurbineException(
304 "Instantiation failed for class " + className,x);
305 }
306 return getInstance(clazz,params,signature);
307 }
308 else
309 {
310 return factory.getInstance(params,signature);
311 }
312 }
313
314 /***
315 * Gets an instance of a named class using a specified class loader.
316 * Parameters for its constructor are given as an array of objects,
317 * primitive types must be wrapped with a corresponding class.
318 *
319 * <p>Class loaders are supported only if the isLoaderSupported
320 * method returns true. Otherwise the loader parameter is ignored.
321 *
322 * @param className the name of the class.
323 * @param loader the class loader.
324 * @param params an array containing the parameters of the constructor.
325 * @param signature an array containing the signature of the constructor.
326 * @return the instance.
327 * @throws TurbineException if instantiation fails.
328 */
329 public Object getInstance(String className,
330 ClassLoader loader,
331 Object[] params,
332 String[] signature)
333 throws TurbineException
334 {
335 if (className == null)
336 {
337 throw new TurbineException(
338 new NullPointerException("String className"));
339 }
340
341 Factory factory = getFactory(className);
342 if (factory == null)
343 {
344 if (loader != null)
345 {
346 Class clazz;
347 try
348 {
349 clazz = loadClass(className,loader);
350 }
351 catch (ClassNotFoundException x)
352 {
353 throw new TurbineException(
354 "Instantiation failed for class " + className,x);
355 }
356 return getInstance(clazz,params,signature);
357 }
358 else
359 {
360 return getInstance(className,params,signature);
361 }
362 }
363 else
364 {
365 return factory.getInstance(loader,params,signature);
366 }
367 }
368
369 /***
370 * Tests if specified class loaders are supported for a named class.
371 *
372 * @param className the name of the class.
373 * @return true if class loaders are supported, false otherwise.
374 * @throws TurbineException if test fails.
375 */
376 public boolean isLoaderSupported(String className)
377 throws TurbineException
378 {
379 Factory factory = getFactory(className);
380 return factory != null ?
381 factory.isLoaderSupported() : true;
382 }
383
384 /***
385 * Gets an instance of a specified class.
386 *
387 * @param clazz the class.
388 * @return the instance.
389 * @throws TurbineException if instantiation fails.
390 */
391 protected Object getInstance(Class clazz)
392 throws TurbineException
393 {
394 try
395 {
396 return clazz.newInstance();
397 }
398 catch (Exception x)
399 {
400 throw new TurbineException(
401 "Instantiation failed for " + clazz.getName(),x);
402 }
403 }
404
405 /***
406 * Gets an instance of a specified class.
407 * Parameters for its constructor are given as an array of objects,
408 * primitive types must be wrapped with a corresponding class.
409 *
410 * @param clazz the class.
411 * @param params an array containing the parameters of the constructor.
412 * @param signature an array containing the signature of the constructor.
413 * @return the instance.
414 * @throws TurbineException if instantiation fails.
415 */
416 protected Object getInstance(Class clazz,
417 Object params[],
418 String signature[])
419 throws TurbineException
420 {
421 /* Try to construct. */
422 try
423 {
424 Class[] sign = getSignature(clazz,params,signature);
425 return clazz.getConstructor(sign).newInstance(params);
426 }
427 catch (Exception x)
428 {
429 throw new TurbineException(
430 "Instantiation failed for " + clazz.getName(),x);
431 }
432 }
433
434 /***
435 * Gets the signature classes for parameters of a method of a class.
436 *
437 * @param clazz the class.
438 * @param params an array containing the parameters of the method.
439 * @param signature an array containing the signature of the method.
440 * @return an array of signature classes. Note that in some cases
441 * objects in the parameter array can be switched to the context
442 * of a different class loader.
443 * @throws ClassNotFoundException if any of the classes is not found.
444 */
445 protected Class[] getSignature(Class clazz,
446 Object params[],
447 String signature[])
448 throws ClassNotFoundException
449 {
450 if (signature != null)
451 {
452 /* We have parameters. */
453 ClassLoader tempLoader;
454 ClassLoader loader = clazz.getClassLoader();
455 Class[] sign = new Class[signature.length];
456 for (int i= 0; i < signature.length; i++)
457 {
458 /* Check primitive types. */
459 sign[i] = getPrimitiveClass(signature[i]);
460 if (sign[i] == null)
461 {
462 /* Not a primitive one, continue building. */
463 if (loader != null)
464 {
465 /* Use the class loader of the target object. */
466 sign[i] = loader.loadClass(signature[i]);
467 tempLoader = sign[i].getClassLoader();
468 if ((params[i] != null) &&
469 (tempLoader != null) &&
470 !tempLoader.equals(params[i].getClass().getClassLoader()))
471 {
472 /*
473 * The class uses a different class loader,
474 * switch the parameter.
475 */
476 params[i] = switchObjectContext(params[i],loader);
477 }
478 }
479 else
480 {
481 /* Use the default class loader. */
482 sign[i] = loadClass(signature[i]);
483 }
484 }
485 }
486 return sign;
487 }
488 else
489 {
490 return null;
491 }
492 }
493
494 /***
495 * Switches an object into the context of a different class loader.
496 *
497 * @param object an object to switch.
498 * @param loader the loader of the new context.
499 */
500 protected Object switchObjectContext(Object object,
501 ClassLoader loader)
502 {
503 ByteArrayOutputStream bout =
504 new ByteArrayOutputStream();
505 try
506 {
507 ObjectOutputStream out =
508 new ObjectOutputStream(bout);
509 out.writeObject(object);
510 out.flush();
511 }
512 catch (Exception x)
513 {
514 return object;
515 }
516
517 try
518 {
519 ByteArrayInputStream bin =
520 new ByteArrayInputStream(bout.toByteArray());
521 ObjectInputStreamForContext in =
522 new ObjectInputStreamForContext(bin,loader);
523
524 return in.readObject();
525 }
526 catch (Exception x)
527 {
528 return object;
529 }
530 }
531
532 /***
533 * Loads the named class using the default class loader.
534 *
535 * @param className the name of the class to load.
536 * @return the loaded class.
537 * @throws ClassNotFoundException if the class was not found.
538 */
539 protected Class loadClass(String className)
540 throws ClassNotFoundException
541 {
542 ClassLoader loader = this.getClass().getClassLoader();
543 try
544 {
545 return loader != null ?
546 loader.loadClass(className) : Class.forName(className);
547 }
548 catch (ClassNotFoundException x)
549 {
550 /* Go through additional loaders. */
551 for (Iterator i = classLoaders.iterator(); i.hasNext();)
552 {
553 try
554 {
555 return ((ClassLoader) i.next()).loadClass(className);
556 }
557 catch (ClassNotFoundException xx) { }
558 }
559
560 /* Give up. */
561 throw x;
562 }
563 }
564
565 /***
566 * Loads the named class using a specified class loader.
567 *
568 * @param className the name of the class to load.
569 * @param loader the loader to use.
570 * @return the loaded class.
571 * @throws ClassNotFoundException if the class was not found.
572 */
573 protected Class loadClass(String className,
574 ClassLoader loader)
575 throws ClassNotFoundException
576 {
577 return loader != null ?
578 loader.loadClass(className) : loadClass(className);
579 }
580
581 /***
582 * Gets a customized factory for a named class.
583 *
584 * @param className the name of the class to load.
585 * @return the factory or null if not specified.
586 * @throws TurbineException if instantiation of the factory fails.
587 */
588 protected Factory getFactory(String className)
589 throws TurbineException
590 {
591 HashMap factories = objectFactories;
592 Object factory = factories.get(className);
593 if (factory != null)
594 {
595 if (factory instanceof String)
596 {
597 /* Not yet instantiated... */
598 try
599 {
600 factory = (Factory) getInstance((String) factory);
601 ((Factory) factory).init(className);
602 }
603 catch (TurbineException x)
604 {
605 throw x;
606 }
607 catch (ClassCastException x)
608 {
609 throw new TurbineException(
610 "Incorrect factory " + (String) factory +
611 " for class " + className,x);
612 }
613 factories = (HashMap) factories.clone();
614 factories.put(className,factory);
615 objectFactories = factories;
616 }
617 return (Factory) factory;
618 }
619 else
620 {
621 return null;
622 }
623 }
624 }
This page was automatically generated by Maven