KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ivata > groupware > container > PicoContainerFactory


1 /*
2  * Copyright (c) 2001 - 2005 ivata limited.
3  * All rights reserved.
4  * -----------------------------------------------------------------------------
5  * ivata groupware may be redistributed under the GNU General Public
6  * License as published by the Free Software Foundation;
7  * version 2 of the License.
8  *
9  * These programs are free software; you can redistribute them and/or
10  * modify them under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; version 2 of the License.
12  *
13  * These programs are distributed in the hope that they will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  * See the GNU General Public License in the file LICENSE.txt for more
18  * details.
19  *
20  * If you would like a copy of the GNU General Public License write to
21  *
22  * Free Software Foundation, Inc.
23  * 59 Temple Place - Suite 330
24  * Boston, MA 02111-1307, USA.
25  *
26  *
27  * To arrange commercial support and licensing, contact ivata at
28  * http://www.ivata.com/contact.jsp
29  * -----------------------------------------------------------------------------
30  * $Log: PicoContainerFactory.java,v $
31  * Revision 1.5.2.1 2005/10/08 17:16:05 colinmacleod
32  * Improved bug catching on initialization.
33  * Added factory binding to startup script to avoid gridlock in getInstance().
34  *
35  * Revision 1.5 2005/04/22 09:30:42 colinmacleod
36  * Changed to using hibernate properties
37  * rather than the configuration instance
38  * directly.
39  *
40  * Revision 1.4 2005/04/10 20:43:09 colinmacleod
41  * Added new themes.
42  * Changed id type to String.
43  * Changed i tag to em and b tag to strong.
44  * Improved PicoContainerFactory with NanoContainer scripts.
45  *
46  * Revision 1.3 2005/04/09 17:19:37 colinmacleod
47  * Changed copyright text to GPL v2 explicitly.
48  *
49  * Revision 1.2 2005/03/22 18:16:56 colinmacleod
50  * Fixed handling of demo version in initialization
51  * of the security server.
52  *
53  * Revision 1.1 2005/03/10 19:23:03 colinmacleod
54  * Moved to ivata groupware.
55  *
56  * Revision 1.13 2004/12/31 18:42:00 colinmacleod
57  * Added ivata masks MaskFactory.
58  *
59  * Revision 1.12 2004/11/12 18:28:25 colinmacleod
60  * Added security session mask authenticator.
61  *
62  * Revision 1.11 2004/11/12 18:13:52 colinmacleod
63  * Ordered imports.
64  *
65  * Revision 1.10 2004/11/12 15:57:10 colinmacleod
66  * Removed dependencies on SSLEXT.
67  * Moved Persistence classes to ivata masks.
68  *
69  * Revision 1.9 2004/11/03 15:52:35 colinmacleod
70  * Mail system now extends person action and form, to add user aliases.
71  *
72  * Revision 1.8 2004/09/30 15:15:54 colinmacleod
73  * Split off address book elements into security subproject.
74  *
75  * Revision 1.7 2004/08/01 11:47:06 colinmacleod
76  * Fixed libraryItemRecent... queries.
77  * Lowered warning level to debug, if there is already a global container.
78  *
79  * Revision 1.6 2004/07/31 10:26:24 colinmacleod
80  * Fixed comment tree.
81  *
82  * Revision 1.5 2004/07/29 20:50:37 colinmacleod
83  * Fixed user right queries.
84  *
85  * Revision 1.4 2004/07/19 22:00:10 colinmacleod
86  * Added log4j logging.
87  *
88  * Revision 1.3 2004/07/18 22:04:12 colinmacleod
89  * Added addressBookPersonByUserName.
90  *
91  * Revision 1.2 2004/07/13 19:42:43 colinmacleod
92  * Moved project to POJOs from EJBs.
93  * Applied PicoContainer to services layer (replacing session EJBs).
94  * Applied Hibernate to persistence layer (replacing entity EJBs).
95  *
96  * Revision 1.1 2004/03/27 10:31:25 colinmacleod
97  * Split off business logic from remote facades to POJOs.
98  * -----------------------------------------------------------------------------
99  */

