You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by ka...@apache.org on 2014/03/31 13:42:31 UTC
svn commit: r1583304 - in /db/derby/code/trunk/java:
engine/org/apache/derby/jdbc/
testing/org/apache/derbyTesting/functionTests/tests/lang/
testing/org/apache/derbyTesting/junit/
Author: kahatlen
Date: Mon Mar 31 11:42:30 2014
New Revision: 1583304
URL: http://svn.apache.org/r1583304
Log:
DERBY-6107: Connection to classpath database fails when login timeout is set
Don't cache threads used for connecting to the database when a login
timeout is set, to prevent that the connection attempt uses the wrong
context class loader.
Added:
db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/LoginTimeoutTestSetup.java (with props)
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/jdbc/InternalDriver.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/DatabaseClassLoadingTest.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.java
Modified: db/derby/code/trunk/java/engine/org/apache/derby/jdbc/InternalDriver.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/jdbc/InternalDriver.java?rev=1583304&r1=1583303&r2=1583304&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/jdbc/InternalDriver.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/jdbc/InternalDriver.java Mon Mar 31 11:42:30 2014
@@ -39,9 +39,10 @@ import java.util.StringTokenizer;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;
@@ -94,8 +95,26 @@ public class InternalDriver implements M
*/
private static boolean deregister = true;
+ /**
+ * <p>
+ * An executor service used for executing connection attempts when a
+ * login timeout has been specified.
+ * </p>
+ *
+ * <p>
+ * DERBY-6107: Core pool size and keep alive timeout should be zero so
+ * that no threads are cached. By creating a fresh thread each time a
+ * task is submitted, we make sure that the task will run in a thread
+ * with the same context class loader as the thread that submitted the
+ * task. This is important for example when connecting to a database
+ * using the classpath subsubprotocol, and the database lives in the
+ * context class loader. If threads are cached, a task may execute in
+ * a thread that has a different context class loader.
+ * </p>
+ */
private static final ExecutorService _executorPool =
- Executors.newCachedThreadPool(new DaemonThreadFactory());
+ new ThreadPoolExecutor(0, Integer.MAX_VALUE, 0L, TimeUnit.SECONDS,
+ new SynchronousQueue<Runnable>(), new DaemonThreadFactory());
public static final InternalDriver activeDriver()
{
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/DatabaseClassLoadingTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/DatabaseClassLoadingTest.java?rev=1583304&r1=1583303&r2=1583304&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/DatabaseClassLoadingTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/DatabaseClassLoadingTest.java Mon Mar 31 11:42:30 2014
@@ -50,6 +50,7 @@ import org.apache.derbyTesting.junit.Cla
import org.apache.derbyTesting.junit.CleanDatabaseTestSetup;
import org.apache.derbyTesting.junit.JDBC;
import org.apache.derbyTesting.junit.JDBCDataSource;
+import org.apache.derbyTesting.junit.LoginTimeoutTestSetup;
import org.apache.derbyTesting.junit.SupportFilesSetup;
import org.apache.derbyTesting.junit.SecurityManagerSetup;
@@ -131,7 +132,10 @@ public class DatabaseClassLoadingTest ex
// specific classes is correct. This operation is not allowed in general.
suite.addTest(SecurityManagerSetup.noSecurityManager(
new DatabaseClassLoadingTest("testClassLoadOrdering")));
-
+
+ // Add test cases accessing a classpath database when a login
+ // timeout has been specified.
+ suite.addTest(loginTimeoutSuite());
test = new SupportFilesSetup(suite,
new String[] {
@@ -185,7 +189,46 @@ public class DatabaseClassLoadingTest ex
}
};
}
-
+
+ /**
+ * Create a test suite that verifies the fix for DERBY-6107. Connection
+ * attempts used to fail when trying to access a classpath database that
+ * lived in the context class loader, if a login timeout was used and a
+ * previous connection attempt had been made from a thread that did not
+ * have the database in its context class loader.
+ */
+ private static Test loginTimeoutSuite() throws Exception {
+ TestSuite suite = new TestSuite("Class loading with login timeout");
+
+ // First run a test when the database is not in the classpath.
+ // Expect the connection attempt to fail.
+ suite.addTest(
+ new DatabaseClassLoadingTest("testLoginTimeoutNotInClasspath"));
+
+ // Then try again with the database in the classpath. Should succeed.
+ // Failed before DERBY-6107.
+ //
+ // Only add this test case if we can close the URLClassLoader when
+ // we're done. Otherwise, we won't be able to delete the jar file
+ // afterwards. (DERBY-2162)
+ if (ClasspathSetup.supportsClose()) {
+ suite.addTest(
+ new ClasspathSetup(
+ new DatabaseClassLoadingTest("testLoginTimeoutInClasspath"),
+ SupportFilesSetup.getReadOnlyURL("dclt.jar")));
+ }
+
+ // Finally, check that the database cannot be found anymore after
+ // it has been removed from the classpath.
+ suite.addTest(
+ new DatabaseClassLoadingTest("testLoginTimeoutNotInClasspath"));
+
+ // All of this should be done with a login timeout. Set the timeout
+ // to a high value, so that the connection attempts don't actually
+ // time out.
+ return new LoginTimeoutTestSetup(suite, 100);
+ }
+
/**
* Test the routines fail before the jars that contain their
* code have been installed and/or set in the classpath.
@@ -1187,9 +1230,58 @@ public class DatabaseClassLoadingTest ex
s.close();
}
-
-
-
+
+ /**
+ * Test that a classpath database is not found when it's not in the
+ * classpath and there is a login timeout.
+ * @see #loginTimeoutSuite()
+ */
+ public void testLoginTimeoutNotInClasspath() throws SQLException {
+ checkConnectionToClasspathDB(false);
+ }
+
+ /**
+ * Test that a classpath database is found when it's in the
+ * classpath and there is a login timeout.
+ * @see #loginTimeoutSuite()
+ */
+ public void testLoginTimeoutInClasspath() throws SQLException {
+ checkConnectionToClasspathDB(true);
+ }
+
+ /**
+ * Check if it is possible to connect to a classpath database.
+ *
+ * @param databaseInClasspath if {@code true}, expect that the database
+ * can be connected to; otherwise, expect that the database cannot be
+ * found.
+ */
+ private void checkConnectionToClasspathDB(boolean databaseInClasspath) {
+ String dbName = "classpath:dbro";
+ DataSource ds = JDBCDataSource.getDataSource(dbName);
+ try {
+ ds.getConnection().close();
+ // We should only be able to get a connection if the database is
+ // in the classpath.
+ assertTrue(
+ "Could connect to database when it was not in the classpath",
+ databaseInClasspath);
+ } catch (SQLException sqle) {
+ // If the database is not in the classpath, we expect
+ // ERROR XJ004: Database 'classpath:dbro' not found.
+ if (databaseInClasspath) {
+ fail("Could not connect to the database", sqle);
+ } else {
+ assertSQLState("XJ004", sqle);
+ }
+ }
+
+ // If we managed to boot the database, shut it down again.
+ if (databaseInClasspath) {
+ JDBCDataSource.shutdownDatabase(ds);
+ }
+ }
+
private void installJar(String resource, String jarName) throws SQLException, MalformedURLException
{
URL jar = SupportFilesSetup.getReadOnlyURL(resource);
Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/LoginTimeoutTestSetup.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/LoginTimeoutTestSetup.java?rev=1583304&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/LoginTimeoutTestSetup.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/LoginTimeoutTestSetup.java Mon Mar 31 11:42:30 2014
@@ -0,0 +1,57 @@
+/*
+ * Derby - Class org.apache.derbyTesting.junit.LoginTimeoutTestSetup
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ */
+
+package org.apache.derbyTesting.junit;
+
+import junit.framework.Test;
+
+/**
+ * A decorator that changes the login timeout for the current configuration
+ * and resets it afterwards.
+ */
+public class LoginTimeoutTestSetup extends BaseJDBCTestSetup {
+
+ private int originalLoginTimeout;
+ private final int newLoginTimeout;
+
+ /**
+ * Create a decorator that makes {@code test} run with a login timeout.
+ *
+ * @param test the test to decorate
+ * @param timeout the login timeout in seconds
+ */
+ public LoginTimeoutTestSetup(Test test, int timeout) {
+ super(test);
+ newLoginTimeout = timeout;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ TestConfiguration config = getTestConfiguration();
+ originalLoginTimeout = config.getLoginTimeout();
+ config.setLoginTimeout(newLoginTimeout);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ getTestConfiguration().setLoginTimeout(originalLoginTimeout);
+ super.tearDown();
+ }
+
+}
Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/LoginTimeoutTestSetup.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.java?rev=1583304&r1=1583303&r2=1583304&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/TestConfiguration.java Mon Mar 31 11:42:30 2014
@@ -1824,6 +1824,15 @@ public final class TestConfiguration {
return connector.getLoginTimeout();
}
+ /**
+ * Set the login timeout for the connector.
+ * @param seconds the login timeout in seconds
+ * @throws SQLException if the timeout cannot be set
+ */
+ public void setLoginTimeout(int seconds) throws SQLException {
+ connector.setLoginTimeout(seconds);
+ }
+
public void waitForShutdownComplete(String physicalDatabaseName) {
String path = getDatabasePath(physicalDatabaseName);
boolean lockfilepresent = true;