001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.dao.jdbc;
016    
017    import com.liferay.portal.kernel.dao.jdbc.DataSourceFactory;
018    import com.liferay.portal.kernel.jndi.JNDIUtil;
019    import com.liferay.portal.kernel.log.Log;
020    import com.liferay.portal.kernel.log.LogFactoryUtil;
021    import com.liferay.portal.kernel.util.PropertiesUtil;
022    import com.liferay.portal.kernel.util.SortedProperties;
023    import com.liferay.portal.kernel.util.Validator;
024    import com.liferay.portal.util.PropsUtil;
025    import com.liferay.portal.util.PropsValues;
026    import com.liferay.util.PwdGenerator;
027    
028    import com.mchange.v2.c3p0.ComboPooledDataSource;
029    
030    import java.lang.management.ManagementFactory;
031    
032    import java.util.Enumeration;
033    import java.util.Map;
034    import java.util.Properties;
035    
036    import javax.management.MBeanServer;
037    import javax.management.ObjectName;
038    
039    import javax.naming.InitialContext;
040    
041    import javax.sql.DataSource;
042    
043    import jodd.bean.BeanUtil;
044    
045    import org.apache.commons.dbcp.BasicDataSourceFactory;
046    import org.apache.tomcat.jdbc.pool.PoolProperties;
047    import org.apache.tomcat.jdbc.pool.jmx.ConnectionPool;
048    
049    import uk.org.primrose.pool.datasource.GenericDataSourceFactory;
050    
051    /**
052     * @author Brian Wing Shun Chan
053     * @author Shuyang Zhou
054     */
055    public class DataSourceFactoryImpl implements DataSourceFactory {
056    
057            public void destroyDataSource(DataSource dataSource) throws Exception {
058                    if (dataSource instanceof ComboPooledDataSource) {
059                            ComboPooledDataSource comboPooledDataSource =
060                                    (ComboPooledDataSource)dataSource;
061    
062                            comboPooledDataSource.close();
063                    }
064                    else if (dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource) {
065                            org.apache.tomcat.jdbc.pool.DataSource tomcatDataSource =
066                                    (org.apache.tomcat.jdbc.pool.DataSource)dataSource;
067    
068                            tomcatDataSource.close();
069                    }
070            }
071    
072            public DataSource initDataSource(Properties properties) throws Exception {
073                    Properties defaultProperties = PropsUtil.getProperties(
074                            "jdbc.default.", true);
075    
076                    PropertiesUtil.merge(defaultProperties, properties);
077    
078                    properties = defaultProperties;
079    
080                    String jndiName = properties.getProperty("jndi.name");
081    
082                    if (Validator.isNotNull(jndiName)) {
083                            try {
084                                    return (DataSource)JNDIUtil.lookup(
085                                            new InitialContext(), jndiName);
086                            }
087                            catch (Exception e) {
088                                    _log.error("Unable to lookup " + jndiName, e);
089                            }
090                    }
091    
092                    DataSource dataSource = null;
093    
094                    String liferayPoolProvider =
095                            PropsValues.JDBC_DEFAULT_LIFERAY_POOL_PROVIDER;
096    
097                    if (liferayPoolProvider.equalsIgnoreCase("c3p0") ||
098                            liferayPoolProvider.equalsIgnoreCase("c3po")) {
099    
100                            if (_log.isDebugEnabled()) {
101                                    _log.debug("Initializing C3P0 data source");
102                            }
103    
104                            dataSource = initDataSourceC3PO(properties);
105                    }
106                    else if (liferayPoolProvider.equalsIgnoreCase("dbcp")) {
107                            if (_log.isDebugEnabled()) {
108                                    _log.debug("Initializing DBCP data source");
109                            }
110    
111                            dataSource = initDataSourceDBCP(properties);
112                    }
113                    else if (liferayPoolProvider.equalsIgnoreCase("primrose")) {
114                            if (_log.isDebugEnabled()) {
115                                    _log.debug("Initializing Primrose data source");
116                            }
117    
118                            dataSource = initDataSourcePrimrose(properties);
119                    }
120                    else {
121                            if (_log.isDebugEnabled()) {
122                                    _log.debug("Initializing Tomcat data source");
123                            }
124    
125                            dataSource = initDataSourceTomcat(properties);
126                    }
127    
128                    if (_log.isDebugEnabled()) {
129                            _log.debug(
130                                    "Created data source " + dataSource.getClass().getName());
131    
132                            SortedProperties sortedProperties = new SortedProperties(
133                                    properties);
134    
135                            sortedProperties.list(System.out);
136                    }
137    
138                    return dataSource;
139            }
140    
141            public DataSource initDataSource(
142                            String driverClassName, String url, String userName,
143                            String password)
144                    throws Exception {
145    
146                    Properties properties = new Properties();
147    
148                    properties.setProperty("driverClassName", driverClassName);
149                    properties.setProperty("url", url);
150                    properties.setProperty("username", userName);
151                    properties.setProperty("password", password);
152    
153                    return initDataSource(properties);
154            }
155    
156            protected DataSource initDataSourceC3PO(Properties properties)
157                    throws Exception {
158    
159                    ComboPooledDataSource comboPooledDataSource =
160                            new ComboPooledDataSource();
161    
162                    String identityToken = PwdGenerator.getPassword(PwdGenerator.KEY2, 8);
163    
164                    comboPooledDataSource.setIdentityToken(identityToken);
165    
166                    Enumeration<String> enu =
167                            (Enumeration<String>)properties.propertyNames();
168    
169                    while (enu.hasMoreElements()) {
170                            String key = enu.nextElement();
171                            String value = properties.getProperty(key);
172    
173                            // Map org.apache.commons.dbcp.BasicDataSource to C3PO
174    
175                            if (key.equalsIgnoreCase("driverClassName")) {
176                                    key = "driverClass";
177                            }
178                            else if (key.equalsIgnoreCase("url")) {
179                                    key = "jdbcUrl";
180                            }
181                            else if (key.equalsIgnoreCase("username")) {
182                                    key = "user";
183                            }
184    
185                            // Ignore Liferay properties
186    
187                            if (isPropertyLiferay(key)) {
188                                    continue;
189                            }
190    
191                            // Ignore DBCP properties
192    
193                            if (isPropertyDBCP(key)) {
194                                    continue;
195                            }
196    
197                            // Ignore Primrose properties
198    
199                            if (isPropertyPrimrose(key)) {
200                                    continue;
201                            }
202    
203                            // Ignore Tomcat
204    
205                            if (isPropertyTomcat(key)) {
206                                    continue;
207                            }
208    
209                            try {
210                                    BeanUtil.setProperty(comboPooledDataSource, key, value);
211                            }
212                            catch (Exception e) {
213                                    if (_log.isWarnEnabled()) {
214                                            _log.warn(
215                                                    "Property " + key + " is not a valid C3PO property");
216                                    }
217                            }
218                    }
219    
220                    return comboPooledDataSource;
221            }
222    
223            protected DataSource initDataSourceDBCP(Properties properties)
224                    throws Exception {
225    
226                    return BasicDataSourceFactory.createDataSource(properties);
227            }
228    
229            protected DataSource initDataSourcePrimrose(Properties properties)
230                    throws Exception {
231    
232                    String poolName = PwdGenerator.getPassword(PwdGenerator.KEY2, 8);
233    
234                    properties.setProperty("poolName", poolName);
235    
236                    Enumeration<String> enu =
237                            (Enumeration<String>)properties.propertyNames();
238    
239                    while (enu.hasMoreElements()) {
240                            String key = enu.nextElement();
241    
242                            String value = properties.getProperty(key);
243    
244                            // Map org.apache.commons.dbcp.BasicDataSource to Primrose
245    
246                            if (key.equalsIgnoreCase("driverClassName")) {
247                                    key = "driverClass";
248                            }
249                            else if (key.equalsIgnoreCase("url")) {
250                                    key = "driverURL";
251                            }
252                            else if (key.equalsIgnoreCase("username")) {
253                                    key = "user";
254                            }
255    
256                            properties.setProperty(key, value);
257                    }
258    
259                    GenericDataSourceFactory genericDataSourceFactory =
260                            new GenericDataSourceFactory();
261    
262                    return genericDataSourceFactory.loadPool(poolName, properties);
263            }
264    
265            protected DataSource initDataSourceTomcat(Properties properties)
266                    throws Exception {
267    
268                    PoolProperties poolProperties = new PoolProperties();
269    
270                    for (Map.Entry<Object, Object> entry : properties.entrySet()) {
271                            String key = (String)entry.getKey();
272                            String value = (String)entry.getValue();
273    
274                            // Ignore Liferay properties
275    
276                            if (isPropertyLiferay(key)) {
277                                    continue;
278                            }
279    
280                            // Ignore C3P0 properties
281    
282                            if (isPropertyC3PO(key)) {
283                                    continue;
284                            }
285    
286                            // Ignore Primrose properties
287    
288                            if (isPropertyPrimrose(key)) {
289                                    continue;
290                            }
291    
292                            try {
293                                    BeanUtil.setProperty(poolProperties, key, value);
294                            }
295                            catch (Exception e) {
296                                    if (_log.isWarnEnabled()) {
297                                            _log.warn(
298                                                    "Property " + key + " is not a valid Tomcat JDBC " +
299                                                            "Connection Pool property");
300                                    }
301                            }
302                    }
303    
304                    String poolName = PwdGenerator.getPassword(PwdGenerator.KEY2, 8);
305    
306                    poolProperties.setName(poolName);
307    
308                    org.apache.tomcat.jdbc.pool.DataSource dataSource =
309                            new org.apache.tomcat.jdbc.pool.DataSource(poolProperties);
310    
311                    if (poolProperties.isJmxEnabled()) {
312                            org.apache.tomcat.jdbc.pool.ConnectionPool jdbcConnectionPool =
313                                    dataSource.createPool();
314    
315                            ConnectionPool jmxConnectionPool = jdbcConnectionPool.getJmxPool();
316    
317                            MBeanServer mBeanServer =
318                                    ManagementFactory.getPlatformMBeanServer();
319    
320                            ObjectName objectName = new ObjectName(
321                                    _TOMCAT_JDBC_POOL_OBJECT_NAME_PREFIX + poolName);
322    
323                            mBeanServer.registerMBean(jmxConnectionPool, objectName);
324                    }
325    
326                    return dataSource;
327            }
328    
329            protected boolean isPropertyC3PO(String key) {
330                    if (key.equalsIgnoreCase("acquireIncrement") ||
331                            key.equalsIgnoreCase("acquireRetryAttempts") ||
332                            key.equalsIgnoreCase("acquireRetryDelay") ||
333                            key.equalsIgnoreCase("connectionCustomizerClassName") ||
334                            key.equalsIgnoreCase("idleConnectionTestPeriod") ||
335                            key.equalsIgnoreCase("maxIdleTime") ||
336                            key.equalsIgnoreCase("maxPoolSize") ||
337                            key.equalsIgnoreCase("minPoolSize") ||
338                            key.equalsIgnoreCase("numHelperThreads") ||
339                            key.equalsIgnoreCase("preferredTestQuery")) {
340    
341                            return true;
342                    }
343                    else {
344                            return false;
345                    }
346            }
347    
348            protected boolean isPropertyDBCP(String key) {
349                    if (key.equalsIgnoreCase("defaultTransactionIsolation") ||
350                            key.equalsIgnoreCase("maxActive") ||
351                            key.equalsIgnoreCase("minIdle") ||
352                            key.equalsIgnoreCase("removeAbandonedTimeout")) {
353    
354                            return true;
355                    }
356                    else {
357                            return false;
358                    }
359            }
360    
361            protected boolean isPropertyLiferay(String key) {
362                    if (key.equalsIgnoreCase("jndi.name") ||
363                            key.equalsIgnoreCase("liferay.pool.provider")) {
364    
365                            return true;
366                    }
367                    else {
368                            return false;
369                    }
370            }
371    
372            protected boolean isPropertyPrimrose(String key) {
373                    if (key.equalsIgnoreCase("base") ||
374                            key.equalsIgnoreCase("connectionTransactionIsolation") ||
375                            key.equalsIgnoreCase("idleTime") ||
376                            key.equalsIgnoreCase("numberOfConnectionsToInitializeWith")) {
377    
378                            return true;
379                    }
380                    else {
381                            return false;
382                    }
383            }
384    
385            protected boolean isPropertyTomcat(String key) {
386                    if (key.equalsIgnoreCase("fairQueue") ||
387                            key.equalsIgnoreCase("jdbcInterceptors") ||
388                            key.equalsIgnoreCase("jmxEnabled") ||
389                            key.equalsIgnoreCase("timeBetweenEvictionRunsMillis") ||
390                            key.equalsIgnoreCase("useEquals")) {
391    
392                            return true;
393                    }
394                    else {
395                            return false;
396                    }
397            }
398    
399            private static final String _TOMCAT_JDBC_POOL_OBJECT_NAME_PREFIX =
400                    "TomcatJDBCPool:type=ConnectionPool,name=";
401    
402            private static Log _log = LogFactoryUtil.getLog(
403                    DataSourceFactoryImpl.class);
404    
405    }