View Javadoc

1   /*
2    * Copyright 2010-2012 Julien Nicoulaud <julien.nicoulaud@gmail.com>
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.dbcp;
17  
18  import javax.naming.Context;
19  import javax.naming.Name;
20  import javax.naming.RefAddr;
21  import javax.naming.Reference;
22  import javax.sql.DataSource;
23  import java.io.ByteArrayInputStream;
24  import java.sql.Connection;
25  import java.util.*;
26  
27  /**
28   * Factory for {@link ManagedBasicDataSource}.
29   * <p/>
30   * This is almost a copy/paste of {@link BasicDataSourceFactory}, since most of the required fields in
31   * {@link BasicDataSourceFactory} are private. It only adds the {@link #PROP_MBEANNAME} property to the datasource configuration
32   * properties set.
33   *
34   * @author <a href="mailto:julien.nicoulaud@gmail.com">Julien Nicoulaud</a>
35   * @see ManagedBasicDataSource
36   * @see BasicDataSourceFactory
37   * @since 0.1
38   */
39  public class ManagedBasicDataSourceFactory extends BasicDataSourceFactory {
40  
41      /**
42       * TODO Add Javadoc comment.
43       */
44      public final static String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit";
45  
46      /**
47       * TODO Add Javadoc comment.
48       */
49      public final static String PROP_DEFAULTREADONLY = "defaultReadOnly";
50  
51      /**
52       * TODO Add Javadoc comment.
53       */
54      public final static String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation";
55  
56      /**
57       * TODO Add Javadoc comment.
58       */
59      public final static String PROP_DEFAULTCATALOG = "defaultCatalog";
60  
61      /**
62       * TODO Add Javadoc comment.
63       */
64      public final static String PROP_DRIVERCLASSNAME = "driverClassName";
65  
66      /**
67       * TODO Add Javadoc comment.
68       */
69      public final static String PROP_MAXACTIVE = "maxActive";
70  
71      /**
72       * TODO Add Javadoc comment.
73       */
74      public final static String PROP_MAXIDLE = "maxIdle";
75  
76      /**
77       * TODO Add Javadoc comment.
78       */
79      public final static String PROP_MINIDLE = "minIdle";
80  
81      /**
82       * TODO Add Javadoc comment.
83       */
84      public final static String PROP_INITIALSIZE = "initialSize";
85  
86      /**
87       * TODO Add Javadoc comment.
88       */
89      public final static String PROP_MAXWAIT = "maxWait";
90  
91      /**
92       * TODO Add Javadoc comment.
93       */
94      public final static String PROP_TESTONBORROW = "testOnBorrow";
95  
96      /**
97       * TODO Add Javadoc comment.
98       */
99      public final static String PROP_TESTONRETURN = "testOnReturn";
100 
101     /**
102      * TODO Add Javadoc comment.
103      */
104     public final static String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis";
105 
106     /**
107      * TODO Add Javadoc comment.
108      */
109     public final static String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun";
110 
111     /**
112      * TODO Add Javadoc comment.
113      */
114     public final static String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis";
115 
116     /**
117      * TODO Add Javadoc comment.
118      */
119     public final static String PROP_TESTWHILEIDLE = "testWhileIdle";
120 
121     /**
122      * TODO Add Javadoc comment.
123      */
124     public final static String PROP_PASSWORD = "password";
125 
126     /**
127      * TODO Add Javadoc comment.
128      */
129     public final static String PROP_URL = "url";
130 
131     /**
132      * TODO Add Javadoc comment.
133      */
134     public final static String PROP_USERNAME = "username";
135 
136     /**
137      * TODO Add Javadoc comment.
138      */
139     public final static String PROP_VALIDATIONQUERY = "validationQuery";
140 
141     /**
142      * TODO Add Javadoc comment.
143      */
144     public final static String PROP_VALIDATIONQUERY_TIMEOUT = "validationQueryTimeout";
145 
146     /**
147      * TODO Add Javadoc comment.
148      */
149     public final static String PROP_INITCONNECTIONSQLS = "initConnectionSqls";
150 
151     /**
152      * TODO Add Javadoc comment.
153      */
154     public final static String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed";
155 
156     /**
157      * TODO Add Javadoc comment.
158      */
159     public final static String PROP_REMOVEABANDONED = "removeAbandoned";
160 
161     /**
162      * TODO Add Javadoc comment.
163      */
164     public final static String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout";
165 
166     /**
167      * TODO Add Javadoc comment.
168      */
169     public final static String PROP_LOGABANDONED = "logAbandoned";
170 
171     /**
172      * TODO Add Javadoc comment.
173      */
174     public final static String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements";
175 
176     /**
177      * TODO Add Javadoc comment.
178      */
179     public final static String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements";
180 
181     /**
182      * TODO Add Javadoc comment.
183      */
184     public final static String PROP_CONNECTIONPROPERTIES = "connectionProperties";
185 
186     /**
187      * The key for the property where one can specify the name of the {@link ManagedBasicDataSource} Mbean.
188      *
189      * @see ManagedBasicDataSource#DEFAULT_MBEAN_NAME
190      */
191     public final static String PROP_MBEANNAME = "mbeanName";
192 
193     /**
194      * TODO Add Javadoc comment.
195      */
196     public final static String[] ALL_PROPERTIES = {
197             PROP_DEFAULTAUTOCOMMIT,
198             PROP_DEFAULTREADONLY,
199             PROP_DEFAULTTRANSACTIONISOLATION,
200             PROP_DEFAULTCATALOG,
201             PROP_DRIVERCLASSNAME,
202             PROP_MAXACTIVE,
203             PROP_MAXIDLE,
204             PROP_MINIDLE,
205             PROP_INITIALSIZE,
206             PROP_MAXWAIT,
207             PROP_TESTONBORROW,
208             PROP_TESTONRETURN,
209             PROP_TIMEBETWEENEVICTIONRUNSMILLIS,
210             PROP_NUMTESTSPEREVICTIONRUN,
211             PROP_MINEVICTABLEIDLETIMEMILLIS,
212             PROP_TESTWHILEIDLE,
213             PROP_PASSWORD,
214             PROP_URL,
215             PROP_USERNAME,
216             PROP_VALIDATIONQUERY,
217             PROP_VALIDATIONQUERY_TIMEOUT,
218             PROP_INITCONNECTIONSQLS,
219             PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED,
220             PROP_REMOVEABANDONED,
221             PROP_REMOVEABANDONEDTIMEOUT,
222             PROP_LOGABANDONED,
223             PROP_POOLPREPAREDSTATEMENTS,
224             PROP_MAXOPENPREPAREDSTATEMENTS,
225             PROP_CONNECTIONPROPERTIES,
226             PROP_MBEANNAME
227     };
228 
229     /**
230      * Create and return a new {@link org.apache.commons.dbcp.ManagedBasicDataSource} instance.  If no instance can be created, return <code>null</code>
231      * instead.
232      *
233      * @param obj         The possibly null object containing location or reference information that can be used in creating an object.
234      * @param name        The name of this object relative to <code>nameCtx</code>.
235      * @param nameCtx     The context relative to which the <code>name</code> parameter is specified, or <code>null</code> if <code>name</code> is
236      *                    relative to the default initial context.
237      * @param environment The possibly null environment that is used in creating this object.
238      * @throws Exception if an exception occurs creating the instance.
239      */
240     @Override
241     public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {
242 
243         // We only know how to deal with <code>javax.naming.Reference</code>s
244         // that specify a class name of "javax.sql.DataSource"
245         if ((obj == null) || !(obj instanceof Reference)) {
246             return null;
247         }
248         Reference ref = (Reference) obj;
249         if (!"javax.sql.DataSource".equals(ref.getClassName())) {
250             return null;
251         }
252 
253         Properties properties = new Properties();
254         for (int i = 0; i < ALL_PROPERTIES.length; i++) {
255             String propertyName = ALL_PROPERTIES[i];
256             RefAddr ra = ref.get(propertyName);
257             if (ra != null) {
258                 String propertyValue = ra.getContent().toString();
259                 properties.setProperty(propertyName, propertyValue);
260             }
261         }
262 
263         return createDataSource(properties);
264     }
265 
266     /**
267      * Create and configures a {@link org.apache.commons.dbcp.ManagedBasicDataSource} instance based on the given properties.
268      *
269      * @param properties the datasource configuration properties.
270      * @throws Exception if an error occurs creating the data source.
271      */
272     public static DataSource createDataSource(Properties properties) throws Exception {
273 
274         ManagedBasicDataSource dataSource;
275         String value = null;
276 
277         value = properties.getProperty(PROP_MBEANNAME);
278         dataSource = (value != null) ? new ManagedBasicDataSource(value) : new ManagedBasicDataSource();
279 
280         value = properties.getProperty(PROP_DEFAULTAUTOCOMMIT);
281         if (value != null) {
282             dataSource.setDefaultAutoCommit(Boolean.valueOf(value).booleanValue());
283         }
284 
285         value = properties.getProperty(PROP_DEFAULTREADONLY);
286         if (value != null) {
287             dataSource.setDefaultReadOnly(Boolean.valueOf(value).booleanValue());
288         }
289 
290         value = properties.getProperty(PROP_DEFAULTTRANSACTIONISOLATION);
291         if (value != null) {
292             int level = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
293             if ("NONE".equalsIgnoreCase(value)) {
294                 level = Connection.TRANSACTION_NONE;
295             } else if ("READ_COMMITTED".equalsIgnoreCase(value)) {
296                 level = Connection.TRANSACTION_READ_COMMITTED;
297             } else if ("READ_UNCOMMITTED".equalsIgnoreCase(value)) {
298                 level = Connection.TRANSACTION_READ_UNCOMMITTED;
299             } else if ("REPEATABLE_READ".equalsIgnoreCase(value)) {
300                 level = Connection.TRANSACTION_REPEATABLE_READ;
301             } else if ("SERIALIZABLE".equalsIgnoreCase(value)) {
302                 level = Connection.TRANSACTION_SERIALIZABLE;
303             } else {
304                 try {
305                     level = Integer.parseInt(value);
306                 } catch (NumberFormatException e) {
307                     System.err.println("Could not parse defaultTransactionIsolation: " + value);
308                     System.err.println("WARNING: defaultTransactionIsolation not set");
309                     System.err.println("using default value of database driver");
310                     level = PoolableConnectionFactory.UNKNOWN_TRANSACTIONISOLATION;
311                 }
312             }
313             dataSource.setDefaultTransactionIsolation(level);
314         }
315 
316         value = properties.getProperty(PROP_DEFAULTCATALOG);
317         if (value != null) {
318             dataSource.setDefaultCatalog(value);
319         }
320 
321         value = properties.getProperty(PROP_DRIVERCLASSNAME);
322         if (value != null) {
323             dataSource.setDriverClassName(value);
324         }
325 
326         value = properties.getProperty(PROP_MAXACTIVE);
327         if (value != null) {
328             dataSource.setMaxActive(Integer.parseInt(value));
329         }
330 
331         value = properties.getProperty(PROP_MAXIDLE);
332         if (value != null) {
333             dataSource.setMaxIdle(Integer.parseInt(value));
334         }
335 
336         value = properties.getProperty(PROP_MINIDLE);
337         if (value != null) {
338             dataSource.setMinIdle(Integer.parseInt(value));
339         }
340 
341         value = properties.getProperty(PROP_INITIALSIZE);
342         if (value != null) {
343             dataSource.setInitialSize(Integer.parseInt(value));
344         }
345 
346         value = properties.getProperty(PROP_MAXWAIT);
347         if (value != null) {
348             dataSource.setMaxWait(Long.parseLong(value));
349         }
350 
351         value = properties.getProperty(PROP_TESTONBORROW);
352         if (value != null) {
353             dataSource.setTestOnBorrow(Boolean.valueOf(value).booleanValue());
354         }
355 
356         value = properties.getProperty(PROP_TESTONRETURN);
357         if (value != null) {
358             dataSource.setTestOnReturn(Boolean.valueOf(value).booleanValue());
359         }
360 
361         value = properties.getProperty(PROP_TIMEBETWEENEVICTIONRUNSMILLIS);
362         if (value != null) {
363             dataSource.setTimeBetweenEvictionRunsMillis(Long.parseLong(value));
364         }
365 
366         value = properties.getProperty(PROP_NUMTESTSPEREVICTIONRUN);
367         if (value != null) {
368             dataSource.setNumTestsPerEvictionRun(Integer.parseInt(value));
369         }
370 
371         value = properties.getProperty(PROP_MINEVICTABLEIDLETIMEMILLIS);
372         if (value != null) {
373             dataSource.setMinEvictableIdleTimeMillis(Long.parseLong(value));
374         }
375 
376         value = properties.getProperty(PROP_TESTWHILEIDLE);
377         if (value != null) {
378             dataSource.setTestWhileIdle(Boolean.valueOf(value).booleanValue());
379         }
380 
381         value = properties.getProperty(PROP_PASSWORD);
382         if (value != null) {
383             dataSource.setPassword(value);
384         }
385 
386         value = properties.getProperty(PROP_URL);
387         if (value != null) {
388             dataSource.setUrl(value);
389         }
390 
391         value = properties.getProperty(PROP_USERNAME);
392         if (value != null) {
393             dataSource.setUsername(value);
394         }
395 
396         value = properties.getProperty(PROP_VALIDATIONQUERY);
397         if (value != null) {
398             dataSource.setValidationQuery(value);
399         }
400 
401         value = properties.getProperty(PROP_VALIDATIONQUERY_TIMEOUT);
402         if (value != null) {
403             dataSource.setValidationQueryTimeout(Integer.parseInt(value));
404         }
405 
406         value = properties.getProperty(PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED);
407         if (value != null) {
408             dataSource.setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue());
409         }
410 
411         value = properties.getProperty(PROP_REMOVEABANDONED);
412         if (value != null) {
413             dataSource.setRemoveAbandoned(Boolean.valueOf(value).booleanValue());
414         }
415 
416         value = properties.getProperty(PROP_REMOVEABANDONEDTIMEOUT);
417         if (value != null) {
418             dataSource.setRemoveAbandonedTimeout(Integer.parseInt(value));
419         }
420 
421         value = properties.getProperty(PROP_LOGABANDONED);
422         if (value != null) {
423             dataSource.setLogAbandoned(Boolean.valueOf(value).booleanValue());
424         }
425 
426         value = properties.getProperty(PROP_POOLPREPAREDSTATEMENTS);
427         if (value != null) {
428             dataSource.setPoolPreparedStatements(Boolean.valueOf(value).booleanValue());
429         }
430 
431         value = properties.getProperty(PROP_MAXOPENPREPAREDSTATEMENTS);
432         if (value != null) {
433             dataSource.setMaxOpenPreparedStatements(Integer.parseInt(value));
434         }
435 
436         value = properties.getProperty(PROP_INITCONNECTIONSQLS);
437         if (value != null) {
438             StringTokenizer tokenizer = new StringTokenizer(value, ";");
439             dataSource.setConnectionInitSqls(Collections.list(tokenizer));
440         }
441 
442         value = properties.getProperty(PROP_CONNECTIONPROPERTIES);
443         if (value != null) {
444             Properties p = getProperties(value);
445             Enumeration e = p.propertyNames();
446             while (e.hasMoreElements()) {
447                 String propertyName = (String) e.nextElement();
448                 dataSource.addConnectionProperty(propertyName, p.getProperty(propertyName));
449             }
450         }
451 
452         // DBCP-215
453         // Trick to make sure that initialSize connections are created
454         if (dataSource.getInitialSize() > 0) {
455             dataSource.getLogWriter();
456         }
457 
458         // Return the configured DataSource instance
459         return dataSource;
460     }
461 
462     /**
463      * Parse properties from the string. Format of the string must be [propertyName=property;]*
464      *
465      * @param propText
466      * @return Properties
467      * @throws Exception
468      */
469     private static Properties getProperties(String propText) throws Exception {
470         Properties p = new Properties();
471         if (propText != null) {
472             p.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes()));
473         }
474         return p;
475     }
476 }