You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ma...@apache.org on 2009/09/10 10:35:34 UTC

svn commit: r813305 - in /jackrabbit/sandbox/JCR-1456/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/config/ main/java/org/apache/jackrabbit/core/util/db/ test/java/org/apache/jackrabbit/core/config/ test/java/org/apache/jackrabbit/core/util...

Author: martijnh
Date: Thu Sep 10 08:35:34 2009
New Revision: 813305

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

* Improved unit tests

Modified:
    jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/DataSourceConfig.java
    jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionFactory.java
    jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/DataSourceConfigTest.java
    jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/db/ConnectionFactoryTest.java

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/DataSourceConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/DataSourceConfig.java?rev=813305&r1=813304&r2=813305&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/DataSourceConfig.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/config/DataSourceConfig.java Thu Sep 10 08:35:34 2009
@@ -113,7 +113,7 @@
             this.dbType = (String) props.getProperty(DB_TYPE);
             this.validationQuery = (String) props.getProperty(VALIDATION_QUERY);
             try {
-                this.maxPoolSize = Integer.parseInt((String) props.getProperty(MAX_POOL_SIZE, "0"));
+                this.maxPoolSize = Integer.parseInt((String) props.getProperty(MAX_POOL_SIZE, "-1"));
             } catch (NumberFormatException e) {
                 throw new ConfigurationException("failed to parse " + MAX_POOL_SIZE
                         + " property for DataSource " + logicalName);

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionFactory.java?rev=813305&r1=813304&r2=813305&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionFactory.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionFactory.java Thu Sep 10 08:35:34 2009
@@ -16,7 +16,6 @@
  */
 package org.apache.jackrabbit.core.util.db;
 
-import java.lang.reflect.Field;
 import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.HashMap;
@@ -31,6 +30,8 @@
 import org.apache.commons.dbcp.DelegatingConnection;
 import org.apache.jackrabbit.core.config.DataSourceConfig;
 import org.apache.jackrabbit.core.config.DataSourceConfig.DataSourceDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * A factory for new database connections.
@@ -42,6 +43,8 @@
  */
 public class ConnectionFactory {
 
+    private static Logger log = LoggerFactory.getLogger(ConnectionFactory.class);
+
     /**
      * The lock to protect the registries. 
      */
@@ -82,7 +85,9 @@
                     if (def.getMaxPoolSize() > 0) {
                         bds.setMaxActive(def.getMaxPoolSize());
                     }
-                    bds.setValidationQuery(def.getValidationQuery());
+                    if (def.getValidationQuery() != null && !"".equals(def.getValidationQuery().trim())) {
+                        bds.setValidationQuery(def.getValidationQuery());
+                    }
                     nameToDataSource.put(def.getLogicalName(), bds);
                     nameToDataSourceDef.put(def.getLogicalName(), def);
                 }
@@ -152,20 +157,15 @@
      * 
      * This method actually assumes that we are using commons DBCP 1.2.2.
      * 
-     * @param con the commons-DBCP {@code PoolableConnection} to unwrap
+     * @param con the commons-DBCP {@code DelegatingConnection} to unwrap
      * @return the unwrapped connection
      */
     public static Connection unwrap(Connection con) throws SQLException {
-        try {
-            Field f = DelegatingConnection.class.getDeclaredField("_conn");
-            f.setAccessible(true);
-            return (Connection) f.get(con);
-        } catch (IllegalArgumentException e) {
-            throw new SQLException("failed to unwrap connection: " + e.getMessage());
-        } catch (NoSuchFieldException e) {
-            throw new SQLException("failed to unwrap connection: " + e.getMessage());
-        } catch (IllegalAccessException e) {
-            throw new SQLException("failed to unwrap connection: " + e.getMessage());
+        if (con instanceof DelegatingConnection) {
+            return ((DelegatingConnection)con).getInnermostDelegate();
+        } else {
+            throw new SQLException("failed to unwrap connection of class " + con.getClass().getName() +
+                ", expected it to be a " + DelegatingConnection.class.getName());
         }
     }
 
@@ -264,7 +264,7 @@
      */
     private static BasicDataSource getDriverDataSource(
             Class<?> driverClass, String url, String user, String password) {
-        BasicDataSource database = new BasicDataSource();
+        BasicDataSource ds = new BasicDataSource();
 
         if (driverClass != null) {
             try {
@@ -278,19 +278,33 @@
                 // a JDBC driver class to have a public default constructor
             }
 
-            database.setDriverClassName(driverClass.getName());
+            ds.setDriverClassName(driverClass.getName());
         }
 
-        database.setUrl(url);
-        database.setUsername(user);
-        database.setPassword(password);
-        database.setDefaultAutoCommit(true);
-        database.setTestOnBorrow(true);
-        database.setMaxActive(10);
-        // FIXME: we could pass the databaseType and derive a validation query from that
-//        database.setValidationQuery("select 1");
-        
-        return database;
+        ds.setUrl(url);
+        ds.setUsername(user);
+        ds.setPassword(password);
+        ds.setDefaultAutoCommit(true);
+        ds.setTestOnBorrow(true);
+        ds.setMaxActive(-1); // unlimited
+        ds.setValidationQuery(guessValidationQuery(url));   
+        ds.setAccessToUnderlyingConnectionAllowed(true);
+        ds.setPoolPreparedStatements(true);
+        ds.setMaxOpenPreparedStatements(-1); // unlimited
+        return ds;
     }
 
+    private static String guessValidationQuery(String url) {
+        if (url.contains("derby")) {
+            return "values(1)";
+        } else if (url.contains("mysql")) {
+            return "select 1";
+        } else if (url.contains("sqlserver") || url.contains("jtds")) {
+            return "select 1";
+        } else if (url.contains("oracle")) {
+            return "select 'validationQuery' from dual";
+        }
+        log.warn("Failed to guess validation query for URL " + url);
+        return null;
+    }
 }

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/DataSourceConfigTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/DataSourceConfigTest.java?rev=813305&r1=813304&r2=813305&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/DataSourceConfigTest.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/config/DataSourceConfigTest.java Thu Sep 10 08:35:34 2009
@@ -60,7 +60,7 @@
         assertNull(def.getUser());
         assertNull(def.getPassword());
         assertNull(def.getValidationQuery());
-        assertEquals(0, def.getMaxPoolSize());
+        assertEquals(-1, def.getMaxPoolSize()); // unlimited
     }
 
     public void testMultipleDefs() throws ConfigurationException {

Modified: jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/db/ConnectionFactoryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/db/ConnectionFactoryTest.java?rev=813305&r1=813304&r2=813305&view=diff
==============================================================================
--- jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/db/ConnectionFactoryTest.java (original)
+++ jackrabbit/sandbox/JCR-1456/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/util/db/ConnectionFactoryTest.java Thu Sep 10 08:35:34 2009
@@ -16,34 +16,136 @@
  */
 package org.apache.jackrabbit.core.util.db;
 
+import java.sql.Connection;
+import java.util.Properties;
+
+import javax.jcr.RepositoryException;
 import javax.sql.DataSource;
 
 import junit.framework.TestCase;
 
+import org.apache.commons.dbcp.BasicDataSource;
+import org.apache.derby.iapi.jdbc.EngineConnection;
+import org.apache.jackrabbit.core.config.ConfigurationException;
+import org.apache.jackrabbit.core.config.DataSourceConfig;
+
 /**
  * 
  */
 public class ConnectionFactoryTest extends TestCase {
 
-    private static final String DERBY_DRIVER = "org.apache.derby.jdbc.EmbeddedDriver";
+    private static final String DRIVER = "org.apache.derby.jdbc.EmbeddedDriver";
 
     private static final String DERBY_URL = "jdbc:derby:target/connection-factory-test/db;create=true";
 
-    public void testIdentity() throws Exception {
-        DataSource ds1 = ConnectionFactory.getDataSource(DERBY_DRIVER, DERBY_URL, "user", "password");
-        DataSource ds2 = ConnectionFactory.getDataSource(DERBY_DRIVER, DERBY_URL, "user", "password");
+    private static final String MYSQL_URL = "jdbc:mysql://localhost:3306/dbName?autoReconnect=true";
+
+    private static final String MSSQL_URL_1 = "jdbc:jtds:sqlserver://localhost:2433/dbName";
+
+    private static final String MSSQL_URL_2 = "jdbc:sqlserver://localhost:1433;databaseName=dbName";
+
+    private static final String ORACLE_URL = "jdbc:oracle:thin:@localhost:1521:xe";
+
+     @Override
+     public void setUp() {
+         System.setProperty("derby.stream.error.file", "target/derby-connectionfactorytest.log");
+     }
+
+    public void testGetDataSource_defaults_Derby() throws Exception {
+        DataSource ds1 = ConnectionFactory.getDataSource(DRIVER, DERBY_URL, "user", "password");
+        assertTrue(ds1 instanceof BasicDataSource);
+        BasicDataSource ds = (BasicDataSource) ds1;
+        assertEquals(-1, ds.getMaxActive());
+        assertEquals("values(1)", ds.getValidationQuery());
+        assertTrue(ds.getDefaultAutoCommit());
+        assertTrue(ds.getTestOnBorrow());
+        assertTrue(ds.isPoolPreparedStatements());
+        assertEquals(-1, ds.getMaxOpenPreparedStatements());
+    }
+
+    public void testGuessValidationQuery_MYSQL() throws Exception {
+        DataSource ds1 = ConnectionFactory.getDataSource(DRIVER, MYSQL_URL, "user", "password");
+        assertEquals("select 1", ((BasicDataSource) ds1).getValidationQuery());
+    }
+
+    public void testGuessValidationQuery_MSSQL() throws Exception {
+        DataSource ds1 = ConnectionFactory.getDataSource(DRIVER, MSSQL_URL_1, "user", "password");
+        assertEquals("select 1", ((BasicDataSource) ds1).getValidationQuery());
+        DataSource ds2 = ConnectionFactory.getDataSource(DRIVER, MSSQL_URL_2, "user", "password");
+        assertEquals("select 1", ((BasicDataSource) ds2).getValidationQuery());
+    }
+
+    public void testGuessValidationQuery_ORACLE() throws Exception {
+        DataSource ds1 = ConnectionFactory.getDataSource(DRIVER, ORACLE_URL, "user", "password");
+        assertEquals("select 'validationQuery' from dual", ((BasicDataSource) ds1).getValidationQuery());
+    }
+
+    public void testRegisterDataSources_defaultValues() throws Exception {
+        BasicDataSource ds = registerAndGet(DERBY_URL, "overwrite");
+        assertEquals(10, ds.getMaxActive());
+        assertEquals("overwrite", ds.getValidationQuery());
+        assertTrue(ds.getDefaultAutoCommit());
+        assertTrue(ds.getTestOnBorrow());
+        assertTrue(ds.isPoolPreparedStatements());
+        assertEquals(-1, ds.getMaxOpenPreparedStatements());
+    }
+
+    public void testRegisterDataSources_noValidationQuery() throws Exception {
+        BasicDataSource ds = registerAndGet(MYSQL_URL, "");
+        assertEquals("select 1", ds.getValidationQuery());
+    }
+
+    public void testGetDatabaseType() throws Exception {
+        String name = register(MYSQL_URL, "");
+        assertEquals("dbType", ConnectionFactory.getDataBaseType(name));
+    }
+
+    public void testGetDataSource_identity() throws Exception {
+        DataSource ds1 = ConnectionFactory.getDataSource(DRIVER, DERBY_URL, "user", "password");
+        DataSource ds2 = ConnectionFactory.getDataSource(DRIVER, DERBY_URL, "user", "password");
         assertSame(ds1, ds2);
     }
 
-    public void testIdentity_differentPasswords() throws Exception {
-        DataSource ds1 = ConnectionFactory.getDataSource(DERBY_DRIVER, DERBY_URL, "user", "password");
-        DataSource ds2 = ConnectionFactory.getDataSource(DERBY_DRIVER, DERBY_URL, "user", "password2");
+    public void testGetDataSource_identity_differentPasswords() throws Exception {
+        DataSource ds1 = ConnectionFactory.getDataSource(DRIVER, DERBY_URL, "user", "password");
+        DataSource ds2 = ConnectionFactory.getDataSource(DRIVER, DERBY_URL, "user", "password2");
         assertSame(ds1, ds2);
     }
 
-    public void testNonIdentity() throws Exception {
-        DataSource ds1 = ConnectionFactory.getDataSource(DERBY_DRIVER, DERBY_URL, "user", "password");
-        DataSource ds2 = ConnectionFactory.getDataSource(DERBY_DRIVER, DERBY_URL, "user2", "password");
+    public void testGetDataSource_noIdentity() throws Exception {
+        DataSource ds1 = ConnectionFactory.getDataSource(DRIVER, DERBY_URL, "user", "password");
+        DataSource ds2 = ConnectionFactory.getDataSource(DRIVER, DERBY_URL, "user2", "password");
         assertNotSame(ds1, ds2);
     }
+
+    public void testUnwrap() throws Exception {
+        DataSource ds = ConnectionFactory.getDataSource(DRIVER, DERBY_URL, "user", "password");
+        Connection wrappedCon = ds.getConnection();
+        assertNotNull(wrappedCon);
+        Connection con = ConnectionFactory.unwrap(wrappedCon);
+        assertTrue(con instanceof EngineConnection);
+    }
+
+    private BasicDataSource registerAndGet(String url, String validationQuery) throws Exception {
+        final String name = register(url, validationQuery);
+        DataSource ds = ConnectionFactory.getDataSource(name);
+        assertTrue(ds instanceof BasicDataSource);
+        return (BasicDataSource) ds;
+    }
+
+    private String register(String url, String validationQuery) throws ConfigurationException,
+            RepositoryException {
+        final String name = "some random name to not interfere with integration tests...";
+        DataSourceConfig dsc = new DataSourceConfig();
+        Properties props = new Properties();
+        props.put(DataSourceConfig.LOGICAL_NAME, name);
+        props.put(DataSourceConfig.DRIVER, "org.apache.derby.jdbc.EmbeddedDriver");
+        props.put(DataSourceConfig.URL, url);
+        props.put(DataSourceConfig.DB_TYPE, "dbType");
+        props.put(DataSourceConfig.MAX_POOL_SIZE, "10");
+        props.put(DataSourceConfig.VALIDATION_QUERY, validationQuery);
+        dsc.addDataSourceDefinition(props);
+        ConnectionFactory.registerDataSources(dsc);
+        return name;
+    }
 }