KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opensubsystems > core > util > ClassFactory


1 /*
2  * Copyright (c) 2003 - 2007 OpenSubsystems s.r.o. Slovak Republic. All rights reserved.
3  *
4  * Project: OpenSubsystems
5  *
6  * $Id: ClassFactory.java,v 1.7 2007/01/07 06:14:00 bastafidli Exp $
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; version 2 of the License.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21
22 package org.opensubsystems.core.util;
23
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.Properties JavaDoc;
28 import java.util.logging.Level JavaDoc;
29 import java.util.logging.Logger JavaDoc;
30
31 import org.opensubsystems.core.error.OSSDynamicClassException;
32 import org.opensubsystems.core.error.OSSException;
33
34 /**
35  * Purpose of this class is to make creation of configurable factories easier.
36  * It allows caller to specify class or class name of the class for which some
37  * new instance is desired. It allows derived class to perform name transformation
38  *
39  * @version $Id: ClassFactory.java,v 1.7 2007/01/07 06:14:00 bastafidli Exp $
40  * @author Miro Halas
41  * @code.reviewer Miro Halas
42  * @code.reviewed 1.5 2006/04/05 05:05:13 bastafidli
43  */

44 public class ClassFactory
45 {
46    // Constants ////////////////////////////////////////////////////////////////
47

48    /**
49     * Lock used in synchronized sections.
50     */

51    private static final String JavaDoc IMPL_LOCK = "IMPL_LOCK";
52
53    // Cached values ////////////////////////////////////////////////////////////
54

55    /**
56     * Logger for this class
57     */

58    private static Logger JavaDoc s_logger = Log.getInstance(ClassFactory.class);
59    
60    /**
61     * Reference to the instance actually in use.
62     */

63    private static ClassFactory s_defaultInstance;
64
65    // Constructors /////////////////////////////////////////////////////////////
66

67    /**
68     * Creates a new instance of DatabaseContextListener
69     */

70    public ClassFactory(
71    )
72    {
73    }
74    
75    /**
76     * Get the default instance so that everybody doesn't have to instantiate
77     * it all the time.
78     *
79     * @return DatabaseSchemaManager
80     * @throws OSSException - cannot get current database
81     */

82    public static ClassFactory getInstance(
83    ) throws OSSException
84    {
85       if (s_defaultInstance == null)
86       {
87          // Only if the default instance wasn't set by other means create a new one
88
// Synchronize just for the creation
89
synchronized (IMPL_LOCK)
90          {
91             setInstance(new ClassFactory());
92          }
93       }
94       
95       return s_defaultInstance;
96    }
97    
98    /**
99     * Set default instance. This instance will be returned by getInstance
100     * method until it is changed.
101     *
102     * @param defaultInstance - new default instance
103     * @see #getInstance
104     */

105    public static void setInstance(
106       ClassFactory defaultInstance
107    )
108    {
109       if (GlobalConstants.ERROR_CHECKING)
110       {
111          assert defaultInstance != null : "Default instance cannot be null";
112       }
113       
114       synchronized (IMPL_LOCK)
115       {
116          s_defaultInstance = defaultInstance;
117       }
118    }
119
120    // Logic ////////////////////////////////////////////////////////////////////
121

122    /**
123     * Create instance of the class by calling parameterless constructor.
124     * The created instance doesn't have to be of the same type as the passed in
125     * class identifier. The identifier can be used to create name of different
126     * class by some transformation, e.g. in case an interface name is passed in
127     * and default implementation class is desired.
128     *
129     * @param clsClassIdentifier - identifier of the class for which new instance
130     * should be created
131     * @return Object - new instance of the object, never null since exception
132     * will be thrown if not found
133     * @throws OSSException - an error has occured
134     */

135    public Object JavaDoc createInstance(
136       Class JavaDoc clsClassIdentifier
137    ) throws OSSException
138    {
139       return createInstance(clsClassIdentifier.getName());
140    }
141
142    /**
143     * Create instance of the class by calling parameterless constructor.
144     * The created instance doesn't have to be of the same type as the passed in
145     * class identifier. The identifier can be used to create name of different
146     * class by some transformation, e.g. in case an interface name is passed in
147     * and default implementation class is desired.
148     *
149     * @param clsClassIdentifier - identifier of the class for which new instance
150     * should be created
151     * @param clsDefault - default class to instantiate if no other class based
152     * on clsClassIdentifier cannot be instantiated
153     * @return Object - new instance of the object, never null since exception
154     * will be thrown if not found
155     * @throws OSSException - an error has occured
156     */

157    public Object JavaDoc createInstance(
158       Class JavaDoc clsClassIdentifier,
159       Class JavaDoc clsDefault
160    ) throws OSSException
161    {
162       return createInstance(clsClassIdentifier.getName(), clsDefault);
163    }
164    
165    /**
166     * Create instance of the class by calling parameterless constructor.
167     * The created instance doesn't have to be of the same type as the passed in
168     * class identifier. The identifier can be used to create name of different
169     * class by some transformation, e.g. in case an interface name is passed in
170     * and default implementation class is desired.
171     *
172     * @param strClassIdentifier - identifier of the class for which new instance
173     * should be created
174     * @param clsDefault - default class to instantiate if no other class based
175     * on clsClassIdentifier cannot be instantiated
176     * @return Object - new instance of the object, never null since exception
177     * will be thrown if not found
178     * @throws OSSException - an error has occured
179     */

180    public Object JavaDoc createInstance(
181       String JavaDoc strClassIdentifier,
182       Class JavaDoc clsDefault
183    ) throws OSSException
184    {
185       Object JavaDoc objInstance;
186       
187       try
188       {
189          objInstance = createInstance(strClassIdentifier);
190       }
191       catch (OSSDynamicClassException dceExc)
192       {
193          objInstance = ClassUtils.createNewInstance(clsDefault);
194          verifyInstance(objInstance);
195       }
196       
197       return objInstance;
198    }
199    
200    /**
201     * Create instance of the class by calling parameterless constructor.
202     * The created instance doesn't have to be of the same type as the passed in
203     * class identifier. The identifier can be used to create name of different
204     * class by some transformation, e.g. in case an interface name is passed in
205     * and default implementation class is desired.
206     *
207     * @param strClassIdentifier - identifier of the class for which new instance
208     * should be created
209     * @return Object - new instance of the object, never null since exception
210     * will be thrown if not found
211     * @throws OSSException - an error has occured
212     */

213    public Object JavaDoc createInstance(
214       String JavaDoc strClassIdentifier
215    ) throws OSSException
216    {
217       String JavaDoc strModifier;
218       Object JavaDoc objInstance = null;
219       List JavaDoc lstClassNames = new ArrayList JavaDoc();
220       
221       strModifier = getModifier();
222       createConfiguredClassNames(strClassIdentifier, strModifier, lstClassNames);
223       if (!lstClassNames.isEmpty())
224       {
225          // There were some class configured for this property sot try to
226
// instantiate it and if it cannto be instantiated, throw an excpetion
227
// since default class might be instantiated instead
228
objInstance = instantiateClass(lstClassNames, strClassIdentifier);
229          if (objInstance != null)
230          {
231             s_logger.finest("Class instantiation for " + strClassIdentifier +
232                             " based on configured setting instantiated " +
233                             objInstance.getClass().getName());
234          }
235       }
236       else
237       {
238          // Since no other class ws configured for specified identifier, try
239
// to get default class for given identifier and if there is any
240
// try to instantiate it
241
createDefaultClassNames(strClassIdentifier, strModifier, lstClassNames);
242          if (!lstClassNames.isEmpty())
243          {
244             objInstance = instantiateClass(lstClassNames, strClassIdentifier);
245             if (objInstance != null)
246             {
247                s_logger.finest("Class instantiation for " + strClassIdentifier +
248                                " based on default setting instantiated " +
249                                objInstance.getClass().getName());
250             }
251          }
252          else
253          {
254             throw new OSSDynamicClassException("No class names available for "
255                      + strClassIdentifier);
256          }
257       }
258       
259       if (objInstance == null)
260       {
261          throw new OSSDynamicClassException("Failed to create instance for "
262                                             + strClassIdentifier);
263       }
264       
265       return objInstance;
266    }
267    
268    // Helper methods ///////////////////////////////////////////////////////////
269

270    /**
271     * Instantiate new istance using ordered list of class names to consider.
272     *
273     * @param lstClassNames - ordered list of classes to consider as a template
274     * for new instance
275     * @param strClassIdentifier - identifier of the class for which new instance
276     * should be created, used for reporting purposes
277     * @return Object - new instance or null if it cannot be instantiated
278     * @throws OSSException - an error has occured
279     */

280    protected Object JavaDoc instantiateClass(
281       List JavaDoc lstClassNames,
282       String JavaDoc strClassIdentifier
283    ) throws OSSException
284    {
285       Object JavaDoc objInstance = null;
286       String JavaDoc strClassName;
287       Iterator JavaDoc classNames;
288       
289       for (classNames = lstClassNames.iterator();
290           (classNames.hasNext()) && (objInstance == null);)
291       {
292          strClassName = (String JavaDoc)classNames.next();
293          try
294          {
295             objInstance = ClassUtils.createNewInstance(strClassName);
296             // Print sucess message so that we can see what class are we using
297
Log.s_logger.finer("Speculative class instantiation for "
298                                + strClassIdentifier + " succeeded for class "
299                                + strClassName);
300          }
301          catch (OSSDynamicClassException dceExc)
302          {
303             // Do not print exception here because it is looking like an error
304
// in the log while what we tried to do was speculatively find a class
305
s_logger.log(Level.FINEST,
306                          "Speculative class instantiation for "
307                          + strClassIdentifier + " failed for class "
308                          + strClassName
309                          // Instead of stack tract print the original message
310
+ " with error " + dceExc.getCause());
311                          // + strClassName, dceExc);
312
}
313       }
314       verifyInstance(objInstance);
315       
316       return objInstance;
317    }
318    
319    /**
320     * This method allows derived class to implement verifications if desired
321     * that the instantiated class must satisfy.
322     *
323     * @param objInstance - instance to verify, can be null
324     * @throws OSSException - an error has occured (e.g. verification error)
325     */

326    protected void verifyInstance(
327       Object JavaDoc objInstance
328    ) throws OSSException
329    {
330       // By default there is no need to verify anything
331
}
332    
333    /**
334     * Create new class name based on the specified identifier and modifier.
335     *
336     * @param strClassIdentifier - identifier of the class for which new instance
337     * should be created
338     * @param strModifier - modifier used together with identifier to query
339     * configured class name or null if none is available
340     * @param lstClassNames - container to add the possible class names to.
341     * The classes will be tried in order as they are added
342     * to this container.
343     * @throws OSSException - an error has occured
344     */

345    protected void createDefaultClassNames(
346       String JavaDoc strClassIdentifier,
347       String JavaDoc strModifier,
348       List JavaDoc lstClassNames
349    ) throws OSSException
350    {
351       // The simplest implementation, just use the identifier as class name
352
lstClassNames.add(strClassIdentifier);
353    }
354
355    /**
356     * Create name for the class identified by given identifier based on
357     * configuration information. This name is first queried using modifier
358     * appended to the identifier and then without modifier for default configuration.
359     *
360     * @param strClassIdentifier - identifier of the class for which new instance
361     * should be created
362     * @param strModifier - modifier used together with identifier to query
363     * configured class name or null if none is available
364     * @param lstClassNames - container to add the possible class names to.
365     * The classes will be tried in order as they are added
366     * to this container.
367     * @throws OSSException - an error has occured
368     */

369    protected void createConfiguredClassNames(
370       String JavaDoc strClassIdentifier,
371       String JavaDoc strModifier,
372       List JavaDoc lstClassNames
373    ) throws OSSException
374    {
375       // The expectation is that the passed in class identifier is the name of
376
// the data factory interface. Use this name in a combination with a current
377
// active database identifier as a lookup to configuration file to see if
378
// the data factory is specified there. If it is not, then use the name
379
// without the database specifier to see if the database factory is database
380
// independent. If it is still not there,
381
Properties JavaDoc prpSettings;
382       String JavaDoc strClassName = null;
383       StringBuffer JavaDoc sbProperty = new StringBuffer JavaDoc(strClassIdentifier);
384       
385       prpSettings = Config.getInstance().getPropertiesSafely();
386       
387       // First database specific property in form datafactory.database
388
if (strModifier != null)
389       {
390          sbProperty.append(".");
391          sbProperty.append(strModifier.toLowerCase());
392          strClassName = prpSettings.getProperty(sbProperty.toString(), null);
393          if (strClassName != null)
394          {
395             lstClassNames.add(strClassName);
396          }
397       }
398       strClassName = prpSettings.getProperty(strClassIdentifier, null);
399       if (strClassName != null)
400       {
401          lstClassNames.add(strClassName);
402       }
403    }
404    
405    /**
406     * Get modifier which should be used together with the class identifier to
407     * construct class names.
408     *
409     * @return String - modifier or null if no modifier should be used
410     * @throws OSSException - an error has occured
411     */

412    protected String JavaDoc getModifier(
413    ) throws OSSException
414    {
415       return null;
416    }
417 }
418
Popular Tags