You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2009/05/26 17:16:36 UTC

svn commit: r778741 - in /jackrabbit/sandbox/JCR-1456/jackrabbit-core: pom.xml src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ConnectionFactory.java

Author: jukka
Date: Tue May 26 15:16:35 2009
New Revision: 778741

URL: http://svn.apache.org/viewvc?rev=778741&view=rev
Log:
JCR-1456: Database connection pooling

Applied proposed patch that introduces Commons DBCP and turns all configured
databse connections into (pooled) DataSources.

Obvious TODO: these DataSources will also need to be managed...

Modified:
    jackrabbit/sandbox/JCR-1456/jackrabbit-core/pom.xml
    jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ConnectionFactory.java

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/pom.xml?rev=778741&r1=778740&r2=778741&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/pom.xml (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/pom.xml Tue May 26 15:16:35 2009
@@ -154,6 +154,11 @@
       <artifactId>commons-io</artifactId>
     </dependency>
     <dependency>
+      <groupId>commons-dbcp</groupId>
+      <artifactId>commons-dbcp</artifactId>
+      <version>1.2.2</version>
+    </dependency>
+    <dependency>
       <groupId>javax.jcr</groupId>
       <artifactId>jcr</artifactId>
     </dependency>

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ConnectionFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ConnectionFactory.java?rev=778741&r1=778740&r2=778741&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ConnectionFactory.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ConnectionFactory.java Tue May 26 15:16:35 2009
@@ -17,7 +17,6 @@
 package org.apache.jackrabbit.core.persistence.bundle.util;
 
 import java.sql.Connection;
-import java.sql.DriverManager;
 import java.sql.SQLException;
 
 import javax.jcr.RepositoryException;
@@ -25,6 +24,8 @@
 import javax.naming.NamingException;
 import javax.sql.DataSource;
 
+import org.apache.commons.dbcp.BasicDataSource;
+
 /**
  * A factory for new database connections.
  * Supported are regular JDBC drivers, as well as
@@ -53,43 +54,115 @@
      * @throws RepositoryException if the driver could not be loaded
      * @throws SQLException if the connection could not be established
      */
-    public static Connection getConnection(String driver, String url,
-            String user, String password) throws RepositoryException,
-            SQLException {
-        if (driver != null && driver.length() > 0) {
+    @SuppressWarnings("unchecked")
+    public static Connection getConnection(
+            String driver, String url, String user, String password)
+            throws RepositoryException, SQLException {
+        DataSource database;
+
+        Class<?> driverClass = getDriverClass(driver);
+        if (driverClass != null
+                && Context.class.isAssignableFrom(driverClass)) {
+            database = getJndiDataSource((Class<Context>) driverClass, url);
+        } else {
+            database = getDriverDataSource(driverClass, url);
+        }
+
+        if (user == null && password == null) {
+            return database.getConnection();
+        } else {
+            return database.getConnection(user, password);
+        }
+    }
+
+    /**
+     * Loads and returns the given JDBC driver (or JNDI context) class.
+     * Returns <code>null</code> if a class name is not given.
+     *
+     * @param driver driver class name
+     * @return driver class, or <code>null</code>
+     * @throws RepositoryException if the class can not be loaded
+     */
+    private static Class<?> getDriverClass(String driver)
+            throws RepositoryException {
+        try {
+            if (driver != null && driver.length() > 0) {
+                return Class.forName(driver);
+            } else {
+                return null;
+            }
+        } catch (ClassNotFoundException e) {
+            throw new RepositoryException(
+                    "Could not load JDBC driver class " + driver, e);
+        }
+    }
+
+    /**
+     * Returns the JDBC {@link DataSource} bound to the given name in
+     * the JNDI {@link Context} identified by the given class.
+     *
+     * @param contextClass class that is instantiated to get the JNDI context 
+     * @param name name of the DataSource within the JNDI context
+     * @return the DataSource bound in JNDI
+     * @throws RepositoryException if the JNDI context can not be accessed,
+     *                             or if the named DataSource is not found
+     */
+    private static DataSource getJndiDataSource(
+            Class<Context> contextClass, String name)
+            throws RepositoryException {
+        try {
+            Object object = contextClass.newInstance().lookup(name);
+            if (object instanceof DataSource) {
+                return (DataSource) object;
+            } else {
+                throw new RepositoryException(
+                        "Object " + object + " with JNDI name "
+                        + name + " is not a JDBC DataSource");
+            }
+        } catch (InstantiationException e) {
+            throw new RepositoryException(
+                    "Invalid JNDI context: " + contextClass.getName(), e);
+        } catch (IllegalAccessException e) {
+            throw new RepositoryException(
+                    "Invalid JNDI context: " + contextClass.getName(), e);
+        } catch (NamingException e) {
+            throw new RepositoryException(
+                    "JNDI name not found: " + name, e);
+        }
+    }
+
+    /**
+     * Creates and returns a pooling JDBC {@link DataSource} for accessing
+     * the database identified by the given driver class and JDBC
+     * connection URL. The driver class can be <code>null</code> if
+     * a specific driver has not been configured.
+     *
+     * @param driverClass the JDBC driver class, or <code>null</code>
+     * @param url the JDBC connection URL
+     * @return pooling DataSource for accessing the specified database
+     */
+    private static DataSource getDriverDataSource(
+            Class<?> driverClass, String url) {
+        BasicDataSource database = new BasicDataSource();
+
+        if (driverClass != null) {
             try {
-                Class< ? > d = Class.forName(driver);
-                if (javax.naming.Context.class.isAssignableFrom(d)) {
-                    // JNDI context
-                    Context context = (Context) d.newInstance();
-                    DataSource ds = (DataSource) context.lookup(url);
-                    if (user == null && password == null) {
-                        return ds.getConnection();
-                    } else {
-                        return ds.getConnection(user, password);
-                    }
-                } else {
-                    try {
-                        // Workaround for Apache Derby:
-                        // The JDBC specification recommends the Class.forName method without the .newInstance() method call,
-                        // but it is required after a Derby 'shutdown'.
-                        d.newInstance();
-                    } catch (Throwable e) {
-                        // Ignore exceptions
-                        // There's no requirement that a JDBC driver class has a public default constructor
-                    }
-                }
-            } catch (ClassNotFoundException e) {
-                throw new RepositoryException("Could not load class " + driver, e);
-            } catch (InstantiationException e) {
-                throw new RepositoryException("Could not instantiate context " + driver, e);
-            } catch (IllegalAccessException e) {
-                throw new RepositoryException("Could not instantiate context " + driver, e);
-            } catch (NamingException e) {
-                throw new RepositoryException("Naming exception using " + driver + " url: " + url, e);
+                // Workaround for Apache Derby:
+                // The JDBC specification recommends the Class.forName
+                // method without the .newInstance() method call,
+                // but it is required after a Derby 'shutdown'
+                driverClass.newInstance();
+            } catch (Throwable e) {
+                // Ignore exceptions as there's no requirement for
+                // a JDBC driver class to have a public default constructor
             }
+
+            database.setDriverClassName(driverClass.getName());
         }
-        return DriverManager.getConnection(url, user, password);
+
+        database.setUrl(url);
+
+        return database;
     }
 
 }