KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > turbine > services > factory > TurbineFactoryService


1 package org.apache.turbine.services.factory;
2
3 /*
4  * Copyright 2001-2004 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 JavaDoc;
20 import java.io.ByteArrayOutputStream JavaDoc;
21 import java.io.ObjectOutputStream JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
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,v 1.9.2.3 2004/08/16 22:57:48 henning Exp $
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 JavaDoc CLASS_LOADERS = "class.loaders";
50
51     /**
52      * The property prefix specifying additional object factories.
53      */

54     public static final String JavaDoc OBJECT_FACTORY = "factory.";
55
56     /**
57      * Primitive classes for reflection of constructors.
58      */

59     private static HashMap JavaDoc primitiveClasses;
60
61     {
62         primitiveClasses = new HashMap JavaDoc(8);
63         primitiveClasses.put(Boolean.TYPE.toString(), Boolean.TYPE);
64         primitiveClasses.put(Character.TYPE.toString(), Character.TYPE);
65         primitiveClasses.put(Byte.TYPE.toString(), Byte.TYPE);
66         primitiveClasses.put(Short.TYPE.toString(), Short.TYPE);
67         primitiveClasses.put(Integer.TYPE.toString(), Integer.TYPE);
68         primitiveClasses.put(Long.TYPE.toString(), Long.TYPE);
69         primitiveClasses.put(Float.TYPE.toString(), Float.TYPE);
70         primitiveClasses.put(Double.TYPE.toString(), Double.TYPE);
71     }
72
73     /**
74      * Additional class loaders.
75      */

76     private ArrayList JavaDoc classLoaders = new ArrayList JavaDoc();
77
78     /**
79      * Customized object factories.
80      */

81     private HashMap JavaDoc objectFactories = new HashMap JavaDoc();
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 JavaDoc getPrimitiveClass(String JavaDoc type)
90     {
91         return (Class JavaDoc) primitiveClasses.get(type);
92     }
93
94     /**
95      * Constructs a Factory Service.
96      */

