View Javadoc

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