View Javadoc

    1   /***
    2    * JFoxSOAF, Service-Oriented Application Framework
    3    *
    4    * Copyright (C) www.huihoo.org
    5    *
    6    * Distributable under GNU LGPL
    7    *
    8    * For more information, please visit: http://www.huihoo.org/jfox/jfoxsoaf
    9    */
    10
    11  package org.huihoo.jfox.soaf.services.jdbc;
    12
    13  import java.io.IOException;
    14  import java.io.InputStream;
    15  import java.security.AccessController;
    16  import java.security.PrivilegedAction;
    17  import java.util.Enumeration;
    18  import java.util.Hashtable;
    19  import java.util.Properties;
    20
    21  import javax.sql.DataSource;
    22
    23  import org.huihoo.jfox.soaf.exception.DataSourceConfigurationException;
    24  import org.huihoo.jfox.soaf.util.resource.ResourceHelper;
    25
    26  /***
    27   * <p>
    28   * Factory for creating database connection instances, with discovery and
    29   * configuration features
    30   * </p>
    31   *
    32   * @author <a href="mailto:founder_chen@yahoo.com.cn">Peter Cheng </a>
    33   * @version $Revision: 1.1 $ $Date: 2004/10/28 15:12:16 $
    34   * @version Revision: 1.0
    35   */
    36
    37  public abstract class DataSourceFactory {
    38
    39      /***
    40       * Protected constructor that is not available for public use.
    41       */
    42      protected DataSourceFactory() {
    43      }
    44
    45      /***
    46       * The previously constructed <code>LogFactory</code> instances, keyed by
    47       * the <code>ClassLoader</code> with which it was created.
    48       */
    49      protected static Hashtable factories = new Hashtable();
    50
    51      /***
    52       * Get singlton database connection instance.
    53       */
    54      public abstract DataSource getInstance()
    55              throws DataSourceConfigurationException;
    56
    57      /***
    58       * Return the configuration attribute with the specified name (if any), or
    59       * <code>null</code> if there is no such attribute.
    60       *
    61       * @param name
    62       *            Name of the attribute to return
    63       */
    64      public abstract Object getAttribute(String name);
    65
    66      /***
    67       * Return an array containing the names of all currently defined
    68       * configuration attributes. If there are no such attributes, a zero length
    69       * array is returned.
    70       */
    71      public abstract String[] getAttributeNames();
    72
    73      /***
    74       * Remove any configuration attribute associated with the specified name. If
    75       * there is no such attribute, no action is taken.
    76       *
    77       * @param name
    78       *            Name of the attribute to remove
    79       */
    80      public abstract void removeAttribute(String name);
    81
    82      /***
    83       * Set the configuration attribute with the specified name. Calling this
    84       * with a <code>null</code> value is equivalent to calling
    85       * <code>removeAttribute(name)</code>.
    86       *
    87       * @param name
    88       *            Name of the attribute to set
    89       * @param value
    90       *            Value of the attribute to set, or <code>null</code> to
    91       *            remove any setting for this attribute
    92       */
    93      public abstract void setAttribute(String name, Object value);
    94
    95      public static DataSourceFactory getFactory()
    96              throws DataSourceConfigurationException {
    97          // Return any previously registered factory for this class loader
    98          DataSourceFactory factory = getCachedFactory(DataSourceFactory.class
    99                  .getClassLoader());
    100
    101         if (factory != null)
    102             return factory;
    103
    104         // Load properties file
    105         Properties props = null;
    106         try {
    107             InputStream stream = ResourceHelper
    108                     .getResourceAsStream(DatabaseConstant.JDBC_FACTORY_PROPERTIES);
    109
    110             if (stream != null) {
    111                 props = new Properties();
    112                 props.load(stream);
    113                 stream.close();
    114             }
    115         } catch (IOException e) {
    116             throw new DataSourceConfigurationException(
    117                     "Load Database configuration IO exception " + e);
    118         } catch (SecurityException e) {
    119             throw new DataSourceConfigurationException(
    120                     "Database configuration access security exception " + e);
    121         }
    122
    123         // Second try a properties file.
    124         if (factory == null && props != null) {
    125             String factoryClass = props
    126                     .getProperty(DatabaseConstant.JDBC_DATABASE_FACTORY);
    127             if (factoryClass != null && !factoryClass.equals("")) {
    128                 factory = newFactory(factoryClass, DataSourceFactory.class
    129                         .getClassLoader());
    130             }
    131         }
    132
    133         // Third, try the fallback implementation class
    134         if (factory == null) {
    135             factory = newFactory(DatabaseConstant.JDBC_DEFAULT_FACTORY,
    136                     DataSourceFactory.class.getClassLoader());
    137         }
    138
    139         if (factory != null) {
    140             /***
    141              * Always cache using context class loader..
    142              */
    143             cacheFactory(DataSourceFactory.class.getClassLoader(), factory);
    144
    145             if (props != null) {
    146                 Enumeration names = props.propertyNames();
    147                 while (names.hasMoreElements()) {
    148                     String name = (String) names.nextElement();
    149                     String value = props.getProperty(name);
    150                     factory.setAttribute(name, value);
    151                 }
    152             }
    153         }
    154
    155         return factory;
    156     }
    157
    158     /***
    159      * Check cached factories (keyed by classLoader)
    160      */
    161     private static DataSourceFactory getCachedFactory(
    162             ClassLoader contextClassLoader) {
    163         DataSourceFactory factory = null;
    164
    165         if (contextClassLoader != null)
    166             factory = (DataSourceFactory) factories.get(contextClassLoader);
    167
    168         return factory;
    169     }
    170
    171     private static void cacheFactory(ClassLoader classLoader,
    172             DataSourceFactory factory) {
    173         if (classLoader != null && factory != null)
    174             factories.put(classLoader, factory);
    175     }
    176
    177     /***
    178      * Return a new instance of the specified <code>LogFactory</code>
    179      * implementation class, loaded by the specified class loader. If that
    180      * fails, try the class loader used to load this (abstract) LogFactory.
    181      *
    182      * @param factoryClass
    183      *            Fully qualified name of the <code>LogFactory</code>
    184      *            implementation class
    185      * @param classLoader
    186      *            ClassLoader from which to load this class
    187      * @exception DataSourceConfigException
    188      *                if a suitable instance cannot be created
    189      */
    190     protected static DataSourceFactory newFactory(final String factoryClass,
    191             final ClassLoader classLoader)
    192             throws DataSourceConfigurationException {
    193         Object result = AccessController.doPrivileged(new PrivilegedAction() {
    194
    195             public Object run() {
    196                 try {
    197                     if (classLoader != null) {
    198                         try {
    199                             return (DataSourceFactory) classLoader.loadClass(
    200                                     factoryClass).newInstance();
    201                         } catch (ClassNotFoundException ex) {
    202                             if (classLoader == DataSourceFactory.class
    203                                     .getClassLoader()) {
    204                                 // Nothing more to try, onwards.
    205                                 throw ex;
    206                             }
    207                             // ignore exception, continue
    208                         } catch (NoClassDefFoundError e) {
    209                             if (classLoader == DataSourceFactory.class
    210                                     .getClassLoader()) {
    211                                 throw e;
    212                             }
    213
    214                         } catch (ClassCastException e) {
    215
    216                             if (classLoader == DataSourceFactory.class
    217                                     .getClassLoader()) {
    218                                 throw e;
    219                             }
    220                         }
    221                     }
    222                     return (DataSourceFactory) Class.forName(factoryClass)
    223                             .newInstance();
    224                 } catch (Exception e) {
    225                     return new DataSourceConfigurationException(e);
    226                 }
    227             }
    228         });
    229
    230         if (result instanceof DataSourceConfigurationException)
    231             throw (DataSourceConfigurationException) result;
    232
    233         return (DataSourceFactory) result;
    234     }
    235
    236     /***
    237      * Retrive concreate datasource.
    238      *
    239      * @return PoolDataSource
    240      * @throws DataSourceConfigurationException
    241      */
    242     public static DataSource getDataSource()
    243             throws DataSourceConfigurationException {
    244         try {
    245             return getFactory().getInstance();
    246         } catch (DataSourceConfigurationException e) {
    247             throw new DataSourceConfigurationException(e.getMessage(), e);
    248         }
    249     }
    250
    251 }