97     public TurbineFactoryService()
98     {
99     }
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         Configuration conf = getConfiguration();
110         if (conf != null)
111         {
112             List JavaDoc loaders = conf.getList(CLASS_LOADERS);
113             if (loaders != null)
114             {
115                 for (int i = 0; i < loaders.size(); i++)
116                 {
117                     try
118                     {
119                         classLoaders.add(
120                                 loadClass((String JavaDoc) loaders.get(i)).newInstance());
121                     }
122                     catch (Exception JavaDoc x)
123                     {
124                         throw new InitializationException(
125                                 "No such class loader '" +
126                                 (String JavaDoc) loaders.get(i) +
127                                 "' for TurbineFactoryService", x);
128                     }
129                 }
130             }
131
132             String JavaDoc key,factory;
133             for (Iterator JavaDoc i = conf.getKeys(OBJECT_FACTORY); i.hasNext();)
134             {
135                 key = (String JavaDoc) i.next();
136                 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                 objectFactories.put(
143                         key.substring(OBJECT_FACTORY.length()), factory);
144             }
145         }
146         setInit(true);
147     }
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 JavaDoc getInstance(String JavaDoc className)
157             throws TurbineException
158     {
159         if (className == null)
160         {
161             throw new TurbineException(
162                     new NullPointerException JavaDoc("String className"));
163         }
164
165         Factory factory = getFactory(className);
166         if (factory == null)
167         {
168             Class JavaDoc clazz;
169             try
170             {
171                 clazz = loadClass(className);
172             }
173             catch (ClassNotFoundException JavaDoc x)
174             {
175                 throw new TurbineException(
176                         "Instantiation failed for class " + className, x);
177             }
178             return getInstance(clazz);
179         }
180         else
181         {
182             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 JavaDoc getInstance(String JavaDoc className,
198             ClassLoader JavaDoc loader)
199             throws TurbineException
200     {
201         if (className == null)
202         {
203             throw new TurbineException(
204                     new NullPointerException JavaDoc("String className"));
205         }
206
207         Factory factory = getFactory(className);
208         if (factory == null)
209         {
210             if (loader != null)
211             {
212                 Class JavaDoc clazz;
213                 try
214                 {
215                     clazz = loadClass(className, loader);
216                 }
217                 catch (ClassNotFoundException JavaDoc x)
218                 {
219                     throw new TurbineException(
220                             "Instantiation failed for class " + className, x);
221                 }
222                 return getInstance(clazz);
223             }
224             else
225             {
226                 return getInstance(className);
227             }
228         }
229         else
230         {
231             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 JavaDoc getInstance(String JavaDoc className,
247             Object JavaDoc[] params,
248             String JavaDoc[] signature)
249             throws TurbineException
250     {
251         if (className == null)
252         {
253             throw new TurbineException(
254                     new NullPointerException JavaDoc("String className"));
255         }
256
257         Factory factory = getFactory(className);
258         if (factory == null)
259         {
260             Class JavaDoc clazz;
261             try
262             {
263                 clazz = loadClass(className);
264             }
265             catch (ClassNotFoundException JavaDoc x)
266             {
267                 throw new TurbineException(
268                         "Instantiation failed for class " + className, x);
269             }
270             return getInstance(clazz, params, signature);
271         }
272         else
273         {
274             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 JavaDoc getInstance(String JavaDoc className,
294             ClassLoader JavaDoc loader,
295             Object JavaDoc[] params,
296             String JavaDoc[] signature)
297             throws TurbineException
298     {
299         if (className == null)
300         {
301             throw new TurbineException(
302                     new NullPointerException JavaDoc("String className"));
303         }
304
305         Factory factory = getFactory(className);
306         if (factory == null)
307         {
308             if (loader != null)
309             {
310                 Class JavaDoc clazz;
311                 try
312                 {
313                     clazz = loadClass(className, loader);
314                 }
315                 catch (ClassNotFoundException JavaDoc x)
316                 {
317                     throw new TurbineException(
318                             "Instantiation failed for class " + className, x);
319                 }
320                 return getInstance(clazz, params, signature);
321             }
322             else
323             {
324                 return getInstance(className, params, signature);
325             }
326         }
327         else
328         {
329             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 JavaDoc className)
341             throws TurbineException
342     {
343         Factory factory = getFactory(className);
344         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 JavaDoc getInstance(Class JavaDoc clazz)
356             throws TurbineException
357     {
358         try
359         {
360             return clazz.newInstance();
361         }
362         catch (Exception JavaDoc x)
363         {
364             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 JavaDoc getInstance(Class JavaDoc clazz,
381             Object JavaDoc params[],
382             String JavaDoc signature[])
383             throws TurbineException
384     {
385         /* Try to construct. */
386         try
387         {
388             Class JavaDoc[] sign = getSignature(clazz, params, signature);
389             return clazz.getConstructor(sign).newInstance(params);
390         }
391         catch (Exception JavaDoc x)
392         {
393             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 JavaDoc[] getSignature(Class JavaDoc clazz,
410             Object JavaDoc params[],
411             String JavaDoc signature[])
412             throws ClassNotFoundException JavaDoc
413     {
414         if (signature != null)
415         {
416             /* We have parameters. */
417             ClassLoader JavaDoc tempLoader;
418             ClassLoader JavaDoc loader = clazz.getClassLoader();
419             Class JavaDoc[] sign = new Class JavaDoc[signature.length];
420             for (int i = 0; i < signature.length; i++)
421             {
422                 /* Check primitive types. */
423                 sign[i] = getPrimitiveClass(signature[i]);
424                 if (sign[i] == null)
425                 {
426                     /* Not a primitive one, continue building. */
427                     if (loader != null)
428                     {
429                         /* Use the class loader of the target object. */
430                         sign[i] = loader.loadClass(signature[i]);
431                         tempLoader = sign[i].getClassLoader();
432                         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                             params[i] = switchObjectContext(params[i], loader);
441                         }
442                     }
443                     else
444                     {
445                         /* Use the default class loader. */
446                         sign[i] = loadClass(signature[i]);
447                     }
448                 }
449             }
450             return sign;
451         }
452         else
453         {
454             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 JavaDoc switchObjectContext(Object JavaDoc object,
465             ClassLoader JavaDoc loader)
466     {
467         ByteArrayOutputStream JavaDoc bout =
468                 new ByteArrayOutputStream JavaDoc();
469         try
470         {
471             ObjectOutputStream JavaDoc out =
472                     new ObjectOutputStream JavaDoc(bout);
473             out.writeObject(object);
474             out.flush();
475         }
476         catch (Exception JavaDoc x)
477         {
478             return object;
479         }
480
481         try
482         {
483             ByteArrayInputStream JavaDoc bin =
484                     new ByteArrayInputStream JavaDoc(bout.toByteArray());
485             ObjectInputStreamForContext in =
486                     new ObjectInputStreamForContext(bin, loader);
487
488             return in.readObject();
489         }
490         catch (Exception JavaDoc x)
491         {
492             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 JavaDoc loadClass(String JavaDoc className)
504             throws ClassNotFoundException JavaDoc
505     {
506         ClassLoader JavaDoc loader = this.getClass().getClassLoader();
507         try
508         {
509             return loader != null ?
510                     loader.loadClass(className) : Class.forName(className);
511         }
512         catch (ClassNotFoundException JavaDoc x)
513         {
514             /* Go through additional loaders. */
515             for (Iterator JavaDoc i = classLoaders.iterator(); i.hasNext();)
516             {
517                 try
518                 {
519                     return ((ClassLoader JavaDoc) i.next()).loadClass(className);
520                 }
521                 catch (ClassNotFoundException JavaDoc xx)
522                 {
523                 }
524             }
525
526             /* Give up. */
527             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 JavaDoc loadClass(String JavaDoc className,
540             ClassLoader JavaDoc loader)
541             throws ClassNotFoundException JavaDoc
542     {
543         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 JavaDoc className)
555             throws TurbineException
556     {
557         HashMap JavaDoc factories = objectFactories;
558         Object JavaDoc factory = factories.get(className);
559         if (factory != null)
560         {
561             if (factory instanceof String JavaDoc)
562             {
563                 /* Not yet instantiated... */
564                 try
565                 {
566                     factory = (Factory) getInstance((String JavaDoc) factory);
567                     ((Factory) factory).init(className);
568                 }
569                 catch (TurbineException x)
570                 {
571                     throw x;
572                 }
573                 catch (ClassCastException JavaDoc x)
574                 {
575                     throw new TurbineException(
576                             "Incorrect factory " + (String JavaDoc) factory +
577                             " for class " + className, x);
578                 }
579                 factories = (HashMap JavaDoc) factories.clone();
580                 factories.put(className, factory);
581                 objectFactories = factories;
582             }
583             return (Factory) factory;
584         }
585         else
586         {
587             return null;
588         }
589     }
590 }
591
Popular Tags