SLING-3637 - Create connection pool lazily in DataSource Provider bundle

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1600198 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/extensions/datasource/internal/DataSourceFactory.java b/src/main/java/org/apache/sling/extensions/datasource/internal/DataSourceFactory.java
index f653fcc..43b5815 100644
--- a/src/main/java/org/apache/sling/extensions/datasource/internal/DataSourceFactory.java
+++ b/src/main/java/org/apache/sling/extensions/datasource/internal/DataSourceFactory.java
@@ -19,6 +19,7 @@
 package org.apache.sling.extensions.datasource.internal;
 
 import java.lang.management.ManagementFactory;
+import java.sql.SQLException;
 import java.util.Dictionary;
 import java.util.Hashtable;
 import java.util.Map;
@@ -26,7 +27,6 @@
 
 import javax.management.InstanceNotFoundException;
 import javax.management.MBeanServer;
-import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
 import javax.sql.DataSource;
 
@@ -115,10 +115,7 @@
         }
 
         dataSource = createDataSource(props, bundleContext);
-
         registerDataSource(bundleContext);
-        registerJmx();
-
         log.info("Created DataSource [{}] with properties {}", name, getDataSourceDetails());
     }
 
@@ -139,20 +136,15 @@
     private DataSource createDataSource(Properties props, BundleContext bundleContext) throws Exception {
         PoolConfiguration poolProperties = org.apache.tomcat.jdbc.pool.DataSourceFactory.parsePoolProperties(props);
 
-        DriverDataSource driverDataSource = new DriverDataSource(poolProperties, driverRegistry, bundleContext);
+        DriverDataSource driverDataSource = new DriverDataSource(poolProperties, driverRegistry,
+                bundleContext, this);
 
         //Specify the DataSource such that connection creation logic is handled
         //by us where we take care of OSGi env
         poolProperties.setDataSource(driverDataSource);
 
-        org.apache.tomcat.jdbc.pool.DataSource dataSource =
-                new org.apache.tomcat.jdbc.pool.DataSource(poolProperties);
-        //initialise the pool itself
-        ConnectionPool pool = dataSource.createPool();
-        driverDataSource.setJmxPool(pool.getJmxPool());
-
         // Return the configured DataSource instance
-        return dataSource;
+        return new LazyJmxRegisteringDataSource(poolProperties);
     }
 
     private void registerDataSource(BundleContext bundleContext) {
@@ -163,12 +155,9 @@
         dsRegistration = bundleContext.registerService(DataSource.class, dataSource, svcProps);
     }
 
-    private void registerJmx() throws MalformedObjectNameException {
-        if(dataSource instanceof DataSourceProxy){
-            org.apache.tomcat.jdbc.pool.jmx.ConnectionPool pool =
-                    ((DataSourceProxy) dataSource).getPool().getJmxPool();
-
-            if(pool == null){
+    void registerJmx(ConnectionPool pool) throws SQLException {
+            org.apache.tomcat.jdbc.pool.jmx.ConnectionPool jmxPool = pool.getJmxPool();
+            if (jmxPool == null) {
                 //jmx not enabled
                 return;
             }
@@ -176,16 +165,19 @@
             table.put("type", "ConnectionPool");
             table.put("class", DataSource.class.getName());
             table.put("name", ObjectName.quote(name));
-            jmxName = new ObjectName("org.apache.sling", table);
 
             try {
+                jmxName = new ObjectName("org.apache.sling", table);
                 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
-                mbs.registerMBean(pool, jmxName);
-            }catch(Exception e){
+                mbs.registerMBean(jmxPool, jmxName);
+            } catch (Exception e) {
                 log.warn("Error occurred while registering the JMX Bean for " +
-                        "connection pool with name {}",jmxName, e);
+                        "connection pool with name {}", jmxName, e);
             }
-        }
+    }
+
+    ConnectionPool getPool() {
+        return ((DataSourceProxy) dataSource).getPool();
     }
 
     private void unregisterJmx(){
@@ -219,6 +211,33 @@
         }
     }
 
