Index: jackrabbit-core/pom.xml =================================================================== --- jackrabbit-core/pom.xml (revision 774850) +++ jackrabbit-core/pom.xml (working copy) @@ -154,6 +154,11 @@ commons-io + commons-dbcp + commons-dbcp + 1.2.2 + + javax.jcr jcr Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ConnectionFactory.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ConnectionFactory.java (revision 774850) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/persistence/bundle/util/ConnectionFactory.java (working copy) @@ -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,114 @@ * @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 (Context.class.isAssignableFrom(driverClass)) { + database = getJndiDataSource((Class) 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 null if a class name is not given. + * + * @param driver driver class name + * @return driver class, or null + * @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 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 null if + * a specific driver has not been configured. + * + * @param driverClass the JDBC driver class, or null + * @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; } }