View Javadoc

1   package org.apache.torque.dsfactory;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.Iterator;
23  
24  import javax.sql.ConnectionPoolDataSource;
25  import javax.sql.DataSource;
26  
27  import org.apache.commons.beanutils.ConvertUtils;
28  import org.apache.commons.beanutils.MappedPropertyDescriptor;
29  import org.apache.commons.beanutils.PropertyUtils;
30  import org.apache.commons.configuration.Configuration;
31  import org.apache.commons.dbcp.cpdsadapter.DriverAdapterCPDS;
32  import org.apache.commons.lang.StringUtils;
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  import org.apache.torque.Torque;
36  import org.apache.torque.TorqueException;
37  import org.apache.torque.TorqueRuntimeException;
38  
39  /***
40   * A class that contains common functionality of the factories in this
41   * package.
42   *
43   * @author <a href="mailto:jmcnally@apache.org">John McNally</a>
44   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
45   * @version $Id: AbstractDataSourceFactory.java 473821 2006-11-11 22:37:25Z tv $
46   */
47  public abstract class AbstractDataSourceFactory
48          implements DataSourceFactory
49  {
50      /*** "pool" Key for the configuration */
51      public static final String POOL_KEY = "pool";
52  
53      /*** "connection" Key for the configuration */
54      public static final String CONNECTION_KEY = "connection";
55  
56      /*** "schema" Key for the configuration */
57      public static final String SCHEMA_KEY = "schema";
58  
59      /*** "defaults" Key for the configuration */
60      public static final String DEFAULTS_KEY = "defaults";
61  
62      /*** "defaults.pool" Key for the configuration */
63      public static final String DEFAULT_POOL_KEY
64              = DEFAULTS_KEY + "." + POOL_KEY;
65  
66      /*** "defaults.connection" Key for the configuration */
67      public static final String DEFAULT_CONNECTION_KEY
68              = DEFAULTS_KEY + "." + CONNECTION_KEY;
69  
70      /*** default schema name for the configuration */
71      public static final String DEFAULT_SCHEMA_KEY
72              = DEFAULTS_KEY + "." + SCHEMA_KEY;
73  
74  
75      /*** The log */
76      private static Log log = LogFactory.getLog(AbstractDataSourceFactory.class);
77  
78      /*** Internal Marker for the Schema name of this database connection */
79      private String schema = null;
80  
81      /***
82       * Encapsulates setting configuration properties on
83       * <code>DataSource</code> objects.
84       *
85       * @param property the property to read from the configuration
86       * @param c the configuration to read the property from
87       * @param ds the <code>DataSource</code> instance to write the property to
88       * @throws Exception if anything goes wrong
89       */
90      protected void setProperty(String property, Configuration c, Object ds)
91          throws Exception
92      {
93          if (c == null || c.isEmpty())
94          {
95              return;
96          }
97  
98          String key = property;
99          Class dsClass = ds.getClass();
100         int dot = property.indexOf('.');
101         try
102         {
103             if (dot > 0)
104             {
105                 property = property.substring(0, dot);
106 
107                 MappedPropertyDescriptor mappedPD =
108                     new MappedPropertyDescriptor(property, dsClass);
109                 Class propertyType = mappedPD.getMappedPropertyType();
110                 Configuration subProps = c.subset(property);
111                 // use reflection to set properties
112                 Iterator j = subProps.getKeys();
113                 while (j.hasNext())
114                 {
115                     String subProp = (String) j.next();
116                     String propVal = subProps.getString(subProp);
117                     Object value = ConvertUtils.convert(propVal, propertyType);
118                     PropertyUtils
119                         .setMappedProperty(ds, property, subProp, value);
120 
121                     if (log.isDebugEnabled())
122                     {
123                         log.debug("setMappedProperty("
124                                        + ds + ", "
125                                        + property + ", "
126                                        + subProp + ", "
127                                        + value
128                                        + ")");
129                     }
130                 }
131             }
132             else
133             {
134                 if ("password".equals(key))
135                 {
136                     // do not log value of password
137                     // for this, ConvertUtils.convert cannot be used
138                     // as it also logs the value of the converted property
139                     // so it is assumed here that the password is a String
140                     String value = c.getString(property);
141                     PropertyUtils.setSimpleProperty(ds, property, value);
142                     if (log.isDebugEnabled())
143                     {
144                         log.debug("setSimpleProperty("
145                                        + ds + ", "
146                                        + property + ", "
147                                        + " (value not logged)"
148                                        + ")");
149                     }
150                 }
151                 else
152                 {
153                     Class propertyType =
154                         PropertyUtils.getPropertyType(ds, property);
155                     Object value =
156                         ConvertUtils.convert(c.getString(property), propertyType);
157                     PropertyUtils.setSimpleProperty(ds, property, value);
158 
159                     if (log.isDebugEnabled())
160                     {
161                         log.debug("setSimpleProperty("
162                                        + ds + ", "
163                                        + property + ", "
164                                        + value
165                                        + ")");
166                     }
167                 }
168             }
169         }
170         catch (RuntimeException e)
171         {
172             throw new TorqueRuntimeException(
173                 "Runtime error setting property " + property, e);
174         }
175         catch (Exception e)
176         {
177             log.error(
178                 "Property: "
179                 + property
180                 + " value: "
181                 + c.getString(key)
182                 + " is not supported by DataSource: "
183                 + ds.getClass().getName());
184         }
185     }
186 
187     /***
188      * Iterate over a Configuration subset and apply all
189      * properties to a passed object which must contain Bean
190      * setter and getter
191      *
192      * @param c The configuration subset
193      * @param o The object to apply the properties to
194      * @throws TorqueException if a property set fails
195      */
196     protected void applyConfiguration(Configuration c, Object o)
197         throws TorqueException
198     {
199         log.debug("applyConfiguration(" + c + ", " + o + ")");
200 
201         if (c != null)
202         {
203             try
204             {
205                 for (Iterator i = c.getKeys(); i.hasNext();)
206                 {
207                     String key = (String) i.next();
208                     setProperty(key, c, o);
209                 }
210             }
211             catch (Exception e)
212             {
213                 log.error(e);
214                 throw new TorqueException(e);
215             }
216         }
217     }
218 
219     /***
220      * Initializes the ConnectionPoolDataSource.
221      *
222      * @param configuration where to read the settings from
223      * @throws TorqueException if a property set fails
224      * @return a configured <code>ConnectionPoolDataSource</code>
225      */
226     protected ConnectionPoolDataSource initCPDS(Configuration configuration)
227         throws TorqueException
228     {
229         log.debug("Starting initCPDS");
230         ConnectionPoolDataSource cpds = new DriverAdapterCPDS();
231         Configuration c = Torque.getConfiguration();
232 
233         if (c == null || c.isEmpty())
234         {
235             log.warn("Global Configuration not set,"
236                     + " no Default connection pool data source configured!");
237         }
238         else
239         {
240             Configuration conf = c.subset(DEFAULT_CONNECTION_KEY);
241             applyConfiguration(conf, cpds);
242         }
243 
244         Configuration conf = configuration.subset(CONNECTION_KEY);
245         applyConfiguration(conf, cpds);
246 
247         return cpds;
248     }
249 
250     /***
251      * Sets the current schema for the database connection
252      *
253      * @param schema The current schema name
254      */
255     public void setSchema(String schema)
256     {
257         this.schema = schema;
258     }
259 
260     /***
261      * This method returns the current schema for the database connection
262      *
263      * @return The current schema name. Null means, no schema has been set.
264      * @throws TorqueException Any exceptions caught during processing will be
265      *         rethrown wrapped into a TorqueException.
266      * @deprecated use DatabaseInfo.setSchema() instead. Will be removed
267      *             in a future version of Torque.
268      */
269     public String getSchema()
270     {
271         return schema;
272     }
273 
274     /***
275      * @return the <code>DataSource</code> configured by the factory.
276      * @throws TorqueException if the source can't be returned
277      */
278     public abstract DataSource getDataSource()
279             throws TorqueException;
280 
281     /***
282      * Initialize the factory.
283      *
284      * @param configuration where to load the factory settings from
285      * @throws TorqueException Any exceptions caught during processing will be
286      *         rethrown wrapped into a TorqueException.
287      */
288     public void initialize(Configuration configuration)
289         throws TorqueException
290     {
291         if (configuration == null)
292         {
293             throw new TorqueException(
294                 "Torque cannot be initialized without "
295                     + "a valid configuration. Please check the log files "
296                     + "for further details.");
297         }
298 
299         schema = configuration.getString(SCHEMA_KEY, null);
300 
301         if (StringUtils.isEmpty(schema))
302         {
303             Configuration conf = Torque.getConfiguration();
304             schema = conf.getString(DEFAULT_SCHEMA_KEY, null);
305         }
306     }
307 }