+    private class LazyJmxRegisteringDataSource extends org.apache.tomcat.jdbc.pool.DataSource {
+        private volatile boolean initialized;
+
+        public LazyJmxRegisteringDataSource(PoolConfiguration poolProperties) {
+            super(poolProperties);
+        }
+
+        @Override
+        public ConnectionPool createPool() throws SQLException {
+            ConnectionPool pool = super.createPool();
+            registerJmxLazily(pool);
+            return pool;
+        }
+
+        private void registerJmxLazily(ConnectionPool pool) throws SQLException {
+            if(!initialized){
+                synchronized (this){
+                    if(initialized){
+                        return;
+                    }
+                    DataSourceFactory.this.registerJmx(pool);
+                    initialized = true;
+                }
+            }
+        }
+    }
+
     /**
      * Dummy impl to enable access to protected fields
      */
diff --git a/src/main/java/org/apache/sling/extensions/datasource/internal/DriverDataSource.java b/src/main/java/org/apache/sling/extensions/datasource/internal/DriverDataSource.java
index e2e0b32..58f7ccb 100644
--- a/src/main/java/org/apache/sling/extensions/datasource/internal/DriverDataSource.java
+++ b/src/main/java/org/apache/sling/extensions/datasource/internal/DriverDataSource.java
@@ -51,14 +51,16 @@
     private final DriverRegistry driverRegistry;
     private final BundleContext bundleContext;
     private final org.slf4j.Logger log = LoggerFactory.getLogger(getClass());
-    private org.apache.tomcat.jdbc.pool.jmx.ConnectionPool jmxPool;
     private Driver driver;
+    private final DataSourceFactory dataSourceFactory;
 
     public DriverDataSource(PoolConfiguration poolProperties, DriverRegistry driverRegistry,
-                            BundleContext bundleContext) {
+                            BundleContext bundleContext,
+                            DataSourceFactory dataSourceFactory) {
         this.poolProperties = poolProperties;
         this.driverRegistry = driverRegistry;
         this.bundleContext = bundleContext;
+        this.dataSourceFactory = dataSourceFactory;
     }
 
     public Connection getConnection() throws SQLException {
@@ -85,8 +87,9 @@
             if (log.isDebugEnabled()) {
                 log.debug("Unable to connect to database.", x);
             }
-            //Based on logic in org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver()
-            if (jmxPool!=null) {
+            //Based on logic in org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver()\
+            org.apache.tomcat.jdbc.pool.jmx.ConnectionPool jmxPool = getJmxPool();
+            if (jmxPool !=null) {
                 jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.NOTIFY_CONNECT,
                         ConnectionPool.getStackTrace(x));
             }
@@ -105,10 +108,6 @@
         return connection;
     }
 
-    public void setJmxPool(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool jmxPool) {
-        this.jmxPool = jmxPool;
-    }
-
     //~-------------------------------------< DataSource >
 
     public PrintWriter getLogWriter() throws SQLException {
@@ -127,6 +126,7 @@
         return 0;
     }
 
+    @SuppressWarnings("UnusedDeclaration") //Part of JDK 7
     public Logger getParentLogger() throws SQLFeatureNotSupportedException {
         throw new SQLFeatureNotSupportedException();
     }
@@ -139,6 +139,13 @@
         return false;
     }
 
+    private org.apache.tomcat.jdbc.pool.jmx.ConnectionPool getJmxPool() {
+        if(dataSourceFactory.getPool() != null){
+            return dataSourceFactory.getPool().getJmxPool();
+        }
+        return null;
+    }
+
     private Driver getDriver() throws SQLException {
         if (driver != null) {
             return driver;
@@ -151,7 +158,7 @@
             driver = findMatchingDriver(drivers);
         }
 
-        if(driver == null){
+        if(driver == null && poolProperties.getDriverClassName() != null){
             log.debug("Looking for driver for [{}] via provided className [{}]",
                     url, poolProperties.getDriverClassName());
             driver = loadDriverClass();