001: /* Copyright 2004-2005 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.rdbm.pool;
007:
008: import org.apache.commons.logging.Log;
009: import org.apache.commons.logging.LogFactory;
010: import org.jasig.portal.properties.MissingPropertyException;
011: import org.jasig.portal.properties.PropertiesManager;
012:
013: /**
014: * @author Eric Dalquist <a href="mailto:edalquist@unicon.net">edalquist@unicon.net</a>
015: * @version $Revision: 36214 $ $Date: 2005-10-19 09:25:55 -0700 (Wed, 19 Oct 2005) $
016: * @since uPortal 2.5
017: */
018: public final class PooledDataSourceFactoryFactory {
019:
020: /**
021: * The name of the portal.properties property the value of which will be the name of the
022: * IPooledDataSourceFactory implementation that we will use.
023: */
024: public static final String POOLED_DATA_SOURCE_FACTORY_PROPERTY = "org.jasig.portal.PooledDataSourceFactory.implementation";
025:
026: /**
027: * A Commons Logging log instance.
028: */
029: private static final Log LOG = LogFactory
030: .getLog(PooledDataSourceFactoryFactory.class);
031:
032: /**
033: * Our default IPooledDataSourceFactory implementation upon which we will fall back if
034: * our property is not set or we cannot instantiate the implementation specified by
035: * our property.
036: *
037: * Default scoped to be accessible to our testcase.
038: */
039: static final Class DEFAULT_POOLED_DATASOURCE_FACTORY = DBCPDataSourceFactory.class;
040:
041: /**
042: * Our static singleton instance that we're managing.
043: */
044: private static IPooledDataSourceFactory pooledDataSourceFactoryImpl = null;
045:
046: /**
047: * Get a reference to our static singleton instance of IPooledDataSourceFactory
048: * as specified in our portal.properties property, or our default implementation, or null.
049: *
050: * That is, this method returns our static singleton instance of IPooledDataSourceFactory.
051: * That instance will be an instance of the implementation named in our portal.properties property
052: * if we are able to instantiate that, or an instance of our default implementation if we were
053: * unable to instantiate the configured implementation, or null if we can instantiate neither.
054: *
055: * This method is synchronized to avoid using the much-feared Double Checked Locking
056: * idiom. By synchronizing we force the change we make when we first (lazily) initialize
057: * our pooledDataSourceFactoryImpl to be written back to main memory and thereby
058: * be available to other threads when they succeed in obtaining the lock and entering
059: * this method.
060: *
061: * @return the configured or default IPooledDataSourceFactory, or null if neither can be instantiated.
062: */
063: public static synchronized IPooledDataSourceFactory getPooledDataSourceFactory() {
064:
065: // if we already have instantiated our static singleton instance, return it
066: if (pooledDataSourceFactoryImpl != null) {
067: return pooledDataSourceFactoryImpl;
068: }
069:
070: // initialize the class name so we can try to use it in our error logging
071: // on failure
072: String className = "unknown";
073: try {
074: className = PropertiesManager
075: .getProperty(POOLED_DATA_SOURCE_FACTORY_PROPERTY);
076: pooledDataSourceFactoryImpl = (IPooledDataSourceFactory) Class
077: .forName(className).newInstance();
078: return pooledDataSourceFactoryImpl;
079: } catch (MissingPropertyException mpe) {
080: // we recover from our property not having been set by falling back on our default.
081: // This is not necessarily an error condition. The deployer may simply have chosen
082: // not to set our property and expects us to fall back on our default.
083: LOG
084: .info("The portal.properties property "
085: + POOLED_DATA_SOURCE_FACTORY_PROPERTY
086: + " was not set, so PooledDataSourceFactoryFactory will fall back on its default "
087: + "IPooledDataSourceFactory implementation, which is "
088: + DEFAULT_POOLED_DATASOURCE_FACTORY);
089: } catch (Exception e) {
090: // we also recover from any other problem that happened in instantiating the configured
091: // IPooledDataSourceFactory by falling back on our default. However, this is an error
092: // condition and logged as such.
093:
094: LOG.error(
095: "Unable to instantiate the configured IPooledDataSourceFactory :"
096: + className
097: + ", so falling back on default of "
098: + DEFAULT_POOLED_DATASOURCE_FACTORY, e);
099:
100: }
101:
102: try {
103: pooledDataSourceFactoryImpl = (IPooledDataSourceFactory) DEFAULT_POOLED_DATASOURCE_FACTORY
104: .newInstance();
105: } catch (Exception e2) {
106: LOG.error(
107: "Could not instantiate our default IPooledDataSourceFactory "
108: + DEFAULT_POOLED_DATASOURCE_FACTORY, e2);
109: }
110:
111: // the field will either be our default if we succeeded in instantiating our default
112: // or will be null if we failed.
113: return pooledDataSourceFactoryImpl;
114:
115: }
116:
117: /**
118: * This private constructor prevents instantiation of this static
119: * factory class.
120: */
121: private PooledDataSourceFactoryFactory() {
122: // do nothing
123: }
124:
125: /**
126: * Clears this static factory's static singleton instance of
127: * IPooledDataSourceFactory. This method exists to support the unit test
128: * for this class and should not be considered part of the API exported
129: * by this class.
130: */
131: static void reset() {
132: pooledDataSourceFactoryImpl = null;
133: }
134: }
|