100 package com.ivata.groupware.container;
101
102 import groovy.lang.Binding;
103
104 import java.io.FileNotFoundException JavaDoc;
105 import java.io.InputStream JavaDoc;
106 import java.io.InputStreamReader JavaDoc;
107 import java.io.Serializable JavaDoc;
108 import java.math.BigDecimal JavaDoc;
109 import java.sql.Connection JavaDoc;
110 import java.sql.DriverManager JavaDoc;
111 import java.sql.ResultSet JavaDoc;
112 import java.sql.Statement JavaDoc;
113 import java.util.HashMap JavaDoc;
114 import java.util.Map JavaDoc;
115 import java.util.Properties JavaDoc;
116
117 import javax.naming.Context JavaDoc;
118 import javax.naming.InitialContext JavaDoc;
119 import javax.naming.NamingException JavaDoc;
120
121 import net.sf.hibernate.SessionFactory;
122
123 import org.apache.log4j.Logger;
124 import org.nanocontainer.reflection.DefaultNanoPicoContainer;
125 import org.nanocontainer.script.ScriptedContainerBuilder;
126 import org.nanocontainer.script.groovy.GroovyContainerBuilder;
127 import org.picocontainer.MutablePicoContainer;
128 import org.picocontainer.PicoContainer;
129 import org.picocontainer.defaults.DefaultPicoContainer;
130 import org.picocontainer.defaults.ObjectReference;
131 import org.picocontainer.defaults.SimpleReference;
132
133 import com.ivata.groupware.container.persistence.hibernate.HibernateSetupConstants;
134 import com.ivata.mask.DefaultMaskFactory;
135 import com.ivata.mask.MaskFactory;
136 import com.ivata.mask.field.DefaultFieldValueConvertorFactory;
137 import com.ivata.mask.util.SystemException;
138
139 /**
140  * This factory class calls <strong>Groovy</strong> scripts to create
141  * <strong>PicoContainer</code> instances.
142  *
143  * @author Colin MacLeod
144  * <a HREF='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
145  * @since ivata groupware v0.10 (2004-03-22)
146  * @version $Revision: 1.5.2.1 $
147  */

