001: /*
002: * Copyright (c) 2001 - 2005 ivata limited.
003: * All rights reserved.
004: * -----------------------------------------------------------------------------
005: * ivata groupware may be redistributed under the GNU General Public
006: * License as published by the Free Software Foundation;
007: * version 2 of the License.
008: *
009: * These programs are free software; you can redistribute them and/or
010: * modify them under the terms of the GNU General Public License
011: * as published by the Free Software Foundation; version 2 of the License.
012: *
013: * These programs are distributed in the hope that they will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: *
017: * See the GNU General Public License in the file LICENSE.txt for more
018: * details.
019: *
020: * If you would like a copy of the GNU General Public License write to
021: *
022: * Free Software Foundation, Inc.
023: * 59 Temple Place - Suite 330
024: * Boston, MA 02111-1307, USA.
025: *
026: *
027: * To arrange commercial support and licensing, contact ivata at
028: * http://www.ivata.com/contact.jsp
029: * -----------------------------------------------------------------------------
030: * $Log: PicoContainerFactory.java,v $
031: * Revision 1.14 2005/10/12 18:29:40 colinmacleod
032: * Split nanoContainer.groovy into smaller scripts for easier re-use.
033: * Added a method to PicoContainerFactory to cache and run scripts.
034: *
035: * Revision 1.13 2005/10/11 18:51:38 colinmacleod
036: * Fixed some checkstyle and javadoc issues.
037: *
038: * Revision 1.12 2005/10/10 16:06:38 colinmacleod
039: * Merged in changes from releases 0.11.2 and 0.11.3.
040: *
041: * Revision 1.11 2005/10/09 09:39:26 colinmacleod
042: * Merged changes from ivata groupware v0.11.2 back into main trunk.
043: *
044: * Revision 1.10 2005/10/03 10:21:14 colinmacleod
045: * Fixed some style and javadoc issues.
046: *
047: * Revision 1.9 2005/10/02 17:02:28 colinmacleod
048: * Fixed CheckStyle errors.
049: *
050: * Revision 1.8 2005/10/02 14:08:56 colinmacleod
051: * Added/improved log4j logging.
052: *
053: * Revision 1.7 2005/10/02 10:23:10 colinmacleod
054: * Added factory bound variable to nano container script.
055: *
056: * Revision 1.6 2005/09/14 15:18:06 colinmacleod
057: * Added systemSettings.groovy.
058: * Removed unused local and class variables.
059: * Added serialVersionUID.
060: *
061: * Revision 1.5.2.1 2005/10/08 17:16:05 colinmacleod
062: * Improved bug catching on initialization.
063: * Added factory binding to startup script to avoid gridlock in getInstance().
064: *
065: * Revision 1.5 2005/04/22 09:30:42 colinmacleod
066: * Changed to using hibernate properties
067: * rather than the configuration instance
068: * directly.
069: *
070: * Revision 1.4 2005/04/10 20:43:09 colinmacleod
071: * Added new themes.
072: * Changed id type to String.
073: * Changed i tag to em and b tag to strong.
074: * Improved PicoContainerFactory with NanoContainer scripts.
075: *
076: * Revision 1.3 2005/04/09 17:19:37 colinmacleod
077: * Changed copyright text to GPL v2 explicitly.
078: *
079: * Revision 1.2 2005/03/22 18:16:56 colinmacleod
080: * Fixed handling of demo version in initialization
081: * of the security server.
082: *
083: * Revision 1.1 2005/03/10 19:23:03 colinmacleod
084: * Moved to ivata groupware.
085: *
086: * Revision 1.13 2004/12/31 18:42:00 colinmacleod
087: * Added ivata masks MaskFactory.
088: *
089: * Revision 1.12 2004/11/12 18:28:25 colinmacleod
090: * Added security session mask authenticator.
091: *
092: * Revision 1.11 2004/11/12 18:13:52 colinmacleod
093: * Ordered imports.
094: *
095: * Revision 1.10 2004/11/12 15:57:10 colinmacleod
096: * Removed dependencies on SSLEXT.
097: * Moved Persistence classes to ivata masks.
098: *
099: * Revision 1.9 2004/11/03 15:52:35 colinmacleod
100: * Mail system now extends person action and form, to add user aliases.
101: *
102: * Revision 1.8 2004/09/30 15:15:54 colinmacleod
103: * Split off address book elements into security subproject.
104: *
105: * Revision 1.7 2004/08/01 11:47:06 colinmacleod
106: * Fixed libraryItemRecent... queries.
107: * Lowered warning level to debug, if there is already a global container.
108: *
109: * Revision 1.6 2004/07/31 10:26:24 colinmacleod
110: * Fixed comment tree.
111: *
112: * Revision 1.5 2004/07/29 20:50:37 colinmacleod
113: * Fixed user right queries.
114: *
115: * Revision 1.4 2004/07/19 22:00:10 colinmacleod
116: * Added log4j logging.
117: *
118: * Revision 1.3 2004/07/18 22:04:12 colinmacleod
119: * Added addressBookPersonByUserName.
120: *
121: * Revision 1.2 2004/07/13 19:42:43 colinmacleod
122: * Moved project to POJOs from EJBs.
123: * Applied PicoContainer to services layer (replacing session EJBs).
124: * Applied Hibernate to persistence layer (replacing entity EJBs).
125: *
126: * Revision 1.1 2004/03/27 10:31:25 colinmacleod
127: * Split off business logic from remote facades to POJOs.
128: * -----------------------------------------------------------------------------
129: */
130: package com.ivata.groupware.container;
131:
132: import groovy.lang.Binding;
133: import groovy.lang.GroovyShell;
134: import groovy.lang.Script;
135:
136: import java.io.FileNotFoundException;
137: import java.io.InputStream;
138: import java.io.InputStreamReader;
139: import java.io.Serializable;
140: import java.math.BigDecimal;
141: import java.sql.Connection;
142: import java.sql.DriverManager;
143: import java.sql.ResultSet;
144: import java.sql.Statement;
145: import java.util.HashMap;
146: import java.util.Map;
147: import java.util.Properties;
148:
149: import javax.naming.Context;
150: import javax.naming.InitialContext;
151: import javax.naming.NamingException;
152:
153: import org.apache.log4j.Logger;
154: import org.codehaus.groovy.control.CompilationFailedException;
155: import org.nanocontainer.reflection.DefaultNanoPicoContainer;
156: import org.nanocontainer.script.ScriptedContainerBuilder;
157: import org.nanocontainer.script.groovy.GroovyContainerBuilder;
158: import org.picocontainer.MutablePicoContainer;
159: import org.picocontainer.PicoContainer;
160: import org.picocontainer.defaults.DefaultPicoContainer;
161: import org.picocontainer.defaults.ObjectReference;
162: import org.picocontainer.defaults.SimpleReference;
163:
164: import com.ivata.groupware.container.persistence.hibernate.HibernateSetupConstants;
165: import com.ivata.mask.DefaultMaskFactory;
166: import com.ivata.mask.MaskFactory;
167: import com.ivata.mask.field.DefaultFieldValueConvertorFactory;
168: import com.ivata.mask.util.SystemException;
169:
170: /**
171: * This factory class calls <strong>Groovy</strong> scripts to create
172: * <strong>PicoContainer</strong> instances.
173: *
174: * @author Colin MacLeod
175: * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
176: * @since ivata groupware v0.10 (2004-03-22)
177: * @version $Revision: 1.14 $
178: */
179: public final class PicoContainerFactory implements Serializable {
180: /**
181: * Scope string for the application level container.
182: */
183: public static final String APPLICATION_SCOPE = "IGW_APPLICATION_SCOPE";
184: /**
185: * The only instance of this class.
186: */
187: private static PicoContainerFactory instance = new PicoContainerFactory();
188: /**
189: * <p>This log provides tracing and debugging information.</p>
190: */
191: private static final Logger logger = Logger
192: .getLogger(PicoContainerFactory.class);
193:
194: /**
195: * Scope string used when the container is request or session scope (we
196: * make no distinciton).
197: */
198: public static final String NO_SCOPE = "IGW_NO_SCOPE";
199: /**
200: * Serialization version (for <code>Serializable</code> interface).
201: */
202: private static final long serialVersionUID = 1L;
203: /**
204: * Scope string for the internal 'singleton' container. This contains
205: * instances of all classes which should only be created once.
206: */
207: public static final String SINGLETON_SCOPE = "IGW_SINGLETON_SCOPE";
208:
209: /**
210: * Private helpser to intialize a class and trap any error.
211: *
212: * @param name The (package and) name of the class to initialize.
213: * @return The initialized class with the name given.
214: * @throws Exception Thrown if the class cannot be created for any reason.
215: */
216: private static Class classForName(final String name)
217: throws Exception {
218: if (logger.isDebugEnabled()) {
219: logger.debug("classForName(String name = " + name
220: + ") - start");
221: }
222:
223: try {
224: Class returnClass = Class.forName(name);
225: if (logger.isDebugEnabled()) {
226: logger
227: .debug("classForName(String) - end - return value = "
228: + returnClass);
229: }
230: return returnClass;
231: } catch (Exception e) {
232: logger.error(
233: e.getClass().getName()
234: + " thrown looking for class called '"
235: + name + "'", e);
236: throw e;
237: }
238: }
239:
240: /**
241: * Get a single instance of the factory.
242: *
243: * @throws SystemException if an instance of this class cannot be
244: * initialized.
245: * @return The sole instance of this class.
246: */
247: public static PicoContainerFactory getInstance()
248: throws SystemException {
249: if (logger.isDebugEnabled()) {
250: logger.debug("getInstance() - start");
251: }
252:
253: synchronized (instance) {
254: if (instance.isInitialized()) {
255: if (logger.isDebugEnabled()) {
256: logger
257: .debug("Returning existing PicoContainerFactory"
258: + " instance " + instance);
259: }
260: return instance;
261: }
262: // TODO: replace this with a JNDI-registered instance below
263: if (true) {
264: instance.initialize();
265:
266: if (logger.isDebugEnabled()) {
267: logger
268: .debug("getInstance() - end - return value = "
269: + instance);
270: }
271: return instance;
272: }
273: logger.info("Initializing PicoContainerFactory.");
274: Context initialContext;
275: try {
276: initialContext = new InitialContext();
277: } catch (NamingException e) {
278: logger.error("getInstance()", e);
279:
280: throw new SystemException(e);
281: }
282: Context envContext;
283: try {
284: envContext = (Context) initialContext
285: .lookup("java:comp/env");
286: } catch (NamingException e) {
287: logger.error("getInstance()", e);
288:
289: throw new SystemException(e);
290: }
291: try {
292: instance = (PicoContainerFactory) envContext
293: .lookup("ivata/PicoContainerFactory");
294: } catch (NamingException e) {
295: logger.error("getInstance()", e);
296:
297: throw new SystemException(e);
298: }
299: instance.initialize();
300: logger
301: .info("PicoContainerFactory initialization complete.");
302: }
303:
304: if (logger.isDebugEnabled()) {
305: logger.debug("getInstance() - end - return value = "
306: + instance);
307: }
308: return instance;
309: }
310:
311: /**
312: * This object is responsible for calling <strong>Groovy</strong> to create
313: * the containers.
314: */
315: private ScriptedContainerBuilder builder = null;
316: /**
317: * The main container.
318: */
319: private PicoContainer globalContainer;
320: /**
321: * <copyDoc>Refer to {@link #getHibernateConfigFileName}.</copyDoc>
322: */
323: private String hibernateConfigFileName = null;
324: /**
325: * <p>
326: * Stores the mask factory used throughout this application.
327: * </p>
328: */
329: private MaskFactory maskFactory = new DefaultMaskFactory(
330: "imInputMaskAction", "imListAction",
331: new DefaultFieldValueConvertorFactory());
332: /**
333: * Filename of the nano container script used to initialize the container.
334: * Will be loaded from the classpath.
335: */
336: private String nanoContainerScript = "/nanoContainer.groovy";
337: /**
338: * Stores all the compiled <em>Groovy</em> scripts, referenced by name.
339: */
340: private Map scripts = new HashMap();
341: /**
342: * This cache is used (for efficiency reasons) to read in and store all
343: * of the settings. You must have a table called <code>setting</code>, with
344: * columns <code>name</code>, <code>type</code>, <code>value</code> and
345: * <code>user</code>. Only those settings where <code>user</code> is
346: * <code>null</code> will be read.
347: */
348: private Map settings = new HashMap();
349: /**
350: * Used to store the instances of 'singleton' classes, i.e. those where
351: * we only want exactly 1 instance. Indexed by class name.
352: */
353: private Map singletonInstances = new HashMap();
354:
355: /**
356: * Filename of the script used to set up any system settings.
357: */
358: private String systemSettingsScript = "/systemSettings.groovy";
359:
360: /**
361: * Public constructor - should only be called by the application server.
362: * See {@link #getInstance getInstance} to get an instance of this class
363: * for any other purpose.
364: */
365: public PicoContainerFactory() {
366: }
367:
368: /**
369: * Use this method to obtain an instance - don't construct this class
370: * directly.
371: *
372: * @param parentContainer A container whose properties you want to inherit.
373: * @param scope This scope will be passed to the groovy initialization
374: * script ("nanoContainer.groovy"), which then decides how to
375: * initialize the pico container.
376: * @return The instance of this class matching.
377: * @throws SystemException If this is the first time the method is called,
378: * and there is a problem initializing the system.
379: */
380: public PicoContainer getContainer(final String scope,
381: final PicoContainer parentContainer) throws SystemException {
382: if (logger.isDebugEnabled()) {
383: logger.debug("getContainer(String scope = " + scope
384: + ", PicoContainer parentContainer = "
385: + parentContainer + ") - start");
386: }
387:
388: assert (builder != null);
389: ObjectReference containerRef = new SimpleReference();
390: ObjectReference parentContainerRef = new SimpleReference();
391: parentContainerRef.set(parentContainer);
392: builder.buildContainer(containerRef, parentContainerRef, scope,
393: true);
394: PicoContainer returnPicoContainer = (PicoContainer) containerRef
395: .get();
396: if (logger.isDebugEnabled()) {
397: logger.debug("getContainer(String, PicoContainer) - end -"
398: + " return value = " + returnPicoContainer);
399: }
400: return returnPicoContainer;
401: }
402:
403: /**
404: * Get the root PicoContainer, and initialize it if it was not already.
405: *
406: * @return root container.
407: */
408: public PicoContainer getGlobalContainer() {
409: if (logger.isDebugEnabled()) {
410: logger.debug("getGlobalContainer() - start");
411: }
412:
413: assert (globalContainer != null);
414:
415: if (logger.isDebugEnabled()) {
416: logger.debug("getGlobalContainer() - end - return value = "
417: + globalContainer);
418: }
419: return globalContainer;
420: }
421:
422: /**
423: * Stores the full path to the filename - it seems if we use the resource
424: * the configuration doesn't get reloaded after we've written it out.
425: * Setting the filename as here after a setup is a workaround.
426: * @return Returns the hibernate config file name.
427: */
428: public String getHibernateConfigFileName() {
429: if (logger.isDebugEnabled()) {
430: logger.debug("getHibernateConfigFileName() - start");
431: }
432:
433: if (logger.isDebugEnabled()) {
434: logger
435: .debug("getHibernateConfigFileName() - end - return value = "
436: + hibernateConfigFileName);
437: }
438: return hibernateConfigFileName;
439: }
440:
441: /**
442: * <p>
443: * Get the mask factory used throughout the ivata groupware application.
444: * </p>
445: *
446: * @return Returns the maskFactory.
447: */
448: public MaskFactory getMaskFactory() {
449: if (logger.isDebugEnabled()) {
450: logger.debug("getMaskFactory() - start");
451: }
452:
453: if (logger.isDebugEnabled()) {
454: logger.debug("getMaskFactory() - end - return value = "
455: + maskFactory);
456: }
457: return maskFactory;
458: }
459:
460: /**
461: * Return a map of all settings as they were when the container was started.
462: * @return Returns the settings.
463: */
464: public Map getSettings() {
465: if (logger.isDebugEnabled()) {
466: logger.debug("getSettings() - start");
467: }
468:
469: if (logger.isDebugEnabled()) {
470: logger.debug("getSettings() - end - return value = "
471: + settings);
472: }
473: return settings;
474: }
475:
476: /**
477: * This map contains a single instance for each class for which we want just
478: * one instance, keyed by the class name. This method should only be called
479: * by the <strong>Groovy</strong> initialization script.
480: *
481: * @return Returns the singletonInstances.
482: */
483: public Map getSingletonInstances() {
484: if (logger.isDebugEnabled()) {
485: logger.debug("getSingletonInstances() - start");
486: }
487:
488: if (logger.isDebugEnabled()) {
489: logger
490: .debug("getSingletonInstances() - end - return value = "
491: + singletonInstances);
492: }
493: return singletonInstances;
494: }
495:
496: /**
497: * This method is called to re-initalize the whole system. It is called
498: * auto-matically from {@link #getInstance getInstance} when
499: * there is no global container set up yet.
500: *
501: * @throws SystemException when the
502: * <a href='http://www.nanocontainer.org'>NanoContainer</a> cannot be
503: * initialized.
504: */
505: public void initialize() throws SystemException {
506: if (logger.isDebugEnabled()) {
507: logger.debug("initialize() - start");
508: }
509:
510: ClassLoader classLoader = Thread.currentThread()
511: .getContextClassLoader();
512: PicoContainer parentContainer = new DefaultNanoPicoContainer(
513: classLoader);
514: // now create the builder which is used to build all subsequent
515: // containers
516: InputStreamReader scriptReader;
517: try {
518: InputStream inputStream = classLoader
519: .getResourceAsStream(nanoContainerScript);
520: if (inputStream == null) {
521: throw new FileNotFoundException("Could not find '"
522: + nanoContainerScript
523: + "' on the current class path.");
524: }
525: scriptReader = new InputStreamReader(inputStream);
526: } catch (Exception e) {
527: logger.error(e.getClass().getName()
528: + " thrown loading nano container script '"
529: + nanoContainerScript + "'", e);
530: throw new SystemException(e);
531: }
532: builder = new GroovyContainerBuilder(scriptReader, classLoader) {
533: /**
534: * Overridden to add in a factory object, and the binding itself!
535: *
536: * @param bindingParam The currently bound variables
537: * @see org.nanocontainer.script.groovy
538: * .GroovyContainerBuilder#handleBinding(groovy.lang.Binding)
539: */
540: protected void handleBinding(final Binding binding) {
541: if (logger.isDebugEnabled()) {
542: logger.debug("handleBinding(Binding binding = "
543: + binding + ") - start");
544: }
545:
546: binding.setProperty("factory", instance);
547: binding.setProperty("binding", binding);
548: super .handleBinding(binding);
549:
550: if (logger.isDebugEnabled()) {
551: logger.debug("handleBinding(Binding) - end");
552: }
553: }
554: };
555:
556: // first register the 'singletons'
557: try {
558: parentContainer = getContainer(SINGLETON_SCOPE,
559: parentContainer);
560: } catch (Exception e) {
561: logger.error("initialize - " + e.getClass().getName()
562: + " initializing the SINGLETON_SCOPE.", e);
563: throw new SystemException(e);
564: }
565: // then use that as the parent of the application scope
566: try {
567: globalContainer = getContainer(APPLICATION_SCOPE,
568: parentContainer);
569: } catch (Exception e) {
570: logger.error("initialize - " + e.getClass().getName()
571: + " initializing the APPLICATION_SCOPE.", e);
572: throw new SystemException(e);
573: }
574: // having set the global container, see if there is a script to override
575: // system settings
576: try {
577: Binding binding = new Binding();
578: binding.setProperty("globalContainer", globalContainer);
579: InputStream scriptInputStream = classLoader
580: .getResourceAsStream(systemSettingsScript);
581:
582: if (scriptInputStream == null) {
583: if (logger.isDebugEnabled()) {
584: logger
585: .warn("initialize - no system settings script called '"
586: + systemSettingsScript + "'");
587: }
588: } else {
589: if (logger.isDebugEnabled()) {
590: logger
591: .warn("initialize - parsing system settings script '"
592: + systemSettingsScript + "'");
593: }
594: GroovyShell systemSettingsShell = new GroovyShell(
595: binding);
596: systemSettingsShell.evaluate(scriptInputStream,
597: systemSettingsScript);
598: }
599: } catch (Exception e) {
600: logger.error("initialize - Error loading script '"
601: + systemSettingsScript + "' from the class path.",
602: e);
603: throw new SystemException(e);
604:
605: }
606:
607: if (logger.isDebugEnabled()) {
608: logger.debug("initialize() - end");
609: }
610: }
611:
612: /**
613: * <p>
614: * Initialize the cache with all the settings. This can then be used
615: * throughout the initialization of the other objects.
616: * </p>
617: * <p>
618: * <b>Note</b> these settings are static and represeng the value of the
619: * settings when the program was started. The values are not updated
620: * when the settings change, unless the factory is reset and re-initialized.
621: * </p>
622: * <p>
623: * This method should only ever be called from
624: * the <strong>Groovy</strong> intialization script.
625: * </p>
626: *
627: * @param hibernateProperties This is a valid
628: * <strong>Hibernate</strong> configuration properties set. It must have
629: * values for these properties:
630: * <code>hibernate.connection.driver_class</code>,
631: * <code>hibernate.connection.url</code>,
632: * <code>hibernate.connection.username</code>,
633: * <code>hibernate.connection.password</code>.
634: * @throws Exception If the settings cannot be retrieved from the
635: * datastore.
636: */
637: public void initializeSettingsCache(
638: final Properties hibernateProperties) throws Exception {
639: if (logger.isDebugEnabled()) {
640: logger.debug("initializeSettingsCache(Properties "
641: + "hibernateProperties = " + hibernateProperties
642: + ") - start");
643: }
644:
645: settings.clear();
646: String driverClass = hibernateProperties
647: .getProperty(HibernateSetupConstants.HIBERNATE_PROPERTY_DATABASE_DRIVER);
648: assert (driverClass != null);
649: classForName(driverClass);
650: String uRL = hibernateProperties
651: .getProperty(HibernateSetupConstants.HIBERNATE_PROPERTY_DATABASE_URL);
652: assert (uRL != null);
653: String userName = hibernateProperties
654: .getProperty(HibernateSetupConstants.HIBERNATE_PROPERTY_DATABASE_USER_NAME);
655: assert (userName != null);
656: String password = hibernateProperties
657: .getProperty(HibernateSetupConstants.HIBERNATE_PROPERTY_DATABASE_PASSWORD);
658: Connection connection = DriverManager.getConnection(uRL,
659: userName, password);
660: Statement statement = connection.createStatement();
661: // NOTE: this is about the only SQL in the whole app.
662: ResultSet allSettings = statement
663: .executeQuery("select name, value, type from setting where person_user is "
664: + "null");
665: while (allSettings.next()) {
666: int parameter = 1;
667: String name = allSettings.getString(parameter++);
668: String stringValue = allSettings.getString(parameter++);
669: int type = allSettings.getInt(parameter++);
670: Object value;
671: if (type == 0) {
672: value = new BigDecimal(stringValue);
673: } else if (type == 2) {
674: value = new Boolean(stringValue);
675: } else {
676: value = stringValue;
677: }
678: settings.put(name, value);
679: }
680: statement.close();
681:
682: if (logger.isDebugEnabled()) {
683: logger.debug("initializeSettingsCache(Properties) - end");
684: }
685: }
686:
687: /**
688: * <p>
689: * Create an instance of the class provided. If the container cannot
690: * instantiate, a temporary container is created to specify this class.
691: * </p>
692: *
693: * @param theClass The class to instantiate.
694: * @return valid instance.
695: * @throws SystemException If this class cannot be instantiated for any
696: * reason.
697: */
698: public Object instantiateOrOverride(final Class theClass)
699: throws SystemException {
700: if (logger.isDebugEnabled()) {
701: logger.debug("instantiateOrOverride(Class theClass = "
702: + theClass + ") - start");
703: }
704:
705: Object returnObject = instantiateOrOverride(globalContainer,
706: theClass);
707: if (logger.isDebugEnabled()) {
708: logger
709: .debug("instantiateOrOverride(Class) - end - return value = "
710: + returnObject);
711: }
712: return returnObject;
713: }
714:
715: /**
716: * <p>
717: * Create an instance of the class provided. If the container cannot
718: * instantiate, a temporary container is created to specify this class.
719: * </p>
720: *
721: * @param container Specific container to use to create the instance.
722: * @param theClass The class to instantiate.
723: * @return valid instance.
724: * @throws SystemException If this class cannot be instantiated for any
725: * reason.
726: */
727: public Object instantiateOrOverride(final PicoContainer container,
728: final Class theClass) throws SystemException {
729: if (logger.isDebugEnabled()) {
730: logger
731: .debug("instantiateOrOverride(PicoContainer container = "
732: + container
733: + ", Class theClass = "
734: + theClass + ") - start");
735: }
736:
737: Object this Instance = container.getComponentInstance(theClass);
738: if (this Instance != null) {
739: if (logger.isDebugEnabled()) {
740: logger
741: .debug("instantiateOrOverride(PicoContainer, Class) -"
742: + " end - return value = "
743: + this Instance);
744: }
745: return this Instance;
746: }
747:
748: // now try the PicoContainer override way
749: MutablePicoContainer tempContainer = new DefaultPicoContainer(
750: container);
751: tempContainer.registerComponentImplementation(theClass);
752: this Instance = tempContainer.getComponentInstance(theClass);
753: if (this Instance != null) {
754: if (logger.isDebugEnabled()) {
755: logger
756: .debug("instantiateOrOverride(PicoContainer, Class) -"
757: + " end - return value = "
758: + this Instance);
759: }
760: return this Instance;
761: }
762:
763: // ok, really override everything
764: tempContainer = override(container);
765: tempContainer.registerComponentImplementation(theClass);
766: Object returnObject = tempContainer
767: .getComponentInstance(theClass);
768: if (logger.isDebugEnabled()) {
769: logger
770: .debug("instantiateOrOverride(PicoContainer, Class) -"
771: + " end - return value = " + returnObject);
772: }
773: return returnObject;
774: }
775:
776: /**
777: * <p>
778: * Create an instance of the class provided. If the container cannot
779: * instantiate, a temporary container is created to specify this class.
780: * </p>
781: *
782: * @param container The container to use to instantiate the class.
783: * @param className The name of the class to instantiate.
784: * @return valid instance.
785: * @throws SystemException If this class cannot be instantiated for any
786: * reason.
787: */
788: public Object instantiateOrOverride(final PicoContainer container,
789: final String className) throws SystemException {
790: if (logger.isDebugEnabled()) {
791: logger
792: .debug("instantiateOrOverride(PicoContainer container = "
793: + container
794: + ", String className = "
795: + className + ") - start");
796: }
797:
798: assert (className != null);
799: Class theClass;
800: try {
801: theClass = classForName(className);
802: } catch (Exception e) {
803: logger.error(
804: "instantiateOrOverride(PicoContainer, String)", e);
805:
806: throw new SystemException(e);
807: }
808: Object returnObject = instantiateOrOverride(container, theClass);
809: if (logger.isDebugEnabled()) {
810: logger
811: .debug("instantiateOrOverride(PicoContainer, String) -"
812: + " end - return value = " + returnObject);
813: }
814: return returnObject;
815: }
816:
817: /**
818: * Find out if the factory has been intialized or not.
819: *
820: * @return <code>true</code> if the factory has been initialized
821: * (<code>init</code> method was called successfully).
822: */
823: public boolean isInitialized() {
824: if (logger.isDebugEnabled()) {
825: logger.debug("isInitialized() - start");
826: }
827:
828: boolean returnboolean = (!singletonInstances.isEmpty());
829: if (logger.isDebugEnabled()) {
830: logger.debug("isInitialized() - end - return value = "
831: + returnboolean);
832: }
833: return returnboolean;
834: }
835:
836: /**
837: * Override the container provided. This creates a child container of the
838: * parent provided and registers all standard components on the child
839: * container.
840: *
841: * @param parent The parent container to be overridden.
842: * @return Child container of the parent provided.
843: * @throws SystemException Thrown if the child cannot be created.
844: */
845: public MutablePicoContainer override(final PicoContainer parent)
846: throws SystemException {
847: if (logger.isDebugEnabled()) {
848: logger.debug("override(PicoContainer parent = " + parent
849: + ") - start");
850: }
851:
852: MutablePicoContainer returnMutablePicoContainer = (MutablePicoContainer) getContainer(
853: NO_SCOPE, parent);
854: if (logger.isDebugEnabled()) {
855: logger
856: .debug("override(PicoContainer) - end - return value = "
857: + returnMutablePicoContainer);
858: }
859: return returnMutablePicoContainer;
860: }
861:
862: /**
863: * Clear the contents of the factory and mark it as not initialized. After
864: * calling this method, you should call <code>intialize</code>.
865: */
866: public void reset() {
867: if (logger.isDebugEnabled()) {
868: logger.debug("reset() - start");
869: }
870:
871: singletonInstances.clear();
872: globalContainer = null;
873:
874: if (logger.isDebugEnabled()) {
875: logger.debug("reset() - end");
876: }
877: }
878:
879: /**
880: * Run a <em>Groovy</em> script, referenced by classpath script name. This
881: * method is normally called by the nano container initialization script,
882: * <code>nanoContainer.groovy</code>.
883: *
884: * @param name Name of the groovy script on the classpath.
885: * @param binding Variable binding to use when running the script.
886: * @throws FileNotFoundException If there is no script with this name
887: * on the classpath.
888: * @throws CompilationFailedException If the script cannot be compiled.
889: */
890: public void runScript(final Binding binding, final String name)
891: throws FileNotFoundException, CompilationFailedException {
892: if (logger.isDebugEnabled()) {
893: logger.debug("runScript(Binding binding = " + binding
894: + ", String name = " + name + ") - start");
895: }
896:
897: // first see if we have cached this script
898: Script script = (Script) scripts.get(name);
899: if (script == null) {
900: if (logger.isDebugEnabled()) {
901: logger.debug("runScript - script '" + name
902: + "' run for first time.");
903: }
904: ClassLoader classLoader = getClass().getClassLoader();
905: InputStream scriptInputStream = classLoader
906: .getResourceAsStream(name);
907: if (scriptInputStream == null) {
908: logger.error("runScript - script '" + name
909: + "' not found in classpath.");
910: throw new FileNotFoundException(
911: "Cannot find script called '" + name + "'.");
912: }
913: GroovyShell groovyShell = new GroovyShell(binding);
914: script = groovyShell.parse(scriptInputStream, name);
915: scripts.put(name, script);
916: }
917: script.setBinding(binding);
918: script.run();
919:
920: if (logger.isDebugEnabled()) {
921: logger.debug("runScript() - end");
922: }
923: }
924:
925: /**
926: * <copyDoc>Refer to {@link #getHibernateConfigFileName}.</copyDoc>
927: * @param hibernateConfigFileNameParam Refer to
928: * {@link #getHibernateConfigFileName}.
929: */
930: public void setHibernateConfigFileName(
931: final String hibernateConfigFileNameParam) {
932: if (logger.isDebugEnabled()) {
933: logger.debug("Setting hibernateConfigFileName. Before '"
934: + hibernateConfigFileName + "', after '"
935: + hibernateConfigFileNameParam + "'");
936: }
937: hibernateConfigFileName = hibernateConfigFileNameParam;
938:
939: if (logger.isDebugEnabled()) {
940: logger.debug("setHibernateConfigFileName(String) - end");
941: }
942: }
943:
944: /**
945: * <copyDoc>Refer to {@link #getSettings}.</copyDoc>
946: * @param settingsParam <copyDoc>Refer to {@link #getSettings}.</copyDoc>
947: */
948: public void setSettings(final Map settingsParam) {
949: if (logger.isDebugEnabled()) {
950: logger.debug("Setting settings. Before '" + settings
951: + "', after '" + settingsParam + "'");
952: }
953: settings = settingsParam;
954:
955: if (logger.isDebugEnabled()) {
956: logger.debug("setSettings(Map) - end");
957: }
958: }
959:
960: /**
961: * <copyDoc>Refer to {@link #getSingletonInstances}.</copyDoc>
962: * @param singletonInstancesParam
963: * <copyDoc>Refer to {@link #getSingletonInstances}.</copyDoc>
964: */
965: public void setSingletonInstances(final Map singletonInstancesParam) {
966: if (logger.isDebugEnabled()) {
967: logger.debug("Setting singletonInstances. Before '"
968: + singletonInstances + "', after '"
969: + singletonInstancesParam + "'");
970: }
971: singletonInstances = singletonInstancesParam;
972:
973: if (logger.isDebugEnabled()) {
974: logger.debug("setSingletonInstances(Map) - end");
975: }
976: }
977: }
|