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.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.torque.Torque;
35 import org.apache.torque.TorqueException;
36 import org.apache.torque.TorqueRuntimeException;
37
38 /**
39 * A class that contains common functionality of the factories in this
40 * package.
41 *
42 * @author <a href="mailto:jmcnally@apache.org">John McNally</a>
43 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
44 * @version $Id: AbstractDataSourceFactory.java 1336091 2012-05-09 11:09:40Z tfischer $
45 */
46 public abstract class AbstractDataSourceFactory
47 implements DataSourceFactory
48 {
49 /** "pool" Key for the configuration */
50 public static final String POOL_KEY = "pool";
51
52 /** "connection" Key for the configuration */
53 public static final String CONNECTION_KEY = "connection";
54
55 /** "defaults" Key for the configuration */
56 public static final String DEFAULTS_KEY = "defaults";
57
58 /** "defaults.pool" Key for the configuration */
59 public static final String DEFAULT_POOL_KEY
60 = DEFAULTS_KEY + "." + POOL_KEY;
61
62 /** "defaults.connection" Key for the configuration */
63 public static final String DEFAULT_CONNECTION_KEY
64 = DEFAULTS_KEY + "." + CONNECTION_KEY;
65
66 /** The log */
67 private static Log log = LogFactory.getLog(AbstractDataSourceFactory.class);
68
69 /**
70 * Encapsulates setting configuration properties on
71 * <code>DataSource</code> objects.
72 *
73 * @param property the property to read from the configuration
74 * @param c the configuration to read the property from
75 * @param ds the <code>DataSource</code> instance to write the property to
76 * @throws Exception if anything goes wrong
77 */
78 protected void setProperty(String property, Configuration c, Object ds)
79 throws Exception
80 {
81 if (c == null || c.isEmpty())
82 {
83 return;
84 }
85
86 String key = property;
87 Class<?> dsClass = ds.getClass();
88 int dot = property.indexOf('.');
89 try
90 {
91 if (dot > 0)
92 {
93 property = property.substring(0, dot);
94
95 MappedPropertyDescriptor mappedPD =
96 new MappedPropertyDescriptor(property, dsClass);
97 Class<?> propertyType = mappedPD.getMappedPropertyType();
98 Configuration subProps = c.subset(property);
99 // use reflection to set properties
100 Iterator<?> j = subProps.getKeys();
101 while (j.hasNext())
102 {
103 String subProp = (String) j.next();
104 String propVal = subProps.getString(subProp);
105 Object value = ConvertUtils.convert(propVal, propertyType);
106 PropertyUtils
107 .setMappedProperty(ds, property, subProp, value);
108
109 if (log.isDebugEnabled())
110 {
111 log.debug("setMappedProperty("
112 + ds + ", "
113 + property + ", "
114 + subProp + ", "
115 + value
116 + ")");
117 }
118 }
119 }
120 else
121 {
122 if ("password".equals(key))
123 {
124 // do not log value of password
125 // for this, ConvertUtils.convert cannot be used
126 // as it also logs the value of the converted property
127 // so it is assumed here that the password is a String
128 String value = c.getString(property);
129 PropertyUtils.setSimpleProperty(ds, property, value);
130 if (log.isDebugEnabled())
131 {
132 log.debug("setSimpleProperty("
133 + ds + ", "
134 + property + ", "
135 + " (value not logged)"
136 + ")");
137 }
138 }
139 else
140 {
141 Class<?> propertyType =
142 PropertyUtils.getPropertyType(ds, property);
143 Object value =
144 ConvertUtils.convert(c.getString(property), propertyType);
145 PropertyUtils.setSimpleProperty(ds, property, value);
146
147 if (log.isDebugEnabled())
148 {
149 log.debug("setSimpleProperty("
150 + ds + ", "
151 + property + ", "
152 + value
153 + ")");
154 }
155 }
156 }
157 }
158 catch (RuntimeException e)
159 {
160 throw new TorqueRuntimeException(
161 "Runtime error setting property " + property, e);
162 }
163 catch (Exception e)
164 {
165 log.error(
166 "Property: "
167 + property
168 + " value: "
169 + c.getString(key)
170 + " is not supported by DataSource: "
171 + ds.getClass().getName());
172 }
173 }
174
175 /**
176 * Iterate over a Configuration subset and apply all
177 * properties to a passed object which must contain Bean
178 * setter and getter
179 *
180 * @param c The configuration subset
181 * @param o The object to apply the properties to
182 * @throws TorqueException if a property set fails
183 */
184 protected void applyConfiguration(Configuration c, Object o)
185 throws TorqueException
186 {
187 log.debug("applyConfiguration(" + c + ", " + o + ")");
188
189 if (c != null)
190 {
191 try
192 {
193 for (Iterator<?> i = c.getKeys(); i.hasNext();)
194 {
195 String key = (String) i.next();
196 setProperty(key, c, o);
197 }
198 }
199 catch (Exception e)
200 {
201 log.error(e);
202 throw new TorqueException(e);
203 }
204 }
205 }
206
207 /**
208 * Initializes the ConnectionPoolDataSource.
209 *
210 * @param configuration where to read the settings from
211 * @throws TorqueException if a property set fails
212 * @return a configured <code>ConnectionPoolDataSource</code>
213 */
214 protected ConnectionPoolDataSource initCPDS(Configuration configuration)
215 throws TorqueException
216 {
217 log.debug("Starting initCPDS");
218 ConnectionPoolDataSource cpds = new DriverAdapterCPDS();
219 Configuration c = Torque.getConfiguration();
220
221 if (c == null || c.isEmpty())
222 {
223 log.warn("Global Configuration not set,"
224 + " no Default connection pool data source configured!");
225 }
226 else
227 {
228 Configuration conf = c.subset(DEFAULT_CONNECTION_KEY);
229 applyConfiguration(conf, cpds);
230 }
231
232 Configuration conf = configuration.subset(CONNECTION_KEY);
233 applyConfiguration(conf, cpds);
234
235 return cpds;
236 }
237
238 /**
239 * @return the <code>DataSource</code> configured by the factory.
240 * @throws TorqueException if the source can't be returned
241 */
242 public abstract DataSource getDataSource()
243 throws TorqueException;
244
245 /**
246 * Initialize the factory.
247 *
248 * @param configuration where to load the factory settings from
249 * @throws TorqueException Any exceptions caught during processing will be
250 * rethrown wrapped into a TorqueException.
251 */
252 public abstract void initialize(Configuration configuration)
253 throws TorqueException;
254 }