148 public final class PicoContainerFactory implements Serializable JavaDoc {
149     /**
150      * Scope string for the application level container.
151      */

152     public static final String JavaDoc APPLICATION_SCOPE = "IGW_APPLICATION_SCOPE";
153     /**
154      * The only instance of this class.
155      */

156     private static PicoContainerFactory instance = new PicoContainerFactory();
157
158     /**
159      * <p>This log provides tracing and debugging information.</p>
160      */

161     private static Logger logger = Logger.getLogger(PicoContainerFactory.class);
162     /**
163      * Scope string used when the container is request or session scope (we
164      * make no distinciton).
165      */

166     public static final String JavaDoc NO_SCOPE = "IGW_NO_SCOPE";
167     /**
168      * Scope string for the internal 'singleton' container. This contains
169      * instances of all classes which should only be created once.
170      */

171     public static final String JavaDoc SINGLETON_SCOPE = "IGW_SINGLETON_SCOPE";
172
173     /**
174      * Private helpser to intialize a class and trap any error.
175      */

176     private static Class JavaDoc classForName(final String JavaDoc name) throws Exception JavaDoc {
177         try {
178             return Class.forName(name);
179         } catch(Exception JavaDoc e) {
180             logger.error(e.getClass().getName()
181                     + " thrown looking for class called '"
182                     + name
183                     + "'", e);
184             throw e;
185         }
186     }
187     /**
188      * Get a single instance of the factory.
189      *
190      * @throws SystemException if an instance of this class cannot be
191      * initialized.
192      */

193     public static PicoContainerFactory getInstance()
194             throws SystemException {
195         if (logger.isDebugEnabled()) {
196             logger.debug("getInstance() - start");
197         }
198
199         synchronized (instance) {
200             if (!instance.isInitialized()) {
201                 if (logger.isDebugEnabled()) {
202                     logger.debug("getInstance() - intiializing.");
203                 }
204                 instance.initialize();
205             }
206         }
207         if (logger.isDebugEnabled()) {
208             logger.debug("getInstance() - end - return value = "
209                     + instance);
210         }
211         return instance;
212     }
213     /**
214      * This object is responsible for calling <strong>Groovy</strong> to create
215      * the containers.
216      */

217     private ScriptedContainerBuilder builder = null;
218     /**
219      * The main container.
220      */

221     private PicoContainer globalContainer;
222     /**
223      * Refer to {@link #getHibernateConfigFileName}.
224      */

225     private String JavaDoc hibernateConfigFileName = null;
226     /**
227      * <p>
228      * Stores the mask factory used throughout this application.
229      * </p>
230      */

231     private MaskFactory maskFactory = new DefaultMaskFactory(
232             "imInputMaskAction", "imListAction",
233             new DefaultFieldValueConvertorFactory());
234     /**
235      * Filename of the nano container script used to initialize the container.
236      * Will be loaded from the classpath.
237      */

238     private String JavaDoc nanoContainerScript = "/nanoContainer.groovy";
239     /**
240      * <strong>Hibernate</strong> session factory used throughout the
241      * application.
242      */

243     private SessionFactory sessionFactory = null;
244
245
246     /**
247      * This cache is used (for efficiency reasons) to read in and store all
248      * of the settings. You must have a table called <code>setting</code>, with
249      * columns <code>name</code>, <code>type</code>, <code>value</code> and
250      * <code>user</code>. Only those settings where <code>user</code> is
251      * <code>null</code> will be read.
252      */

253     private Map JavaDoc settings = new HashMap JavaDoc();
254
255     /**
256      * Used to store the instances of 'singleton' classes, i.e. those where
257      * we only want exactly 1 instance. Indexed by class name.
258      */

259     private Map JavaDoc singletonInstances = new HashMap JavaDoc();
260     /**
261      * Public constructor - should only be called by the application server.
262      * See {@link #getInstance getInstance} to get an instance of this class
263      * for any other purpose.
264      */

265     public PicoContainerFactory() {
266     }
267     /**
268      *
269      * @param scope
270      * @return
271      * @throws SystemException
272      */

273     public PicoContainer getContainer(final String JavaDoc scope,
274             final PicoContainer parentContainer)
275             throws SystemException {
276         assert (builder != null);
277         ObjectReference containerRef = new SimpleReference();
278         ObjectReference parentContainerRef = new SimpleReference();
279         parentContainerRef.set(parentContainer);
280         builder.buildContainer(containerRef, parentContainerRef,
281                 scope, true);
282         return (PicoContainer) containerRef.get();
283     }
284
285     /**
286      * Get the root PicoContainer, and initialize it if it was not already.
287      *
288      * @return root container.
289      */

290     public PicoContainer getGlobalContainer() {
291         assert (globalContainer != null);
292         return globalContainer;
293     }
294     /**
295      * Stores the full path to the filename - it seems if we use the resource
296      * the configuration doesn't get reloaded after we've written it out.
297      * Setting the filename as here after a setup is a workaround.
298      * @return Returns the hibernate config file name.
299      */

300     public String JavaDoc getHibernateConfigFileName() {
301         return hibernateConfigFileName;
302     }
303     /**
304      * <p>
305      * Get the mask factory used throughout the ivata groupware application.
306      * </p>
307      *
308      * @return Returns the maskFactory.
309      */

310     public MaskFactory getMaskFactory() {
311         return maskFactory;
312     }
313     /**
314      * Return a map of all settings as they were when the container was started.
315      * @return Returns the settings.
316      */

317     public Map JavaDoc getSettings() {
318         return settings;
319     }
320     /**
321      * This map contains a single instance for each class for which we want just
322      * one instance, keyed by the class name. This method should only be called
323      * by the <strong>Groovy</strong> initialization script.
324      *
325      * @return Returns the singletonInstances.
326      */

327     public Map JavaDoc getSingletonInstances() {
328         return singletonInstances;
329     }
330     /**
331      * This method is called to re-initalize the whole system. It is called
332      * auto-matically from {@link #getInstance getInstance} when
333      * there is no global container set up yet.
334      *
335      * @throws SystemException when the
336      * <a HREF='http://www.nanocontainer.org'>NanoContainer</a> cannot be
337      * initialized.
338      */

339     public void initialize() throws SystemException {
340         ClassLoader JavaDoc classLoader =
341             Thread.currentThread().getContextClassLoader();
342         PicoContainer parentContainer =
343             new DefaultNanoPicoContainer(classLoader);
344         // now create the builder which is used to build all subsequent
345
// containers
346
InputStreamReader JavaDoc scriptReader;
347         try {
348             InputStream JavaDoc inputStream = classLoader.getResourceAsStream(
349                     nanoContainerScript);
350             if (inputStream == null) {
351                 throw new FileNotFoundException JavaDoc("Could not find '"
352                         + nanoContainerScript
353                         + "' on the current class path.");
354             }
355             scriptReader = new InputStreamReader JavaDoc(inputStream);
356         } catch (Exception JavaDoc e) {
357             logger.error(e.getClass().getName()
358                     + " thrown loading nano container script '"
359                     + nanoContainerScript
360                     + "'", e);
361             throw new SystemException(e);
362         }
363         builder = new GroovyContainerBuilder(
364                 scriptReader,
365                 classLoader) {
366             /**
367              * Overridden to add in a factory object.
368              * @param bindingParam The currently bound variables
369              * @see org.nanocontainer.script.groovy
370              * .GroovyContainerBuilder#handleBinding(groovy.lang.Binding)
371              */

372             protected void handleBinding(final Binding binding) {
373                 if (logger.isDebugEnabled()) {
374                     logger.debug("handleBinding(Binding binding = " + binding
375                             + ") - start");
376                 }
377
378                 binding.setProperty("factory", instance);
379                 super.handleBinding(binding);
380
381                 if (logger.isDebugEnabled()) {
382                     logger.debug("handleBinding(Binding) - end");
383                 }
384             }
385         };
386
387         // first register the 'singletons'
388
try {
389             parentContainer = getContainer(SINGLETON_SCOPE,
390                     parentContainer);
391         } catch (Exception JavaDoc e) {
392             logger.error ("initialize - "
393                 + e.getClass().getName()
394                 + " initializing the SINGLETON_SCOPE.", e);
395             throw new SystemException(e);
396         }
397         // then use that as the parent of the application scope
398
try {
399             globalContainer = getContainer(APPLICATION_SCOPE,
400                     parentContainer);
401         } catch (Exception JavaDoc e) {
402             logger.error ("initialize - "
403                 + e.getClass().getName()
404                 + " initializing the APPLICATION_SCOPE.", e);
405             throw new SystemException(e);
406         }
407     }
408
409     /**
410      * <p>
411      * Initialize the cache with all the settings. This can then be used
412      * throughout the initialization of the other objects.
413      * </p>
414      * <p>
415      * <b>Note</b> these settings are static and represeng the value of the
416      * settings when the program was started. The values are not updated
417      * when the settings change, unless the factory is reset and re-initialized.
418      * </p>
419      * <p>
420      * This method should only ever be called from
421      * the <strong>Groovy</strong> intialization script.
422      * </p>
423      *
424      * @param configuration This is a valid <strong>Hibernate</strong>
425      * configuration object. It must have these properties set:
426      * <code>hibernate.connection.driver_class</code>,
427      * <code>hibernate.connection.url</code>,
428      * <code>hibernate.connection.username</code>,
429      * <code>hibernate.connection.password</code>.
430      */

431     public void initializeSettingsCache(Properties JavaDoc
432             hibernateProperties) throws Exception JavaDoc {
433         settings.clear();
434         String JavaDoc driverClass = hibernateProperties.getProperty(
435                         HibernateSetupConstants
436                             .HIBERNATE_PROPERTY_DATABASE_DRIVER);
437         assert(driverClass != null);
438         classForName(driverClass);
439         String JavaDoc uRL = hibernateProperties.getProperty(
440                 HibernateSetupConstants
441                 .HIBERNATE_PROPERTY_DATABASE_URL);
442         assert(uRL != null);
443         String JavaDoc userName =hibernateProperties.getProperty(
444                 HibernateSetupConstants
445                 .HIBERNATE_PROPERTY_DATABASE_USER_NAME);
446         assert(userName != null);
447         String JavaDoc password = hibernateProperties.getProperty(
448                 HibernateSetupConstants
449                 .HIBERNATE_PROPERTY_DATABASE_PASSWORD);
450         Connection JavaDoc connection = DriverManager.getConnection(uRL, userName,
451                 password);
452         Statement JavaDoc statement = connection.createStatement();
453         // NOTE: this is about the only SQL in the whole app.
454
ResultSet JavaDoc allSettings = statement.executeQuery(
455                 "select name, value, type from setting where person_user is "
456                 + "null");
457         while(allSettings.next()) {
458             String JavaDoc name = allSettings.getString(1);
459             String JavaDoc stringValue = allSettings.getString(2);
460             int type = allSettings.getInt(3);
461             Object JavaDoc value;
462             if (type == 0) {
463                 value = new BigDecimal JavaDoc(stringValue);
464             } else if (type == 2) {
465                 value = new Boolean JavaDoc(stringValue);
466             } else {
467                 value = stringValue;
468             }
469             settings.put(name, value);
470         }
471         statement.close();
472     }
473     /**
474      * <p>
475      * Create an instance of the class provided. If the container cannot
476      * instantiate, a temporary container is created to specify this class.
477      * </p>
478      *
479      * @param container The container to use to instantiate the class.
480      * @param theClassName The class to instantiate.
481      * @return valid instance.
482      */

483     public Object JavaDoc instantiateOrOverride(
484             Class JavaDoc theClass)
485             throws SystemException {
486         return instantiateOrOverride(globalContainer, theClass);
487     }
488     public Object JavaDoc instantiateOrOverride(PicoContainer container,
489             Class JavaDoc theClass)
490             throws SystemException {
491         Object JavaDoc instance = container.getComponentInstance(theClass);
492         if (instance != null) {
493             return instance;
494         }
495
496         // now try the PicoContainer override way
497
MutablePicoContainer tempContainer =
498             new DefaultPicoContainer(container);
499         tempContainer.registerComponentImplementation(theClass);
500         instance = tempContainer.getComponentInstance(theClass);
501         if (instance != null) {
502             return instance;
503         }
504
505         // ok, really override everything
506
tempContainer = override(container);
507         tempContainer.registerComponentImplementation(theClass);
508         return tempContainer.getComponentInstance(theClass);
509     }
510
511     /**
512      * <p>
513      * Create an instance of the class provided. If the container cannot
514      * instantiate, a temporary container is created to specify this class.
515      * </p>
516      *
517      * @param container The container to use to instantiate the class.
518      * @param className The name of the class to instantiate.
519      * @return valid instance.
520      */

521     public Object JavaDoc instantiateOrOverride(PicoContainer container,
522             String JavaDoc className)
523             throws SystemException {
524         assert (className != null);
525         Class JavaDoc theClass;
526         try {
527             theClass = classForName(className);
528         } catch (Exception JavaDoc e) {
529             throw new SystemException(e);
530         }
531         return instantiateOrOverride(container, theClass);
532     }
533     /**
534      * Find out if the factory has been intialized or not.
535      *
536      * @return <code>true</code> if the factory has been initialized
537      * (<code>init</code> method was called successfully).
538      */

539     public boolean isInitialized() {
540         return (!singletonInstances.isEmpty());
541     }
542
543     /**
544      * Override the container provided. This creates a child container of the
545      * parent provided and registers all standard components on the child
546      * container.
547      *
548      * @param parent parent container to be overridden
549      */

550     public MutablePicoContainer override(PicoContainer parent)
551             throws SystemException {
552         return (MutablePicoContainer) getContainer(NO_SCOPE, parent);
553     }
554     /**
555      * Clear the contents of the factory and mark it as not initialized. After
556      * calling this method, you should call <code>intialize</code>.
557      */

558     public void reset() {
559         singletonInstances.clear();
560         globalContainer = null;
561         sessionFactory = null;
562     }
563     /**
564      * Refer to {@link #getHibernateConfigFileName}.
565      * @param hibernateConfigFileNameParam Refer to
566      * {@link #getHibernateConfigFileName}.
567      */

568     public void setHibernateConfigFileName(String JavaDoc hibernateConfigFileNameParam) {
569         if (logger.isDebugEnabled()) {
570             logger.debug("Setting hibernateConfigFileName. Before '"
571                     + hibernateConfigFileName + "', after '"
572                     + hibernateConfigFileNameParam + "'");
573         }
574         hibernateConfigFileName = hibernateConfigFileNameParam;
575     }
576     /**
577      * Refer to {@link #getSettings}.
578      * @param settingsParam Refer to {@link #getSettings}.
579      */

580     public void setSettings(Map JavaDoc settingsParam) {
581         if (logger.isDebugEnabled()) {
582             logger.debug("Setting settings. Before '" + settings + "', after '"
583                     + settingsParam + "'");
584         }
585         settings = settingsParam;
586     }
587     /**
588      * Refer to {@link #getSingletonInstances}.
589      * @param singletonInstancesParam Refer to {@link #getSingletonInstances}.
590      */

591     public void setSingletonInstances(Map JavaDoc singletonInstancesParam) {
592         if (logger.isDebugEnabled()) {
593             logger.debug("Setting singletonInstances. Before '"
594                     + singletonInstances + "', after '"
595                     + singletonInstancesParam + "'");
596         }
597         singletonInstances = singletonInstancesParam;
598     }
599 }
600
Popular Tags