You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2015/05/03 11:18:33 UTC
[1/3] cayenne git commit: CAY-2009 Non-blocking connection pool
Repository: cayenne
Updated Branches:
refs/heads/master d28c03635 -> 517df07b7
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSource_FailingValidationQueryIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSource_FailingValidationQueryIT.java b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSource_FailingValidationQueryIT.java
new file mode 100644
index 0000000..7f7d854
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSource_FailingValidationQueryIT.java
@@ -0,0 +1,66 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import java.sql.Driver;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.conn.DataSourceInfo;
+import org.apache.cayenne.datasource.PoolingDataSource;
+import org.apache.cayenne.datasource.PoolingDataSourceParameters;
+import org.apache.cayenne.di.AdhocObjectFactory;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.log.JdbcEventLogger;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.Test;
+
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class PoolingDataSource_FailingValidationQueryIT extends ServerCase {
+
+ @Inject
+ private DataSourceInfo dataSourceInfo;
+
+ @Inject
+ private AdhocObjectFactory objectFactory;
+
+ @Inject
+ private JdbcEventLogger logger;
+
+ protected PoolingDataSourceParameters createParameters() {
+ PoolingDataSourceParameters poolParameters = new PoolingDataSourceParameters();
+ poolParameters.setMinConnections(2);
+ poolParameters.setMaxConnections(3);
+ poolParameters.setMaxQueueWaitTime(1000);
+ poolParameters.setValidationQuery("SELECT count(1) FROM NO_SUCH_TABLE");
+ return poolParameters;
+ }
+
+ @Test(expected = CayenneRuntimeException.class)
+ public void testConstructor() throws Exception {
+ Driver driver = objectFactory.newInstance(Driver.class, dataSourceInfo.getJdbcDriver());
+ DriverDataSource nonPooling = new DriverDataSource(driver, dataSourceInfo.getDataSourceUrl(),
+ dataSourceInfo.getUserName(), dataSourceInfo.getPassword());
+ nonPooling.setLogger(logger);
+
+ PoolingDataSourceParameters poolParameters = createParameters();
+ new PoolingDataSource(nonPooling, poolParameters);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSource_StaticsTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSource_StaticsTest.java b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSource_StaticsTest.java
new file mode 100644
index 0000000..114f621
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSource_StaticsTest.java
@@ -0,0 +1,41 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.cayenne.datasource.PoolingDataSource;
+import org.junit.Test;
+
+public class PoolingDataSource_StaticsTest {
+
+ @Test
+ public void testMaxIdleConnections() {
+
+ assertEquals(1, PoolingDataSource.maxIdleConnections(1, 1));
+ assertEquals(2, PoolingDataSource.maxIdleConnections(1, 2));
+ assertEquals(1, PoolingDataSource.maxIdleConnections(0, 2));
+ assertEquals(2, PoolingDataSource.maxIdleConnections(0, 3));
+ assertEquals(2, PoolingDataSource.maxIdleConnections(0, 4));
+ assertEquals(3, PoolingDataSource.maxIdleConnections(0, 5));
+ assertEquals(6, PoolingDataSource.maxIdleConnections(5, 6));
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSource_ValidationQueryIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSource_ValidationQueryIT.java b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSource_ValidationQueryIT.java
new file mode 100644
index 0000000..5d2a886
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSource_ValidationQueryIT.java
@@ -0,0 +1,56 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import static org.junit.Assert.assertEquals;
+
+import java.sql.Connection;
+
+import org.apache.cayenne.datasource.PoolingDataSourceParameters;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.Test;
+
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class PoolingDataSource_ValidationQueryIT extends BasePoolingDataSourceIT {
+
+ @Override
+ protected PoolingDataSourceParameters createParameters() {
+ PoolingDataSourceParameters params = super.createParameters();
+ params.setValidationQuery("SELECT count(1) FROM ARTIST");
+ return params;
+ }
+
+ @Test
+ public void testGetConnection_ValidationQuery() throws Exception {
+
+ assertEquals(2, dataSource.poolSize());
+ assertEquals(2, dataSource.availableSize());
+
+ Connection c1 = dataSource.getConnection();
+
+ assertEquals(2, dataSource.poolSize());
+ assertEquals(1, dataSource.availableSize());
+
+ c1.close();
+
+ assertEquals(2, dataSource.poolSize());
+ assertEquals(2, dataSource.availableSize());
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceFactory.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceFactory.java
index 43ef5f3..be4df2f 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceFactory.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceFactory.java
@@ -26,8 +26,8 @@ import java.util.Set;
import javax.sql.DataSource;
-import org.apache.cayenne.conn.DataSourceBuilder;
import org.apache.cayenne.conn.DataSourceInfo;
+import org.apache.cayenne.datasource.DataSourceBuilder;
import org.apache.cayenne.di.AdhocObjectFactory;
import org.apache.cayenne.di.Inject;
import org.apache.cayenne.log.JdbcEventLogger;
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbGeneratorTask.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbGeneratorTask.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbGeneratorTask.java
index f0f4ff2..634213b 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbGeneratorTask.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbGeneratorTask.java
@@ -23,7 +23,7 @@ import java.sql.Driver;
import java.util.Collections;
import org.apache.cayenne.access.DbGenerator;
-import org.apache.cayenne.conn.DriverDataSource;
+import org.apache.cayenne.datasource.DriverDataSource;
import org.apache.cayenne.dba.DbAdapter;
import org.apache.cayenne.di.DIBootstrap;
import org.apache.cayenne.di.Injector;
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-tools/src/main/java/org/apache/cayenne/tools/configuration/DriverDataSourceFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/configuration/DriverDataSourceFactory.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/configuration/DriverDataSourceFactory.java
index c45eefd..56c1a05 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/configuration/DriverDataSourceFactory.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/configuration/DriverDataSourceFactory.java
@@ -25,7 +25,7 @@ import javax.sql.DataSource;
import org.apache.cayenne.configuration.DataNodeDescriptor;
import org.apache.cayenne.configuration.server.DataSourceFactory;
import org.apache.cayenne.conn.DataSourceInfo;
-import org.apache.cayenne.conn.DriverDataSource;
+import org.apache.cayenne.datasource.DriverDataSource;
import org.apache.cayenne.di.AdhocObjectFactory;
import org.apache.cayenne.di.Inject;
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/docs/doc/src/main/resources/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/docs/doc/src/main/resources/RELEASE-NOTES.txt b/docs/doc/src/main/resources/RELEASE-NOTES.txt
index 5efb96d..ecc2b48 100644
--- a/docs/doc/src/main/resources/RELEASE-NOTES.txt
+++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt
@@ -21,6 +21,7 @@ CAY-2001 Saving a display state of Project
CAY-2004 EJBQL: Support for ordering on aggregate expressions
CAY-2007 Refactoring SelectTranslator for better extensibility
CAY-2008 Connection pool refactoring and validation query support in Cayenne DataSource
+CAY-2009 Non-blocking connection pool
Bug Fixes:
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/pref/DataSourcePreferences.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/pref/DataSourcePreferences.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/pref/DataSourcePreferences.java
index 94ea608..1092624 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/pref/DataSourcePreferences.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/pref/DataSourcePreferences.java
@@ -36,7 +36,7 @@ import java.util.prefs.Preferences;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JOptionPane;
-import org.apache.cayenne.conn.DriverDataSource;
+import org.apache.cayenne.datasource.DriverDataSource;
import org.apache.cayenne.modeler.FileClassLoadingService;
import org.apache.cayenne.modeler.pref.DBConnectionInfo;
import org.apache.cayenne.modeler.util.CayenneController;
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/DBConnectionInfo.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/DBConnectionInfo.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/DBConnectionInfo.java
index 005c585..e91fabf 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/DBConnectionInfo.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/pref/DBConnectionInfo.java
@@ -27,7 +27,7 @@ import javax.sql.DataSource;
import org.apache.cayenne.configuration.server.DbAdapterFactory;
import org.apache.cayenne.conn.DataSourceInfo;
-import org.apache.cayenne.conn.DriverDataSource;
+import org.apache.cayenne.datasource.DriverDataSource;
import org.apache.cayenne.dba.AutoAdapter;
import org.apache.cayenne.dba.DbAdapter;
import org.apache.cayenne.di.AdhocObjectFactory;
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/plugins/maven-cayenne-plugin/src/main/java/org/apache/cayenne/tools/DbGeneratorMojo.java
----------------------------------------------------------------------
diff --git a/plugins/maven-cayenne-plugin/src/main/java/org/apache/cayenne/tools/DbGeneratorMojo.java b/plugins/maven-cayenne-plugin/src/main/java/org/apache/cayenne/tools/DbGeneratorMojo.java
index ad4c6e9..e15c65e 100644
--- a/plugins/maven-cayenne-plugin/src/main/java/org/apache/cayenne/tools/DbGeneratorMojo.java
+++ b/plugins/maven-cayenne-plugin/src/main/java/org/apache/cayenne/tools/DbGeneratorMojo.java
@@ -23,7 +23,7 @@ import java.io.File;
import java.sql.Driver;
import org.apache.cayenne.access.DbGenerator;
-import org.apache.cayenne.conn.DriverDataSource;
+import org.apache.cayenne.datasource.DriverDataSource;
import org.apache.cayenne.dba.DbAdapter;
import org.apache.cayenne.dba.JdbcAdapter;
import org.apache.cayenne.di.AdhocObjectFactory;
[3/3] cayenne git commit: CAY-2009 Non-blocking connection pool
Posted by aa...@apache.org.
CAY-2009 Non-blocking connection pool
* moving everything into a new datasource package ("conn" package name makes no sense)
* stopped using javax.sql.ConnectionPoolDataSource. Using simple delegation
to a non-pooled DataSource instead
* non-blocking data structures for operating the pool
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/517df07b
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/517df07b
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/517df07b
Branch: refs/heads/master
Commit: 517df07b7665fb7786b4ffd519e8c9a2f3855ff9
Parents: d28c036
Author: aadamchik <aa...@apache.org>
Authored: Sun May 3 05:14:19 2015 -0400
Committer: aadamchik <aa...@apache.org>
Committed: Sun May 3 05:15:06 2015 -0400
----------------------------------------------------------------------
.../org/apache/cayenne/access/DbGenerator.java | 2 +-
.../server/PropertyDataSourceFactory.java | 4 +-
.../server/XMLPoolingDataSourceFactory.java | 4 +-
.../apache/cayenne/conn/ConnectionWrapper.java | 749 -------------------
.../apache/cayenne/conn/DataSourceBuilder.java | 140 ----
.../apache/cayenne/conn/DriverDataSource.java | 298 --------
.../cayenne/conn/ManagedPoolingDataSource.java | 155 ----
.../cayenne/conn/PooledConnectionFactory.java | 90 ---
.../cayenne/conn/PooledConnectionImpl.java | 195 -----
.../apache/cayenne/conn/PoolingDataSource.java | 471 ------------
.../conn/PoolingDataSourceParameters.java | 64 --
.../java/org/apache/cayenne/conn/package.html | 26 -
.../datasource/BadValidationQueryException.java | 41 +
.../cayenne/datasource/DataSourceBuilder.java | 135 ++++
.../cayenne/datasource/DriverDataSource.java | 298 ++++++++
.../datasource/ManagedPoolingDataSource.java | 107 +++
.../cayenne/datasource/PoolAwareConnection.java | 609 +++++++++++++++
.../cayenne/datasource/PoolingDataSource.java | 314 ++++++++
.../datasource/PoolingDataSourceManager.java | 65 ++
.../datasource/PoolingDataSourceParameters.java | 64 ++
.../cayenne/datasource/StoppedDataSource.java | 88 +++
.../cayenne/conn/BasePoolingDataSourceIT.java | 74 --
.../cayenne/conn/DriverDataSourceTest.java | 43 --
.../cayenne/conn/PooledConnectionImplTest.java | 67 --
.../cayenne/conn/PoolingDataSourceIT.java | 72 --
...lingDataSource_FailingValidationQueryIT.java | 43 --
.../PoolingDataSource_ValidationQueryIT.java | 55 --
.../datasource/BasePoolingDataSourceIT.java | 77 ++
.../datasource/DriverDataSourceTest.java | 44 ++
.../datasource/PoolAwareConnectionTest.java | 99 +++
.../cayenne/datasource/PoolingDataSourceIT.java | 160 ++++
.../datasource/PoolingDataSourceTest.java | 196 +++++
...lingDataSource_FailingValidationQueryIT.java | 66 ++
.../PoolingDataSource_StaticsTest.java | 41 +
.../PoolingDataSource_ValidationQueryIT.java | 56 ++
.../di/server/ServerCaseDataSourceFactory.java | 2 +-
.../apache/cayenne/tools/DbGeneratorTask.java | 2 +-
.../configuration/DriverDataSourceFactory.java | 2 +-
docs/doc/src/main/resources/RELEASE-NOTES.txt | 1 +
.../dialog/pref/DataSourcePreferences.java | 2 +-
.../cayenne/modeler/pref/DBConnectionInfo.java | 2 +-
.../apache/cayenne/tools/DbGeneratorMojo.java | 2 +-
42 files changed, 2472 insertions(+), 2553 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/access/DbGenerator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/DbGenerator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/DbGenerator.java
index f31f61c..275e07e 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/DbGenerator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/DbGenerator.java
@@ -36,7 +36,7 @@ import javax.sql.DataSource;
import org.apache.cayenne.ashwood.AshwoodEntitySorter;
import org.apache.cayenne.conn.DataSourceInfo;
-import org.apache.cayenne.conn.DriverDataSource;
+import org.apache.cayenne.datasource.DriverDataSource;
import org.apache.cayenne.dba.DbAdapter;
import org.apache.cayenne.dba.PkGenerator;
import org.apache.cayenne.dba.TypesMapping;
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/PropertyDataSourceFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/PropertyDataSourceFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/PropertyDataSourceFactory.java
index 60bf717..0826d7c 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/PropertyDataSourceFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/PropertyDataSourceFactory.java
@@ -24,8 +24,8 @@ import org.apache.cayenne.ConfigurationException;
import org.apache.cayenne.configuration.Constants;
import org.apache.cayenne.configuration.DataNodeDescriptor;
import org.apache.cayenne.configuration.RuntimeProperties;
-import org.apache.cayenne.conn.DataSourceBuilder;
-import org.apache.cayenne.conn.PoolingDataSource;
+import org.apache.cayenne.datasource.DataSourceBuilder;
+import org.apache.cayenne.datasource.PoolingDataSource;
import org.apache.cayenne.di.AdhocObjectFactory;
import org.apache.cayenne.di.Inject;
import org.apache.cayenne.log.JdbcEventLogger;
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/XMLPoolingDataSourceFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/XMLPoolingDataSourceFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/XMLPoolingDataSourceFactory.java
index a62a2d9..c333325 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/XMLPoolingDataSourceFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/XMLPoolingDataSourceFactory.java
@@ -24,9 +24,9 @@ import org.apache.cayenne.ConfigurationException;
import org.apache.cayenne.configuration.Constants;
import org.apache.cayenne.configuration.DataNodeDescriptor;
import org.apache.cayenne.configuration.RuntimeProperties;
-import org.apache.cayenne.conn.DataSourceBuilder;
import org.apache.cayenne.conn.DataSourceInfo;
-import org.apache.cayenne.conn.PoolingDataSource;
+import org.apache.cayenne.datasource.DataSourceBuilder;
+import org.apache.cayenne.datasource.PoolingDataSource;
import org.apache.cayenne.di.AdhocObjectFactory;
import org.apache.cayenne.di.Inject;
import org.apache.cayenne.log.JdbcEventLogger;
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/conn/ConnectionWrapper.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/conn/ConnectionWrapper.java b/cayenne-server/src/main/java/org/apache/cayenne/conn/ConnectionWrapper.java
deleted file mode 100644
index 006a72a..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/conn/ConnectionWrapper.java
+++ /dev/null
@@ -1,749 +0,0 @@
-/*****************************************************************
- * 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.cayenne.conn;
-
-import java.sql.Array;
-import java.sql.Blob;
-import java.sql.CallableStatement;
-import java.sql.Clob;
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.NClob;
-import java.sql.PreparedStatement;
-import java.sql.SQLClientInfoException;
-import java.sql.SQLException;
-import java.sql.SQLWarning;
-import java.sql.SQLXML;
-import java.sql.Savepoint;
-import java.sql.Statement;
-import java.sql.Struct;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.Executor;
-
-/**
- * ConnectionWrapper is a <code>java.sql.Connection</code> implementation that wraps
- * another Connection, delegating method calls to this connection. It works in conjunction
- * with PooledConnectionImpl, to generate pool events, provide limited automated
- * reconnection functionality, etc.
- *
- */
-public class ConnectionWrapper implements Connection {
-
- private Connection connection;
- private PooledConnectionImpl pooledConnection;
- private long lastReconnected;
- private int reconnectCount;
-
- /**
- * Fixes Sybase problems with autocommit. Used idea from Jonas
- * org.objectweb.jonas.jdbc_xa.ConnectionImpl (http://www.objectweb.org/jonas/).
- * <p>
- * If problem is not the one that can be fixed by this patch, original exception is
- * rethrown. If exception occurs when fixing the problem, new exception is thrown.
- * </p>
- */
- static void sybaseAutoCommitPatch(Connection c, SQLException e, boolean autoCommit)
- throws SQLException {
-
- String s = e.getMessage().toLowerCase();
- if (s.contains("set chained command not allowed")) {
- c.commit();
- c.setAutoCommit(autoCommit); // Shouldn't fail now.
- }
- else {
- throw e;
- }
- }
-
- /**
- * Creates new ConnectionWrapper
- */
- public ConnectionWrapper(Connection connection, PooledConnectionImpl pooledConnection) {
- this.connection = connection;
- this.pooledConnection = pooledConnection;
- }
-
- protected void reconnect(SQLException exception) throws SQLException {
-
- // if there was a relatively recent reconnect, just rethrow an error
- // and retire itself. THIS WILL PREVENT RECONNECT LOOPS
- if (reconnectCount > 0 && System.currentTimeMillis() - lastReconnected < 60000) {
-
- retire(exception);
- throw exception;
- }
-
- pooledConnection.reconnect();
-
- // Pooled connection will wrap returned connection into
- // another ConnectionWrapper.... lets get the real connection
- // underneath...
- Connection connection = pooledConnection.getConnection();
- if (connection instanceof ConnectionWrapper) {
- this.connection = ((ConnectionWrapper) connection).connection;
- }
- else {
- this.connection = connection;
- }
-
- lastReconnected = System.currentTimeMillis();
- reconnectCount++;
- }
-
- protected void retire(SQLException exception) {
- // notify all the listeners....
- pooledConnection.connectionErrorNotification(exception);
- }
-
- @Override
- public void clearWarnings() throws SQLException {
- try {
- connection.clearWarnings();
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public void close() throws SQLException {
- if (null != pooledConnection) {
- pooledConnection.returnConnectionToThePool();
- }
- connection = null;
- pooledConnection = null;
- }
-
- @Override
- public void commit() throws SQLException {
- try {
- connection.commit();
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public Statement createStatement() throws SQLException {
- try {
- return connection.createStatement();
- }
- catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return createStatement();
- }
- }
-
- @Override
- public Statement createStatement(int resultSetType, int resultSetConcurrency)
- throws SQLException {
- try {
- return connection.createStatement(resultSetType, resultSetConcurrency);
- }
- catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return createStatement(resultSetType, resultSetConcurrency);
- }
- }
-
- @Override
- public boolean getAutoCommit() throws SQLException {
- try {
- return connection.getAutoCommit();
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public String getCatalog() throws SQLException {
- try {
- return connection.getCatalog();
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public DatabaseMetaData getMetaData() throws SQLException {
- try {
- return connection.getMetaData();
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public int getTransactionIsolation() throws SQLException {
- try {
- return connection.getTransactionIsolation();
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public SQLWarning getWarnings() throws SQLException {
- try {
- return connection.getWarnings();
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public boolean isClosed() throws SQLException {
- if (connection != null) {
- try {
- return connection.isClosed();
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
- else
- return true;
- }
-
- @Override
- public boolean isReadOnly() throws SQLException {
- try {
- return connection.isReadOnly();
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public String nativeSQL(String sql) throws SQLException {
- try {
- return connection.nativeSQL(sql);
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public CallableStatement prepareCall(String sql) throws SQLException {
- try {
- return connection.prepareCall(sql);
- }
- catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return prepareCall(sql);
- }
- }
-
- @Override
- public CallableStatement prepareCall(
- String sql,
- int resultSetType,
- int resultSetConcurrency) throws SQLException {
- try {
- return connection.prepareCall(sql, resultSetType, resultSetConcurrency);
- }
- catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return prepareCall(sql, resultSetType, resultSetConcurrency);
- }
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql) throws SQLException {
- try {
- return connection.prepareStatement(sql);
- }
- catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return prepareStatement(sql);
- }
- }
-
- @Override
- public PreparedStatement prepareStatement(
- String sql,
- int resultSetType,
- int resultSetConcurrency) throws SQLException {
- try {
- return connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
- }
- catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return prepareStatement(sql, resultSetType, resultSetConcurrency);
- }
- }
-
- @Override
- public void rollback() throws SQLException {
- try {
- connection.rollback();
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public void setAutoCommit(boolean autoCommit) throws SQLException {
- try {
- connection.setAutoCommit(autoCommit);
- }
- catch (SQLException sqlEx) {
-
- try {
- // apply Sybase patch
- sybaseAutoCommitPatch(connection, sqlEx, autoCommit);
- }
- catch (SQLException patchEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
- }
-
- @Override
- public void setCatalog(String catalog) throws SQLException {
- try {
- connection.setCatalog(catalog);
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public void setReadOnly(boolean readOnly) throws SQLException {
- try {
- connection.setReadOnly(readOnly);
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public void setTransactionIsolation(int level) throws SQLException {
- try {
- connection.setTransactionIsolation(level);
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public Map<String,Class<?>> getTypeMap() throws SQLException {
- try {
- return connection.getTypeMap();
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
- try {
- connection.setTypeMap(map);
- }
- catch (SQLException sqlEx) {
- retire(sqlEx);
- throw sqlEx;
- }
- }
-
- @Override
- public void setHoldability(int holdability) throws SQLException {
- throw new java.lang.UnsupportedOperationException(
- "Method setHoldability() not yet implemented.");
- }
-
- @Override
- public int getHoldability() throws SQLException {
- throw new java.lang.UnsupportedOperationException(
- "Method getHoldability() not yet implemented.");
- }
-
- @Override
- public Savepoint setSavepoint() throws SQLException {
- throw new java.lang.UnsupportedOperationException(
- "Method setSavepoint() not yet implemented.");
- }
-
- @Override
- public Savepoint setSavepoint(String name) throws SQLException {
- throw new java.lang.UnsupportedOperationException(
- "Method setSavepoint() not yet implemented.");
- }
-
- @Override
- public void rollback(Savepoint savepoint) throws SQLException {
- throw new java.lang.UnsupportedOperationException(
- "Method rollback() not yet implemented.");
- }
-
- @Override
- public void releaseSavepoint(Savepoint savepoint) throws SQLException {
- throw new java.lang.UnsupportedOperationException(
- "Method releaseSavepoint() not yet implemented.");
- }
-
- @Override
- public Statement createStatement(
- int resultSetType,
- int resultSetConcurrency,
- int resultSetHoldability) throws SQLException {
- throw new java.lang.UnsupportedOperationException(
- "Method createStatement() not yet implemented.");
- }
-
- @Override
- public PreparedStatement prepareStatement(
- String sql,
- int resultSetType,
- int resultSetConcurrency,
- int resultSetHoldability) throws SQLException {
- throw new java.lang.UnsupportedOperationException(
- "Method prepareStatement() not yet implemented.");
- }
-
- @Override
- public CallableStatement prepareCall(
- String sql,
- int resultSetType,
- int resultSetConcurrency,
- int resultSetHoldability) throws SQLException {
- try {
- return connection.prepareCall(
- sql,
- resultSetType,
- resultSetConcurrency,
- resultSetHoldability);
- }
- catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return prepareCall(
- sql,
- resultSetType,
- resultSetConcurrency,
- resultSetHoldability);
- }
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
- throws SQLException {
-
- try {
- return connection.prepareStatement(sql, autoGeneratedKeys);
- }
- catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return prepareStatement(sql, autoGeneratedKeys);
- }
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
- throws SQLException {
- try {
- return connection.prepareStatement(sql, columnIndexes);
- }
- catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return prepareStatement(sql, columnIndexes);
- }
- }
-
- @Override
- public PreparedStatement prepareStatement(String sql, String[] columnNames)
- throws SQLException {
- try {
- return connection.prepareStatement(sql, columnNames);
- }
- catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return prepareStatement(sql, columnNames);
- }
- }
-
- /**
- * @since 3.0
- */
- @Override
- public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
- try {
- return connection.createArrayOf(typeName, elements);
- }
- catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return createArrayOf(typeName, elements);
- }
- }
-
- /**
- * @since 3.0
- */
- @Override
- public Blob createBlob() throws SQLException {
- try {
- return connection.createBlob();
- } catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return createBlob();
- }
- }
-
- /**
- * @since 3.0
- */
- @Override
- public Clob createClob() throws SQLException {
- try {
- return connection.createClob();
- } catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return createClob();
- }
- }
-
- /**
- * @since 3.0
- */
- @Override
- public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
- try {
- return connection.createStruct(typeName, attributes);
- } catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return createStruct(typeName, attributes);
- }
- }
-
- /**
- * @since 3.0
- */
- @Override
- public Properties getClientInfo() throws SQLException {
- try {
- return connection.getClientInfo();
- } catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return getClientInfo();
- }
- }
-
- /**
- * @since 3.0
- */
- @Override
- public String getClientInfo(String name) throws SQLException {
- try {
- return connection.getClientInfo(name);
- } catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return getClientInfo(name);
- }
- }
-
- /**
- * @since 3.0
- */
- @Override
- public boolean isValid(int timeout) throws SQLException {
- try {
- return connection.isValid(timeout);
- } catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return isValid(timeout);
- }
- }
-
- /**
- * @since 3.0
- */
- @Override
- public boolean isWrapperFor(Class<?> iface) throws SQLException {
- // TODO: we can implement that now.
- throw new UnsupportedOperationException();
- }
-
- /**
- * @since 3.0
- */
- @Override
- public <T> T unwrap(Class<T> iface) throws SQLException {
- // TODO: we can implement that now.
- throw new UnsupportedOperationException();
- }
-
- /**
- * @since 3.0
- */
- @Override
- public NClob createNClob() throws SQLException {
- try {
- return connection.createNClob();
- } catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return createNClob();
- }
- }
-
- /**
- * @since 3.0
- */
- @Override
- public SQLXML createSQLXML() throws SQLException {
- try {
- return connection.createSQLXML();
- } catch (SQLException sqlEx) {
-
- // reconnect has code to prevent loops
- reconnect(sqlEx);
- return createSQLXML();
- }
- }
-
- /**
- * @since 3.0
- */
- // JDBC 4 compatibility under Java 1.5
- @Override
- public void setClientInfo(Properties properties) throws SQLClientInfoException {
- // TODO: we can implement that now.
- throw new UnsupportedOperationException();
- }
-
- /**
- * @since 3.0
- */
- // JDBC 4 compatibility under Java 1.5
- @Override
- public void setClientInfo(String name, String value) throws SQLClientInfoException {
- // TODO: we can implement that now.
- throw new UnsupportedOperationException();
- }
-
- /**
- * @since 3.1
- *
- * JDBC 4.1 compatibility under Java 1.5
- */
- public void setSchema(String schema) throws SQLException {
- throw new UnsupportedOperationException();
- }
-
- /**
- * @since 3.1
- *
- * JDBC 4.1 compatibility under Java 1.5
- */
- public String getSchema() throws SQLException {
- throw new UnsupportedOperationException();
- }
-
- /**
- * @since 3.1
- *
- * JDBC 4.1 compatibility under Java 1.5
- */
- public void abort(Executor executor) throws SQLException {
- throw new UnsupportedOperationException();
- }
-
- /**
- * @since 3.1
- *
- * JDBC 4.1 compatibility under Java 1.5
- */
- public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
- throw new UnsupportedOperationException();
- }
-
- /**
- * @since 3.1
- *
- * JDBC 4.1 compatibility under Java 1.5
- */
- public int getNetworkTimeout() throws SQLException {
- throw new UnsupportedOperationException();
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/conn/DataSourceBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/conn/DataSourceBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/conn/DataSourceBuilder.java
deleted file mode 100644
index 504a053..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/conn/DataSourceBuilder.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*****************************************************************
- * 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.cayenne.conn;
-
-import java.sql.Driver;
-
-import javax.sql.DataSource;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.di.AdhocObjectFactory;
-import org.apache.cayenne.log.JdbcEventLogger;
-import org.apache.cayenne.log.NoopJdbcEventLogger;
-
-/**
- * A builder class that creates a default Cayenne implementation of a pooling
- * {@link DataSource}.
- *
- * @since 4.0
- */
-public class DataSourceBuilder {
-
- private AdhocObjectFactory objectFactory;
- private JdbcEventLogger logger;
- private String userName;
- private String password;
- private String driver;
- private String url;
- private PoolingDataSourceParameters poolParameters;
-
- public static DataSourceBuilder builder(AdhocObjectFactory objectFactory, JdbcEventLogger logger) {
- return new DataSourceBuilder(objectFactory, logger);
- }
-
- private DataSourceBuilder(AdhocObjectFactory objectFactory, JdbcEventLogger logger) {
- this.objectFactory = objectFactory;
- this.logger = logger;
- this.logger = NoopJdbcEventLogger.getInstance();
- this.poolParameters = new PoolingDataSourceParameters();
-
- poolParameters.setMinConnections(1);
- poolParameters.setMaxConnections(1);
- poolParameters.setMaxQueueWaitTime(PoolingDataSource.MAX_QUEUE_WAIT_DEFAULT);
- }
-
- public DataSourceBuilder userName(String userName) {
- this.userName = userName;
- return this;
- }
-
- public DataSourceBuilder password(String password) {
- this.password = password;
- return this;
- }
-
- public DataSourceBuilder driver(String driver) {
- this.driver = driver;
- return this;
- }
-
- public DataSourceBuilder url(String url) {
- this.url = url;
- return this;
- }
-
- public DataSourceBuilder minConnections(int minConnections) {
- poolParameters.setMinConnections(minConnections);
- return this;
- }
-
- public DataSourceBuilder maxConnections(int maxConnections) {
- poolParameters.setMaxConnections(maxConnections);
- return this;
- }
-
- public DataSourceBuilder maxQueueWaitTime(long maxQueueWaitTime) {
- poolParameters.setMaxQueueWaitTime(maxQueueWaitTime);
- return this;
- }
-
- public DataSourceBuilder validationQuery(String validationQuery) {
- poolParameters.setValidationQuery(validationQuery);
- return this;
- }
-
- public DataSource build() {
-
- // sanity checks...
- if (poolParameters.getMaxConnections() < 0) {
- throw new CayenneRuntimeException("Maximum number of connections can not be negative ("
- + poolParameters.getMaxConnections() + ").");
- }
-
- if (poolParameters.getMinConnections() < 0) {
- throw new CayenneRuntimeException("Minimum number of connections can not be negative ("
- + poolParameters.getMinConnections() + ").");
- }
-
- if (poolParameters.getMinConnections() > poolParameters.getMaxConnections()) {
- throw new CayenneRuntimeException("Minimum number of connections can not be bigger then maximum.");
- }
-
- DataSource nonPooling = buildNonPoolingDataSource();
- return buildPoolingDataSource(new PooledConnectionFactory(nonPooling));
- }
-
- private DataSource buildNonPoolingDataSource() {
- Driver driver = objectFactory.newInstance(Driver.class, this.driver);
- DriverDataSource dataSource = new DriverDataSource(driver, url, userName, password);
- dataSource.setLogger(logger);
- return dataSource;
- }
-
- private DataSource buildPoolingDataSource(PooledConnectionFactory connectionFactory) {
- PoolingDataSource poolDS;
- try {
- poolDS = new PoolingDataSource(connectionFactory, poolParameters);
- } catch (Exception e) {
- logger.logConnectFailure(e);
- throw new CayenneRuntimeException("Error creating DataSource", e);
- }
-
- return new ManagedPoolingDataSource(poolDS);
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/conn/DriverDataSource.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/conn/DriverDataSource.java b/cayenne-server/src/main/java/org/apache/cayenne/conn/DriverDataSource.java
deleted file mode 100644
index 0cf9afc..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/conn/DriverDataSource.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*****************************************************************
- * 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.cayenne.conn;
-
-import java.io.PrintWriter;
-import java.sql.Connection;
-import java.sql.Driver;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.sql.SQLFeatureNotSupportedException;
-import java.util.Properties;
-import java.util.logging.Logger;
-
-import javax.sql.DataSource;
-
-import org.apache.cayenne.log.JdbcEventLogger;
-import org.apache.cayenne.util.Util;
-
-/**
- * A non-pooling DataSource implementation wrapping a JDBC driver.
- *
- */
-public class DriverDataSource implements DataSource {
-
- protected Driver _driver;
- protected String driverClassName;
-
- protected String connectionUrl;
- protected String userName;
- protected String password;
-
- protected JdbcEventLogger logger;
-
- /**
- * Loads JDBC driver using current thread class loader.
- *
- * @since 3.0
- * @deprecated since 4.0 as class loading should not happen here.
- */
- @Deprecated
- private static Driver loadDriver(String driverClassName) throws SQLException {
-
- Class<?> driverClass;
- try {
- driverClass = Util.getJavaClass(driverClassName);
- }
- catch (Exception ex) {
- throw new SQLException("Can not load JDBC driver named '"
- + driverClassName
- + "': "
- + ex.getMessage());
- }
-
- try {
- return (Driver) driverClass.newInstance();
- }
- catch (Exception ex) {
- throw new SQLException("Error instantiating driver '"
- + driverClassName
- + "': "
- + ex.getMessage());
- }
- }
-
- /**
- * Creates a new DriverDataSource. If "driverClassName" is null, DriverDataSource will
- * consult DriverManager for a registered driver for the given URL. So when specifying
- * null, a user must take care of registering the driver. "connectionUrl" on the other
- * hand must NOT be null.
- */
- public DriverDataSource(String driverClassName, String connectionUrl) {
- this(driverClassName, connectionUrl, null, null);
- }
-
- /**
- * Creates a new DriverDataSource. If "driverClassName" is null, DriverDataSource will
- * consult DriverManager for a registered driver for the given URL. So when specifying
- * null, a user must take care of registering the driver. "connectionUrl" on the other
- * hand must NOT be null.
- *
- * @since 3.0
- */
- public DriverDataSource(String driverClassName, String connectionUrl,
- String userName, String password) {
-
- setDriverClassName(driverClassName);
-
- this.connectionUrl = connectionUrl;
- this.userName = userName;
- this.password = password;
- }
-
- /**
- * Creates a new DriverDataSource wrapping a given Driver. If "driver" is null,
- * DriverDataSource will consult DriverManager for a registered driver for the given
- * URL. So when specifying null, a user must take care of registering the driver.
- * "connectionUrl" on the other hand must NOT be null.
- *
- * @since 1.1
- */
- public DriverDataSource(Driver driver, String connectionUrl, String userName,
- String password) {
-
- this._driver = driver;
- this.driverClassName = driver.getClass().getName();
- this.connectionUrl = connectionUrl;
- this.userName = userName;
- this.password = password;
- }
-
- /**
- * Returns a new database connection, using preconfigured data to locate the database
- * and obtain a connection.
- */
- public Connection getConnection() throws SQLException {
- // login with internal credentials
- return getConnection(userName, password);
- }
-
- /**
- * Returns a new database connection using provided credentials to login to the
- * database.
- */
- public Connection getConnection(String userName, String password) throws SQLException {
- try {
- if (logger != null) {
- logger.logConnect(connectionUrl, userName, password);
- }
-
- Connection c = null;
-
- if (getDriver() == null) {
- c = DriverManager.getConnection(connectionUrl, userName, password);
- }
- else {
- Properties connectProperties = new Properties();
-
- if (userName != null) {
- connectProperties.put("user", userName);
- }
-
- if (password != null) {
- connectProperties.put("password", password);
- }
- c = getDriver().connect(connectionUrl, connectProperties);
- }
-
- // some drivers (Oracle) return null connections instead of throwing
- // an exception... fix it here
-
- if (c == null) {
- throw new SQLException("Can't establish connection: " + connectionUrl);
- }
-
- if (logger != null) {
- logger.logConnectSuccess();
- }
-
- return c;
- }
- catch (SQLException sqlex) {
- if (logger != null) {
- logger.logConnectFailure(sqlex);
- }
-
- throw sqlex;
- }
- }
-
- public int getLoginTimeout() throws SQLException {
- return -1;
- }
-
- public void setLoginTimeout(int seconds) throws SQLException {
- // noop
- }
-
- public PrintWriter getLogWriter() throws SQLException {
- return DriverManager.getLogWriter();
- }
-
- public void setLogWriter(PrintWriter out) throws SQLException {
- DriverManager.setLogWriter(out);
- }
-
- public JdbcEventLogger getLogger() {
- return logger;
- }
-
- public void setLogger(JdbcEventLogger delegate) {
- logger = delegate;
- }
-
- /**
- * @since 3.0
- */
- public String getConnectionUrl() {
- return connectionUrl;
- }
-
- /**
- * @since 3.0
- */
- public void setConnectionUrl(String connectionUrl) {
- this.connectionUrl = connectionUrl;
- }
-
- /**
- * @since 3.0
- */
- public String getPassword() {
- return password;
- }
-
- /**
- * @since 3.0
- */
- public void setPassword(String password) {
- this.password = password;
- }
-
- /**
- * @since 3.0
- */
- public String getUserName() {
- return userName;
- }
-
- /**
- * @since 3.0
- */
- public void setUserName(String userName) {
- this.userName = userName;
- }
-
- public String getDriverClassName() {
- return driverClassName;
- }
-
- public void setDriverClassName(String driverClassName) {
- if (!Util.nullSafeEquals(getDriverClassName(), driverClassName)) {
- this.driverClassName = driverClassName;
- this._driver = null; // force reload
- }
- }
-
- /**
- * Lazily instantiate the driver class to prevent errors for connections that are never opened
- */
- private Driver getDriver() throws SQLException {
- if (_driver == null && driverClassName != null) {
- _driver = loadDriver(driverClassName);
- }
- return _driver;
- }
-
- /**
- * @since 3.0
- */
- // JDBC 4 compatibility under Java 1.5
- public boolean isWrapperFor(Class<?> iface) throws SQLException {
- throw new UnsupportedOperationException();
- }
-
- /**
- * @since 3.0
- */
- // JDBC 4 compatibility under Java 1.5
- public <T> T unwrap(Class<T> iface) throws SQLException {
- throw new UnsupportedOperationException();
- }
-
- /**
- * @since 3.1
- *
- * JDBC 4.1 compatibility under Java 1.5
- */
- public Logger getParentLogger() throws SQLFeatureNotSupportedException {
- throw new UnsupportedOperationException();
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/conn/ManagedPoolingDataSource.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/conn/ManagedPoolingDataSource.java b/cayenne-server/src/main/java/org/apache/cayenne/conn/ManagedPoolingDataSource.java
deleted file mode 100644
index 357c3e0..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/conn/ManagedPoolingDataSource.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*****************************************************************
- * 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.cayenne.conn;
-
-import java.io.PrintWriter;
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.sql.SQLFeatureNotSupportedException;
-import java.util.logging.Logger;
-
-import javax.sql.DataSource;
-
-import org.apache.cayenne.di.ScopeEventListener;
-
-/**
- * A wrapper for {@link PoolingDataSourceManager} that manages the underlying
- * connection pool size, shrinking it if needed.
- *
- * @since 4.0
- */
-public class ManagedPoolingDataSource implements DataSource, ScopeEventListener {
-
- private PoolingDataSourceManager dataSourceManager;
- private PoolingDataSource dataSource;
-
- public ManagedPoolingDataSource(PoolingDataSource dataSource) {
-
- this.dataSource = dataSource;
- this.dataSourceManager = new PoolingDataSourceManager();
-
- dataSourceManager.start();
- }
-
- @Override
- public void beforeScopeEnd() {
- dataSourceManager.shouldStop();
- }
-
- @Override
- public Connection getConnection() throws SQLException {
- return dataSource.getConnection();
- }
-
- @Override
- public Connection getConnection(String username, String password) throws SQLException {
- return dataSource.getConnection(username, password);
- }
-
- @Override
- public PrintWriter getLogWriter() throws SQLException {
- return dataSource.getLogWriter();
- }
-
- @Override
- public int getLoginTimeout() throws SQLException {
- return dataSource.getLoginTimeout();
- }
-
- @Override
- public boolean isWrapperFor(Class<?> iface) throws SQLException {
- return (ManagedPoolingDataSource.class.equals(iface)) ? true : dataSource.isWrapperFor(iface);
- }
-
- @Override
- public void setLogWriter(PrintWriter arg0) throws SQLException {
- dataSource.setLogWriter(arg0);
- }
-
- @Override
- public void setLoginTimeout(int arg0) throws SQLException {
- dataSource.setLoginTimeout(arg0);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public <T> T unwrap(Class<T> iface) throws SQLException {
- return ManagedPoolingDataSource.class.equals(iface) ? (T) this : dataSource.unwrap(iface);
- }
-
- // JDBC 4.1 compatibility under Java 1.6 and newer
- public Logger getParentLogger() throws SQLFeatureNotSupportedException {
- throw new UnsupportedOperationException();
- }
-
- boolean shouldShrinkPool() {
- int unused = dataSource.getCurrentlyUnused();
- int used = dataSource.getCurrentlyInUse();
- int total = unused + used;
- int median = dataSource.getMinConnections() + 1
- + (dataSource.getMaxConnections() - dataSource.getMinConnections()) / 2;
-
- return unused > 0 && total > median;
- }
-
- class PoolingDataSourceManager extends Thread {
-
- private volatile boolean shouldStop;
-
- PoolingDataSourceManager() {
- setName("PoolManagerCleanup-" + dataSource.hashCode());
- setDaemon(true);
- this.shouldStop = false;
- }
-
- public void shouldStop() {
- shouldStop = true;
- interrupt();
- }
-
- @Override
- public void run() {
- while (true) {
-
- try {
- // don't do it too often
- Thread.sleep(600000);
- } catch (InterruptedException iex) {
- // ignore...
- }
-
- synchronized (dataSource) {
-
- // simple pool management - close one connection if the
- // count is
- // above median and there are any idle connections.
-
- if (shouldStop) {
- break;
- }
-
- if (shouldShrinkPool()) {
- dataSource.shrinkPool(1);
- }
- }
- }
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/conn/PooledConnectionFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/conn/PooledConnectionFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/conn/PooledConnectionFactory.java
deleted file mode 100644
index 2ebfeab..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/conn/PooledConnectionFactory.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*****************************************************************
- * 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.cayenne.conn;
-
-import java.io.PrintWriter;
-import java.sql.SQLException;
-import java.sql.SQLFeatureNotSupportedException;
-import java.util.logging.Logger;
-
-import javax.sql.ConnectionPoolDataSource;
-import javax.sql.DataSource;
-import javax.sql.PooledConnection;
-
-/**
- * A {@link ConnectionPoolDataSource} implementation.
- * <p>
- * It is implemented as a wrapper around a non-pooled data source object.
- * Delegates all method calls except for "getPooledConnection" to the underlying
- * DataSource.
- *
- * @since 4.0
- */
-public class PooledConnectionFactory implements ConnectionPoolDataSource {
-
- private DataSource nonPooledDatasource;
-
- public PooledConnectionFactory(DataSource nonPooledDatasource) {
- this.nonPooledDatasource = nonPooledDatasource;
- }
-
- public PooledConnectionFactory(String jdbcDriver, String connectionUrl) throws SQLException {
- nonPooledDatasource = new DriverDataSource(jdbcDriver, connectionUrl);
- }
-
- @Override
- public int getLoginTimeout() throws SQLException {
- return nonPooledDatasource.getLoginTimeout();
- }
-
- @Override
- public void setLoginTimeout(int seconds) throws SQLException {
- nonPooledDatasource.setLoginTimeout(seconds);
- }
-
- @Override
- public PrintWriter getLogWriter() throws SQLException {
- return nonPooledDatasource.getLogWriter();
- }
-
- @Override
- public void setLogWriter(PrintWriter out) throws SQLException {
- nonPooledDatasource.setLogWriter(out);
- }
-
- @Override
- public PooledConnection getPooledConnection() throws SQLException {
- return new PooledConnectionImpl(nonPooledDatasource, null, null);
- }
-
- @Override
- public PooledConnection getPooledConnection(String user, String password) throws SQLException {
- return new PooledConnectionImpl(nonPooledDatasource, user, password);
- }
-
- /**
- * @since 3.1
- *
- * JDBC 4.1 compatibility under Java 1.7
- */
- public Logger getParentLogger() throws SQLFeatureNotSupportedException {
- throw new UnsupportedOperationException();
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/conn/PooledConnectionImpl.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/conn/PooledConnectionImpl.java b/cayenne-server/src/main/java/org/apache/cayenne/conn/PooledConnectionImpl.java
deleted file mode 100644
index eb327ff..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/conn/PooledConnectionImpl.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*****************************************************************
- * 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.cayenne.conn;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import javax.sql.ConnectionEvent;
-import javax.sql.ConnectionEventListener;
-import javax.sql.DataSource;
-import javax.sql.PooledConnection;
-import javax.sql.StatementEventListener;
-
-/**
- * PooledConnectionImpl is an implementation of a pooling wrapper for the
- * database connection as per JDBC3 spec. Most of the modern JDBC drivers should
- * have its own implementation that may be used instead of this class.
- */
-public class PooledConnectionImpl implements PooledConnection {
-
- private Connection connectionObj;
- private List<ConnectionEventListener> connectionEventListeners;
- private boolean hadErrors;
- private DataSource dataSource;
- private String userName;
- private String password;
-
- public PooledConnectionImpl(DataSource dataSource, String userName, String password) {
-
- // TODO: maybe remove synchronization and use
- // FastArrayList from commons-collections? After
- // all the only listener is usually pool manager.
- this.connectionEventListeners = Collections.synchronizedList(new ArrayList<ConnectionEventListener>(10));
-
- this.dataSource = dataSource;
- this.userName = userName;
- this.password = password;
- }
-
- public void reconnect() throws SQLException {
- if (connectionObj != null) {
- try {
- connectionObj.close();
- } catch (SQLException ex) {
- // ignore exception, since connection is expected
- // to be in a bad state
- } finally {
- connectionObj = null;
- }
- }
-
- connectionObj = (userName != null) ? dataSource.getConnection(userName, password) : dataSource.getConnection();
- }
-
- @Override
- public void addConnectionEventListener(ConnectionEventListener listener) {
- synchronized (connectionEventListeners) {
- if (!connectionEventListeners.contains(listener)) {
- connectionEventListeners.add(listener);
- }
- }
- }
-
- @Override
- public void removeConnectionEventListener(ConnectionEventListener listener) {
- synchronized (connectionEventListeners) {
- connectionEventListeners.remove(listener);
- }
- }
-
- @Override
- public void close() throws SQLException {
-
- synchronized (connectionEventListeners) {
- // remove all listeners
- connectionEventListeners.clear();
- }
-
- if (connectionObj != null) {
- try {
- connectionObj.close();
- } finally {
- connectionObj = null;
- }
- }
- }
-
- @Override
- public Connection getConnection() throws SQLException {
- if (connectionObj == null) {
- reconnect();
- }
-
- // set autocommit to false to return connection
- // always in consistent state
- if (!connectionObj.getAutoCommit()) {
-
- try {
- connectionObj.setAutoCommit(true);
- } catch (SQLException sqlEx) {
- // try applying Sybase patch
- ConnectionWrapper.sybaseAutoCommitPatch(connectionObj, sqlEx, true);
- }
- }
-
- connectionObj.clearWarnings();
- return new ConnectionWrapper(connectionObj, this);
- }
-
- protected void returnConnectionToThePool() throws SQLException {
- // do not return to pool bad connections
- if (hadErrors)
- close();
- else
- // notify the listeners that connection is no longer used by
- // application...
- this.connectionClosedNotification();
- }
-
- /**
- * This method creates and sents an event to listeners when an error occurs
- * in the underlying connection. Listeners can have special logic to analyze
- * the error and do things like closing this PooledConnection (if the error
- * is fatal), etc...
- */
- public void connectionErrorNotification(SQLException exception) {
- // hint for later to avoid returning bad connections to the pool
- hadErrors = true;
-
- synchronized (connectionEventListeners) {
- if (connectionEventListeners.isEmpty()) {
- return;
- }
-
- ConnectionEvent closedEvent = new ConnectionEvent(this, exception);
- for (ConnectionEventListener nextListener : connectionEventListeners) {
- nextListener.connectionErrorOccurred(closedEvent);
- }
- }
- }
-
- /**
- * Creates and sends an event to listeners when a user closes
- * java.sql.Connection object belonging to this PooledConnection.
- */
- protected void connectionClosedNotification() {
- synchronized (connectionEventListeners) {
- if (connectionEventListeners.size() == 0) {
- return;
- }
-
- ConnectionEvent closedEvent = new ConnectionEvent(this);
-
- for (ConnectionEventListener nextListener : connectionEventListeners) {
- nextListener.connectionClosed(closedEvent);
- }
- }
- }
-
- /**
- * @since 3.0
- */
- @Override
- public void addStatementEventListener(StatementEventListener listener) {
- throw new UnsupportedOperationException("Statement events are unsupported");
- }
-
- /**
- * @since 3.0
- */
- @Override
- public void removeStatementEventListener(StatementEventListener listener) {
- throw new UnsupportedOperationException("Statement events are unsupported");
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/conn/PoolingDataSource.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/conn/PoolingDataSource.java b/cayenne-server/src/main/java/org/apache/cayenne/conn/PoolingDataSource.java
deleted file mode 100644
index cccf905..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/conn/PoolingDataSource.java
+++ /dev/null
@@ -1,471 +0,0 @@
-/*****************************************************************
- * 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.cayenne.conn;
-
-import java.io.PrintWriter;
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.SQLFeatureNotSupportedException;
-import java.sql.Statement;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.logging.Logger;
-
-import javax.sql.ConnectionEvent;
-import javax.sql.ConnectionEventListener;
-import javax.sql.ConnectionPoolDataSource;
-import javax.sql.DataSource;
-import javax.sql.PooledConnection;
-
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.di.ScopeEventListener;
-
-/**
- * A {@link DataSource} with a pool of connections, that can automatically grow
- * to the max size as more connections are requested.
- *
- * @since 4.0
- */
-public class PoolingDataSource implements ScopeEventListener, DataSource, ConnectionEventListener {
-
- /**
- * Defines a maximum time in milliseconds that a connection request could
- * wait in the connection queue. After this period expires, an exception
- * will be thrown in the calling method.
- */
- public static final int MAX_QUEUE_WAIT_DEFAULT = 20000;
-
- /**
- * An exception indicating that a connection request waiting in the queue
- * timed out and was unable to obtain a connection.
- */
- public static class ConnectionUnavailableException extends SQLException {
- private static final long serialVersionUID = 1063973806941023165L;
-
- public ConnectionUnavailableException(String message) {
- super(message);
- }
- }
-
- protected ConnectionPoolDataSource pooledConnectionFactory;
-
- private int minConnections;
- private int maxConnections;
- private long maxQueueWaitTime;
- private String validationQuery;
-
- private List<PooledConnection> unusedPool;
- private List<PooledConnection> usedPool;
- private boolean shuttingDown;
-
- /**
- * Creates new PoolManager with the specified policy for connection pooling
- * and a ConnectionPoolDataSource object.
- *
- * @param poolDataSource
- * data source for pooled connections
- * @param minCons
- * Non-negative integer that specifies a minimum number of open
- * connections to keep in the pool at all times
- * @param maxCons
- * Non-negative integer that specifies maximum number of
- * simultaneously open connections
- * @throws SQLException
- * if pool manager can not be created.
- * @since 4.0
- */
- public PoolingDataSource(ConnectionPoolDataSource poolDataSource, PoolingDataSourceParameters parameters)
- throws SQLException {
-
- this.pooledConnectionFactory = poolDataSource;
-
- // clone parameters to keep DataSource immutable
- this.minConnections = parameters.getMinConnections();
- this.maxConnections = parameters.getMaxConnections();
- this.maxQueueWaitTime = parameters.getMaxQueueWaitTime();
- this.validationQuery = parameters.getValidationQuery();
-
- // init pool... use linked lists to use the queue in the FIFO manner
- this.usedPool = new LinkedList<PooledConnection>();
- this.unusedPool = new LinkedList<PooledConnection>();
- growPool(minConnections);
- }
-
- /**
- * Creates and returns new PooledConnection object, adding itself as a
- * listener for connection events.
- */
- protected PooledConnection newPooledConnection() throws SQLException {
- PooledConnection connection = pooledConnectionFactory.getPooledConnection();
- connection.addConnectionEventListener(this);
- return connection;
- }
-
- /**
- * Shuts down the pool, closing all open connections. This is an
- * implementation of {@link ScopeEventListener}.
- *
- * @since 3.1
- */
- @Override
- public synchronized void beforeScopeEnd() {
- try {
-
- // using boolean variable instead of locking PoolManager instance
- // due to possible deadlock during shutdown when one of connections
- // locks its event listeners list trying to invoke locked
- // PoolManager's listener methods
- shuttingDown = true;
-
- ListIterator<PooledConnection> unusedIterator = unusedPool.listIterator();
- while (unusedIterator.hasNext()) {
- PooledConnection con = unusedIterator.next();
- // close connection
- con.close();
- // remove connection from the list
- unusedIterator.remove();
- }
-
- // clean used connections
- ListIterator<PooledConnection> usedIterator = usedPool.listIterator();
- while (usedIterator.hasNext()) {
- PooledConnection con = usedIterator.next();
- // stop listening for connection events
- con.removeConnectionEventListener(this);
- // close connection
- con.close();
- // remove connection from the list
- usedIterator.remove();
- }
- } catch (SQLException e) {
- throw new CayenneRuntimeException("Error while shutting down");
- }
- }
-
- /**
- * @return true if at least one more connection can be added to the pool.
- */
- protected synchronized boolean canGrowPool() {
- return getPoolSize() < maxConnections;
- }
-
- /**
- * Increases connection pool by the specified number of connections.
- *
- * @return the actual number of created connections.
- * @throws SQLException
- * if an error happens when creating a new connection.
- */
- protected synchronized int growPool(int addConnections) throws SQLException {
-
- int i = 0;
- int startPoolSize = getPoolSize();
- for (; i < addConnections && startPoolSize + i < maxConnections; i++) {
- PooledConnection newConnection = newPooledConnection();
- unusedPool.add(newConnection);
- }
-
- return i;
- }
-
- public synchronized void shrinkPool(int closeConnections) {
- int idleSize = unusedPool.size();
- for (int i = 0; i < closeConnections && i < idleSize; i++) {
- PooledConnection con = unusedPool.remove(i);
-
- try {
- con.close();
- } catch (SQLException ex) {
- // ignore
- }
- }
- }
-
- public String getValidationQuery() {
- return validationQuery;
- }
-
- /**
- * Returns maximum number of connections this pool can keep. This parameter
- * when configured allows to limit the number of simultaneously open
- * connections.
- */
- public int getMaxConnections() {
- return maxConnections;
- }
-
- /**
- * Returns the absolute minimum number of connections allowed in this pool
- * at any moment in time.
- */
- public int getMinConnections() {
- return minConnections;
- }
-
- /**
- * Returns current number of connections.
- */
- public synchronized int getPoolSize() {
- return usedPool.size() + unusedPool.size();
- }
-
- /**
- * Returns the number of connections obtained via this DataSource that are
- * currently in use by the DataSource clients.
- */
- public synchronized int getCurrentlyInUse() {
- return usedPool.size();
- }
-
- /**
- * Returns the number of connections maintained in the pool that are
- * currently not used by any clients and are available immediately via
- * <code>getConnection</code> method.
- */
- public synchronized int getCurrentlyUnused() {
- return unusedPool.size();
- }
-
- /**
- * Returns connection from the pool using internal values of user name and
- * password.
- */
- @Override
- public synchronized Connection getConnection() throws SQLException {
- if (shuttingDown) {
- throw new SQLException("Pool manager is shutting down.");
- }
-
- PooledConnection pooledConnection = uncheckPooledConnection();
-
- try {
- return uncheckAndValidateConnection(pooledConnection);
- } catch (SQLException ex) {
-
- try {
- pooledConnection.close();
- } catch (SQLException ignored) {
- }
-
- // do one reconnect attempt...
- pooledConnection = uncheckPooledConnection();
- try {
- return uncheckAndValidateConnection(pooledConnection);
- } catch (SQLException reconnectEx) {
- try {
- pooledConnection.close();
- } catch (SQLException ignored) {
- }
-
- throw reconnectEx;
- }
- }
- }
-
- /**
- * Returns connection from the pool.
- */
- @Override
- public synchronized Connection getConnection(String userName, String password) throws SQLException {
- throw new UnsupportedOperationException(
- "Connections for a specific user are not supported by the pooled DataSource");
- }
-
- private Connection uncheckConnection(PooledConnection pooledConnection) throws SQLException {
- Connection c = pooledConnection.getConnection();
-
- // only do that on successfully unchecked connection...
- usedPool.add(pooledConnection);
- return c;
- }
-
- private Connection uncheckAndValidateConnection(PooledConnection pooledConnection) throws SQLException {
- Connection c = uncheckConnection(pooledConnection);
-
- if (validationQuery != null) {
-
- Statement statement = c.createStatement();
- try {
- ResultSet rs = statement.executeQuery(validationQuery);
- try {
-
- if (!rs.next()) {
- throw new SQLException("Connection validation failed, no result for query: " + validationQuery);
- }
-
- } finally {
- rs.close();
- }
- } finally {
- statement.close();
- }
- }
-
- return c;
- }
-
- private PooledConnection uncheckPooledConnection() throws SQLException {
- // wait for returned connections or the maintenance thread
- // to bump the pool size...
-
- if (unusedPool.size() == 0) {
-
- // first try to open a new connection
- if (canGrowPool()) {
- return newPooledConnection();
- }
-
- // can't open no more... will have to wait for others to return a
- // connection
-
- // note that if we were woken up
- // before the full wait period expired, and no connections are
- // available yet, go back to sleep. Otherwise we don't give a
- // maintenance
- // thread a chance to increase pool size
- long waitTill = System.currentTimeMillis() + maxQueueWaitTime;
-
- do {
- try {
- wait(maxQueueWaitTime);
- } catch (InterruptedException iex) {
- // ignoring
- }
-
- } while (unusedPool.size() == 0 && (maxQueueWaitTime == 0 || waitTill > System.currentTimeMillis()));
-
- if (unusedPool.size() == 0) {
- throw new ConnectionUnavailableException(
- "Can't obtain connection. Request timed out. Total used connections: " + usedPool.size());
- }
- }
-
- // get first connection... lets cycle them in FIFO manner
- return unusedPool.remove(0);
- }
-
- @Override
- public int getLoginTimeout() throws java.sql.SQLException {
- return pooledConnectionFactory.getLoginTimeout();
- }
-
- @Override
- public void setLoginTimeout(int seconds) throws java.sql.SQLException {
- pooledConnectionFactory.setLoginTimeout(seconds);
- }
-
- @Override
- public PrintWriter getLogWriter() throws java.sql.SQLException {
- return pooledConnectionFactory.getLogWriter();
- }
-
- @Override
- public void setLogWriter(PrintWriter out) throws java.sql.SQLException {
- pooledConnectionFactory.setLogWriter(out);
- }
-
- /**
- * Returns closed connection to the pool.
- */
- @Override
- public synchronized void connectionClosed(ConnectionEvent event) {
-
- if (shuttingDown) {
- return;
- }
-
- // return connection to the pool
- PooledConnection closedConn = (PooledConnection) event.getSource();
-
- // remove this connection from the list of connections
- // managed by this pool...
- int usedInd = usedPool.indexOf(closedConn);
- if (usedInd >= 0) {
- usedPool.remove(usedInd);
- unusedPool.add(closedConn);
-
- // notify threads waiting for connections
- notifyAll();
- }
- // else ....
- // other possibility is that this is a bad connection, so just ignore
- // its closing
- // event,
- // since it was unregistered in "connectionErrorOccurred"
- }
-
- /**
- * Removes connection with an error from the pool. This method is called by
- * PoolManager connections on connection errors to notify PoolManager that
- * connection is in invalid state.
- */
- @Override
- public synchronized void connectionErrorOccurred(ConnectionEvent event) {
-
- if (shuttingDown) {
- return;
- }
-
- // later on we should analyze the error to see if this
- // is fatal... right now just kill this PooledConnection
-
- PooledConnection errorSrc = (PooledConnection) event.getSource();
-
- // remove this connection from the list of connections
- // managed by this pool...
-
- int usedInd = usedPool.indexOf(errorSrc);
- if (usedInd >= 0) {
- usedPool.remove(usedInd);
- } else {
- int unusedInd = unusedPool.indexOf(errorSrc);
- if (unusedInd >= 0) {
- unusedPool.remove(unusedInd);
- }
- }
-
- // do not close connection,
- // let the code that catches the exception handle it
- // ....
- }
-
- @Override
- public boolean isWrapperFor(Class<?> iface) throws SQLException {
- return PoolingDataSource.class.equals(iface);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public <T> T unwrap(Class<T> iface) throws SQLException {
- if (PoolingDataSource.class.equals(iface)) {
- return (T) this;
- }
-
- throw new SQLException("Not a wrapper for " + iface);
- }
-
- // JDBC 4.1 compatibility under Java <= 1.6
- public Logger getParentLogger() throws SQLFeatureNotSupportedException {
- throw new UnsupportedOperationException();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/conn/PoolingDataSourceParameters.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/conn/PoolingDataSourceParameters.java b/cayenne-server/src/main/java/org/apache/cayenne/conn/PoolingDataSourceParameters.java
deleted file mode 100644
index 3066553..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/conn/PoolingDataSourceParameters.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*****************************************************************
- * 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.cayenne.conn;
-
-/**
- * A collection of pooling parameters used by {@link PoolingDataSource}.
- *
- * @since 4.0
- */
-public class PoolingDataSourceParameters {
-
- private String validationQuery;
- private int minConnections;
- private int maxConnections;
- private long maxQueueWaitTime;
-
- public int getMinConnections() {
- return minConnections;
- }
-
- public void setMinConnections(int minConnections) {
- this.minConnections = minConnections;
- }
-
- public int getMaxConnections() {
- return maxConnections;
- }
-
- public void setMaxConnections(int maxConnections) {
- this.maxConnections = maxConnections;
- }
-
- public long getMaxQueueWaitTime() {
- return maxQueueWaitTime;
- }
-
- public void setMaxQueueWaitTime(long maxQueueWaitTime) {
- this.maxQueueWaitTime = maxQueueWaitTime;
- }
-
- public String getValidationQuery() {
- return validationQuery;
- }
-
- public void setValidationQuery(String validationQuery) {
- this.validationQuery = validationQuery;
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/conn/package.html
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/conn/package.html b/cayenne-server/src/main/java/org/apache/cayenne/conn/package.html
deleted file mode 100644
index 4fe2394..0000000
--- a/cayenne-server/src/main/java/org/apache/cayenne/conn/package.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
- 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.
--->
-<html>
-<body>
-Provides full DataSource implementation. Allows to wrap JDBC
-drivers into a DataSource-compatible classes. Adds features like connection
-pooling, etc. Can be used as a DataSource implementation with application
-servers, web containers, etc.
-</body>
-</html>
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/datasource/BadValidationQueryException.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/datasource/BadValidationQueryException.java b/cayenne-server/src/main/java/org/apache/cayenne/datasource/BadValidationQueryException.java
new file mode 100644
index 0000000..9f7e74b
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/datasource/BadValidationQueryException.java
@@ -0,0 +1,41 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import java.sql.SQLException;
+
+/**
+ * Thrown when the pool fails to validate a fresh connection that is known to be
+ * in a good state.
+ *
+ * @since 4.0
+ */
+public class BadValidationQueryException extends SQLException {
+
+ private static final long serialVersionUID = -3690715196865727679L;
+
+ public BadValidationQueryException(String message) {
+ super(message);
+ }
+
+ public BadValidationQueryException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/datasource/DataSourceBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/datasource/DataSourceBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/datasource/DataSourceBuilder.java
new file mode 100644
index 0000000..e02f8eb
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/datasource/DataSourceBuilder.java
@@ -0,0 +1,135 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import java.sql.Driver;
+
+import javax.sql.DataSource;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.di.AdhocObjectFactory;
+import org.apache.cayenne.log.JdbcEventLogger;
+import org.apache.cayenne.log.NoopJdbcEventLogger;
+
+/**
+ * A builder class that creates a default Cayenne implementation of a pooling
+ * {@link DataSource}.
+ *
+ * @since 4.0
+ */
+public class DataSourceBuilder {
+
+ private AdhocObjectFactory objectFactory;
+ private JdbcEventLogger logger;
+ private String userName;
+ private String password;
+ private String driver;
+ private String url;
+ private PoolingDataSourceParameters poolParameters;
+
+ public static DataSourceBuilder builder(AdhocObjectFactory objectFactory, JdbcEventLogger logger) {
+ return new DataSourceBuilder(objectFactory, logger);
+ }
+
+ private DataSourceBuilder(AdhocObjectFactory objectFactory, JdbcEventLogger logger) {
+ this.objectFactory = objectFactory;
+ this.logger = logger;
+ this.logger = NoopJdbcEventLogger.getInstance();
+ this.poolParameters = new PoolingDataSourceParameters();
+
+ poolParameters.setMinConnections(1);
+ poolParameters.setMaxConnections(1);
+ poolParameters.setMaxQueueWaitTime(PoolingDataSource.MAX_QUEUE_WAIT_DEFAULT);
+ }
+
+ public DataSourceBuilder userName(String userName) {
+ this.userName = userName;
+ return this;
+ }
+
+ public DataSourceBuilder password(String password) {
+ this.password = password;
+ return this;
+ }
+
+ public DataSourceBuilder driver(String driver) {
+ this.driver = driver;
+ return this;
+ }
+
+ public DataSourceBuilder url(String url) {
+ this.url = url;
+ return this;
+ }
+
+ public DataSourceBuilder minConnections(int minConnections) {
+ poolParameters.setMinConnections(minConnections);
+ return this;
+ }
+
+ public DataSourceBuilder maxConnections(int maxConnections) {
+ poolParameters.setMaxConnections(maxConnections);
+ return this;
+ }
+
+ public DataSourceBuilder maxQueueWaitTime(long maxQueueWaitTime) {
+ poolParameters.setMaxQueueWaitTime(maxQueueWaitTime);
+ return this;
+ }
+
+ public DataSourceBuilder validationQuery(String validationQuery) {
+ poolParameters.setValidationQuery(validationQuery);
+ return this;
+ }
+
+ public DataSource build() {
+
+ // sanity checks...
+ if (poolParameters.getMaxConnections() < 0) {
+ throw new CayenneRuntimeException("Maximum number of connections can not be negative ("
+ + poolParameters.getMaxConnections() + ").");
+ }
+
+ if (poolParameters.getMinConnections() < 0) {
+ throw new CayenneRuntimeException("Minimum number of connections can not be negative ("
+ + poolParameters.getMinConnections() + ").");
+ }
+
+ if (poolParameters.getMinConnections() > poolParameters.getMaxConnections()) {
+ throw new CayenneRuntimeException("Minimum number of connections can not be bigger then maximum.");
+ }
+
+ return buildManaged(buildPooling(buildNonPooling()));
+ }
+
+ private DataSource buildNonPooling() {
+ Driver driver = objectFactory.newInstance(Driver.class, this.driver);
+ DriverDataSource dataSource = new DriverDataSource(driver, url, userName, password);
+ dataSource.setLogger(logger);
+ return dataSource;
+ }
+
+ private PoolingDataSource buildPooling(DataSource nonPoolingDataSource) {
+ return new PoolingDataSource(nonPoolingDataSource, poolParameters);
+ }
+
+ private DataSource buildManaged(PoolingDataSource dataSource) {
+ return new ManagedPoolingDataSource(dataSource);
+ }
+}
[2/3] cayenne git commit: CAY-2009 Non-blocking connection pool
Posted by aa...@apache.org.
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/datasource/DriverDataSource.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/datasource/DriverDataSource.java b/cayenne-server/src/main/java/org/apache/cayenne/datasource/DriverDataSource.java
new file mode 100644
index 0000000..af096dc
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/datasource/DriverDataSource.java
@@ -0,0 +1,298 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Properties;
+import java.util.logging.Logger;
+
+import javax.sql.DataSource;
+
+import org.apache.cayenne.log.JdbcEventLogger;
+import org.apache.cayenne.util.Util;
+
+/**
+ * A non-pooling DataSource implementation wrapping a JDBC driver.
+ *
+ */
+public class DriverDataSource implements DataSource {
+
+ protected Driver _driver;
+ protected String driverClassName;
+
+ protected String connectionUrl;
+ protected String userName;
+ protected String password;
+
+ protected JdbcEventLogger logger;
+
+ /**
+ * Loads JDBC driver using current thread class loader.
+ *
+ * @since 3.0
+ * @deprecated since 4.0 as class loading should not happen here.
+ */
+ @Deprecated
+ private static Driver loadDriver(String driverClassName) throws SQLException {
+
+ Class<?> driverClass;
+ try {
+ driverClass = Util.getJavaClass(driverClassName);
+ }
+ catch (Exception ex) {
+ throw new SQLException("Can not load JDBC driver named '"
+ + driverClassName
+ + "': "
+ + ex.getMessage());
+ }
+
+ try {
+ return (Driver) driverClass.newInstance();
+ }
+ catch (Exception ex) {
+ throw new SQLException("Error instantiating driver '"
+ + driverClassName
+ + "': "
+ + ex.getMessage());
+ }
+ }
+
+ /**
+ * Creates a new DriverDataSource. If "driverClassName" is null, DriverDataSource will
+ * consult DriverManager for a registered driver for the given URL. So when specifying
+ * null, a user must take care of registering the driver. "connectionUrl" on the other
+ * hand must NOT be null.
+ */
+ public DriverDataSource(String driverClassName, String connectionUrl) {
+ this(driverClassName, connectionUrl, null, null);
+ }
+
+ /**
+ * Creates a new DriverDataSource. If "driverClassName" is null, DriverDataSource will
+ * consult DriverManager for a registered driver for the given URL. So when specifying
+ * null, a user must take care of registering the driver. "connectionUrl" on the other
+ * hand must NOT be null.
+ *
+ * @since 3.0
+ */
+ public DriverDataSource(String driverClassName, String connectionUrl,
+ String userName, String password) {
+
+ setDriverClassName(driverClassName);
+
+ this.connectionUrl = connectionUrl;
+ this.userName = userName;
+ this.password = password;
+ }
+
+ /**
+ * Creates a new DriverDataSource wrapping a given Driver. If "driver" is null,
+ * DriverDataSource will consult DriverManager for a registered driver for the given
+ * URL. So when specifying null, a user must take care of registering the driver.
+ * "connectionUrl" on the other hand must NOT be null.
+ *
+ * @since 1.1
+ */
+ public DriverDataSource(Driver driver, String connectionUrl, String userName,
+ String password) {
+
+ this._driver = driver;
+ this.driverClassName = driver.getClass().getName();
+ this.connectionUrl = connectionUrl;
+ this.userName = userName;
+ this.password = password;
+ }
+
+ /**
+ * Returns a new database connection, using preconfigured data to locate the database
+ * and obtain a connection.
+ */
+ public Connection getConnection() throws SQLException {
+ // login with internal credentials
+ return getConnection(userName, password);
+ }
+
+ /**
+ * Returns a new database connection using provided credentials to login to the
+ * database.
+ */
+ public Connection getConnection(String userName, String password) throws SQLException {
+ try {
+ if (logger != null) {
+ logger.logConnect(connectionUrl, userName, password);
+ }
+
+ Connection c = null;
+
+ if (getDriver() == null) {
+ c = DriverManager.getConnection(connectionUrl, userName, password);
+ }
+ else {
+ Properties connectProperties = new Properties();
+
+ if (userName != null) {
+ connectProperties.put("user", userName);
+ }
+
+ if (password != null) {
+ connectProperties.put("password", password);
+ }
+ c = getDriver().connect(connectionUrl, connectProperties);
+ }
+
+ // some drivers (Oracle) return null connections instead of throwing
+ // an exception... fix it here
+
+ if (c == null) {
+ throw new SQLException("Can't establish connection: " + connectionUrl);
+ }
+
+ if (logger != null) {
+ logger.logConnectSuccess();
+ }
+
+ return c;
+ }
+ catch (SQLException sqlex) {
+ if (logger != null) {
+ logger.logConnectFailure(sqlex);
+ }
+
+ throw sqlex;
+ }
+ }
+
+ public int getLoginTimeout() throws SQLException {
+ return -1;
+ }
+
+ public void setLoginTimeout(int seconds) throws SQLException {
+ // noop
+ }
+
+ public PrintWriter getLogWriter() throws SQLException {
+ return DriverManager.getLogWriter();
+ }
+
+ public void setLogWriter(PrintWriter out) throws SQLException {
+ DriverManager.setLogWriter(out);
+ }
+
+ public JdbcEventLogger getLogger() {
+ return logger;
+ }
+
+ public void setLogger(JdbcEventLogger delegate) {
+ logger = delegate;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public String getConnectionUrl() {
+ return connectionUrl;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public void setConnectionUrl(String connectionUrl) {
+ this.connectionUrl = connectionUrl;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public String getUserName() {
+ return userName;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getDriverClassName() {
+ return driverClassName;
+ }
+
+ public void setDriverClassName(String driverClassName) {
+ if (!Util.nullSafeEquals(getDriverClassName(), driverClassName)) {
+ this.driverClassName = driverClassName;
+ this._driver = null; // force reload
+ }
+ }
+
+ /**
+ * Lazily instantiate the driver class to prevent errors for connections that are never opened
+ */
+ private Driver getDriver() throws SQLException {
+ if (_driver == null && driverClassName != null) {
+ _driver = loadDriver(driverClassName);
+ }
+ return _driver;
+ }
+
+ /**
+ * @since 3.0
+ */
+ // JDBC 4 compatibility under Java 1.5
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @since 3.0
+ */
+ // JDBC 4 compatibility under Java 1.5
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @since 3.1
+ *
+ * JDBC 4.1 compatibility under Java 1.5
+ */
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ throw new UnsupportedOperationException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/datasource/ManagedPoolingDataSource.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/datasource/ManagedPoolingDataSource.java b/cayenne-server/src/main/java/org/apache/cayenne/datasource/ManagedPoolingDataSource.java
new file mode 100644
index 0000000..65083b1
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/datasource/ManagedPoolingDataSource.java
@@ -0,0 +1,107 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.logging.Logger;
+
+import javax.sql.DataSource;
+
+import org.apache.cayenne.di.ScopeEventListener;
+
+/**
+ * A wrapper for {@link PoolingDataSourceManager} that manages the underlying
+ * connection pool size.
+ *
+ * @since 4.0
+ */
+public class ManagedPoolingDataSource implements DataSource, ScopeEventListener {
+
+ private PoolingDataSourceManager dataSourceManager;
+ private DataSource dataSource;
+
+ public ManagedPoolingDataSource(PoolingDataSource dataSource) {
+
+ this.dataSource = dataSource;
+ this.dataSourceManager = new PoolingDataSourceManager(dataSource);
+
+ dataSourceManager.start();
+ }
+
+ @Override
+ public void beforeScopeEnd() {
+
+ // swap the underlying DataSource to prevent further interaction with
+ // the callers
+ this.dataSource = new StoppedDataSource(dataSource);
+
+ // shut down the thread..
+ dataSourceManager.shutdown();
+ }
+
+ @Override
+ public Connection getConnection() throws SQLException {
+ return dataSource.getConnection();
+ }
+
+ @Override
+ public Connection getConnection(String username, String password) throws SQLException {
+ return dataSource.getConnection(username, password);
+ }
+
+ @Override
+ public PrintWriter getLogWriter() throws SQLException {
+ return dataSource.getLogWriter();
+ }
+
+ @Override
+ public int getLoginTimeout() throws SQLException {
+ return dataSource.getLoginTimeout();
+ }
+
+ @Override
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ return (ManagedPoolingDataSource.class.equals(iface)) ? true : dataSource.isWrapperFor(iface);
+ }
+
+ @Override
+ public void setLogWriter(PrintWriter arg0) throws SQLException {
+ dataSource.setLogWriter(arg0);
+ }
+
+ @Override
+ public void setLoginTimeout(int arg0) throws SQLException {
+ dataSource.setLoginTimeout(arg0);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ return ManagedPoolingDataSource.class.equals(iface) ? (T) this : dataSource.unwrap(iface);
+ }
+
+ // JDBC 4.1 compatibility under Java 1.6 and newer
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ throw new SQLFeatureNotSupportedException();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolAwareConnection.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolAwareConnection.java b/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolAwareConnection.java
new file mode 100644
index 0000000..6b90504
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolAwareConnection.java
@@ -0,0 +1,609 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.CallableStatement;
+import java.sql.Clob;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.NClob;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLClientInfoException;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Savepoint;
+import java.sql.Statement;
+import java.sql.Struct;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.Executor;
+
+/**
+ * A {@link Connection} wrapper that interacts with the
+ * {@link PoolingDataSource}, allowing to recycle connections and track
+ * failures.
+ *
+ * @since 4.0
+ */
+public class PoolAwareConnection implements Connection {
+
+ private PoolingDataSource parent;
+ private Connection connection;
+ private String validationQuery;
+
+ // An old hack that fixes Sybase problems with autocommit. Used idea from
+ // Jonas org.objectweb.jonas.jdbc_xa.ConnectionImpl
+ // (http://www.objectweb.org/jonas/).
+ //
+ // If problem is not the one that can be fixed by this patch, original
+ // exception is rethrown. If exception occurs when fixing the problem, new
+ // exception is thrown.
+ //
+ static void sybaseAutoCommitPatch(Connection c, SQLException e, boolean autoCommit) throws SQLException {
+
+ String s = e.getMessage().toLowerCase();
+ if (s.contains("set chained command not allowed")) {
+ c.commit();
+ c.setAutoCommit(autoCommit); // Shouldn't fail now.
+ } else {
+ throw e;
+ }
+ }
+
+ public PoolAwareConnection(PoolingDataSource parent, Connection connection, String validationQuery) {
+ this.parent = parent;
+ this.connection = connection;
+ this.validationQuery = validationQuery;
+ }
+
+ Connection getConnection() {
+ return connection;
+ }
+
+ boolean validate() {
+
+ if (validationQuery == null) {
+ return true;
+ }
+
+ try {
+ Statement statement = connection.createStatement();
+ try {
+ ResultSet rs = statement.executeQuery(validationQuery);
+ try {
+
+ if (!rs.next()) {
+ throw new SQLException("Connection validation failed, no result for query: " + validationQuery);
+ }
+
+ } finally {
+ rs.close();
+ }
+ } finally {
+ statement.close();
+ }
+ } catch (SQLException e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ void recover(SQLException reconnectCause) throws SQLException {
+
+ try {
+ connection.close();
+ } catch (SQLException e) {
+ // ignore exception, since connection is expected to be in a bad
+ // state
+ }
+
+ try {
+ connection = parent.createUnwrapped();
+ } catch (SQLException e) {
+ parent.retire(this);
+ throw reconnectCause;
+ }
+ }
+
+ @Override
+ public void clearWarnings() throws SQLException {
+ try {
+ connection.clearWarnings();
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public void close() throws SQLException {
+ parent.reclaim(this);
+ }
+
+ @Override
+ public void commit() throws SQLException {
+ try {
+ connection.commit();
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public Statement createStatement() throws SQLException {
+ try {
+ return connection.createStatement();
+ } catch (SQLException sqlEx) {
+ recover(sqlEx);
+ return connection.createStatement();
+ }
+ }
+
+ @Override
+ public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
+ try {
+ return connection.createStatement(resultSetType, resultSetConcurrency);
+ } catch (SQLException e) {
+ recover(e);
+ return connection.createStatement(resultSetType, resultSetConcurrency);
+ }
+ }
+
+ @Override
+ public boolean getAutoCommit() throws SQLException {
+ try {
+ return connection.getAutoCommit();
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public String getCatalog() throws SQLException {
+ try {
+ return connection.getCatalog();
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public DatabaseMetaData getMetaData() throws SQLException {
+ try {
+ return connection.getMetaData();
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public int getTransactionIsolation() throws SQLException {
+ try {
+ return connection.getTransactionIsolation();
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public SQLWarning getWarnings() throws SQLException {
+ try {
+ return connection.getWarnings();
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public boolean isClosed() throws SQLException {
+
+ try {
+ return connection.isClosed();
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public boolean isReadOnly() throws SQLException {
+ try {
+ return connection.isReadOnly();
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public String nativeSQL(String sql) throws SQLException {
+ try {
+ return connection.nativeSQL(sql);
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public CallableStatement prepareCall(String sql) throws SQLException {
+ try {
+ return connection.prepareCall(sql);
+ } catch (SQLException sqlEx) {
+ recover(sqlEx);
+ return connection.prepareCall(sql);
+ }
+ }
+
+ @Override
+ public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
+ try {
+ return connection.prepareCall(sql, resultSetType, resultSetConcurrency);
+ } catch (SQLException sqlEx) {
+
+ recover(sqlEx);
+ return connection.prepareCall(sql, resultSetType, resultSetConcurrency);
+ }
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql) throws SQLException {
+ try {
+ return connection.prepareStatement(sql);
+ } catch (SQLException sqlEx) {
+ recover(sqlEx);
+ return connection.prepareStatement(sql);
+ }
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
+ throws SQLException {
+ try {
+ return connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
+ } catch (SQLException sqlEx) {
+
+ recover(sqlEx);
+ return connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
+ }
+ }
+
+ @Override
+ public void rollback() throws SQLException {
+ try {
+ connection.rollback();
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public void setAutoCommit(boolean autoCommit) throws SQLException {
+ try {
+ connection.setAutoCommit(autoCommit);
+ } catch (SQLException sqlEx) {
+
+ try {
+ // apply Sybase patch
+ sybaseAutoCommitPatch(connection, sqlEx, autoCommit);
+ } catch (SQLException patchEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+ }
+
+ @Override
+ public void setCatalog(String catalog) throws SQLException {
+ try {
+ connection.setCatalog(catalog);
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public void setReadOnly(boolean readOnly) throws SQLException {
+ try {
+ connection.setReadOnly(readOnly);
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public void setTransactionIsolation(int level) throws SQLException {
+ try {
+ connection.setTransactionIsolation(level);
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public Map<String, Class<?>> getTypeMap() throws SQLException {
+ try {
+ return connection.getTypeMap();
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
+ try {
+ connection.setTypeMap(map);
+ } catch (SQLException sqlEx) {
+ parent.retire(this);
+ throw sqlEx;
+ }
+ }
+
+ @Override
+ public void setHoldability(int holdability) throws SQLException {
+ throw new java.lang.UnsupportedOperationException("Method setHoldability() not yet implemented.");
+ }
+
+ @Override
+ public int getHoldability() throws SQLException {
+ throw new java.lang.UnsupportedOperationException("Method getHoldability() not yet implemented.");
+ }
+
+ @Override
+ public Savepoint setSavepoint() throws SQLException {
+ throw new java.lang.UnsupportedOperationException("Method setSavepoint() not yet implemented.");
+ }
+
+ @Override
+ public Savepoint setSavepoint(String name) throws SQLException {
+ throw new java.lang.UnsupportedOperationException("Method setSavepoint() not yet implemented.");
+ }
+
+ @Override
+ public void rollback(Savepoint savepoint) throws SQLException {
+ throw new java.lang.UnsupportedOperationException("Method rollback() not yet implemented.");
+ }
+
+ @Override
+ public void releaseSavepoint(Savepoint savepoint) throws SQLException {
+ throw new java.lang.UnsupportedOperationException("Method releaseSavepoint() not yet implemented.");
+ }
+
+ @Override
+ public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
+ throws SQLException {
+ throw new java.lang.UnsupportedOperationException("Method createStatement() not yet implemented.");
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
+ int resultSetHoldability) throws SQLException {
+ throw new java.lang.UnsupportedOperationException("Method prepareStatement() not yet implemented.");
+ }
+
+ @Override
+ public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency,
+ int resultSetHoldability) throws SQLException {
+ try {
+ return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
+ } catch (SQLException e) {
+
+ recover(e);
+ return connection.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
+ }
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
+
+ try {
+ return connection.prepareStatement(sql, autoGeneratedKeys);
+ } catch (SQLException e) {
+
+ recover(e);
+ return connection.prepareStatement(sql, autoGeneratedKeys);
+ }
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
+ try {
+ return connection.prepareStatement(sql, columnIndexes);
+ } catch (SQLException e) {
+
+ recover(e);
+ return connection.prepareStatement(sql, columnIndexes);
+ }
+ }
+
+ @Override
+ public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
+ try {
+ return connection.prepareStatement(sql, columnNames);
+ } catch (SQLException sqlEx) {
+
+ recover(sqlEx);
+ return connection.prepareStatement(sql, columnNames);
+ }
+ }
+
+ @Override
+ public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
+ try {
+ return connection.createArrayOf(typeName, elements);
+ } catch (SQLException sqlEx) {
+
+ recover(sqlEx);
+ return connection.createArrayOf(typeName, elements);
+ }
+ }
+
+ @Override
+ public Blob createBlob() throws SQLException {
+ try {
+ return connection.createBlob();
+ } catch (SQLException sqlEx) {
+
+ recover(sqlEx);
+ return connection.createBlob();
+ }
+ }
+
+ @Override
+ public Clob createClob() throws SQLException {
+ try {
+ return connection.createClob();
+ } catch (SQLException sqlEx) {
+
+ recover(sqlEx);
+ return connection.createClob();
+ }
+ }
+
+ @Override
+ public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
+ try {
+ return connection.createStruct(typeName, attributes);
+ } catch (SQLException sqlEx) {
+
+ recover(sqlEx);
+ return connection.createStruct(typeName, attributes);
+ }
+ }
+
+ @Override
+ public Properties getClientInfo() throws SQLException {
+ try {
+ return connection.getClientInfo();
+ } catch (SQLException sqlEx) {
+
+ recover(sqlEx);
+ return connection.getClientInfo();
+ }
+ }
+
+ @Override
+ public String getClientInfo(String name) throws SQLException {
+ try {
+ return connection.getClientInfo(name);
+ } catch (SQLException sqlEx) {
+
+ recover(sqlEx);
+ return connection.getClientInfo(name);
+ }
+ }
+
+ @Override
+ public boolean isValid(int timeout) throws SQLException {
+ try {
+ return connection.isValid(timeout);
+ } catch (SQLException sqlEx) {
+
+ recover(sqlEx);
+ return connection.isValid(timeout);
+ }
+ }
+
+ @Override
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ return (PoolAwareConnection.class.equals(iface)) ? true : connection.isWrapperFor(iface);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ return PoolAwareConnection.class.equals(iface) ? (T) this : connection.unwrap(iface);
+ }
+
+ @Override
+ public NClob createNClob() throws SQLException {
+ try {
+ return connection.createNClob();
+ } catch (SQLException sqlEx) {
+
+ recover(sqlEx);
+ return connection.createNClob();
+ }
+ }
+
+ @Override
+ public SQLXML createSQLXML() throws SQLException {
+ try {
+ return connection.createSQLXML();
+ } catch (SQLException sqlEx) {
+
+ recover(sqlEx);
+ return connection.createSQLXML();
+ }
+ }
+
+ @Override
+ public void setClientInfo(Properties properties) throws SQLClientInfoException {
+ // TODO: we can implement that now.
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setClientInfo(String name, String value) throws SQLClientInfoException {
+ // TODO: we can implement that now.
+ throw new UnsupportedOperationException();
+ }
+
+ // JDBC 4.1 compatibility pre Java 7
+ public void setSchema(String schema) throws SQLException {
+ throw new UnsupportedOperationException();
+ }
+
+ // JDBC 4.1 compatibility pre Java 7
+ public String getSchema() throws SQLException {
+ throw new UnsupportedOperationException();
+ }
+
+ // JDBC 4.1 compatibility pre Java 7
+ public void abort(Executor executor) throws SQLException {
+ throw new UnsupportedOperationException();
+ }
+
+ // JDBC 4.1 compatibility pre Java 7
+ public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
+ throw new UnsupportedOperationException();
+ }
+
+ // JDBC 4.1 compatibility pre Java 7
+ public int getNetworkTimeout() throws SQLException {
+ throw new UnsupportedOperationException();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSource.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSource.java b/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSource.java
new file mode 100644
index 0000000..83bf2f2
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSource.java
@@ -0,0 +1,314 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Logger;
+
+import javax.sql.DataSource;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * A non-blocking {@link DataSource} with a pool of connections.
+ *
+ * @since 4.0
+ */
+public class PoolingDataSource implements DataSource {
+
+ /**
+ * Defines a maximum time in milliseconds that a connection request could
+ * wait in the connection queue. After this period expires, an exception
+ * will be thrown in the calling method.
+ */
+ public static final int MAX_QUEUE_WAIT_DEFAULT = 20000;
+
+ private static Log LOGGER = LogFactory.getLog(PoolingDataSource.class);
+
+ private DataSource nonPoolingDataSource;
+ private long maxQueueWaitTime;
+
+ private Map<PoolAwareConnection, Object> pool;
+ private Semaphore poolCap;
+ private BlockingQueue<PoolAwareConnection> available;
+
+ private int maxIdleConnections;
+ private int minConnections;
+ private String validationQuery;
+
+ static int maxIdleConnections(int min, int max) {
+ return min == max ? min : min + (int) Math.ceil((max - min) / 2d);
+ }
+
+ public PoolingDataSource(DataSource nonPoolingDataSource, PoolingDataSourceParameters parameters) {
+
+ int minConnections = parameters.getMinConnections();
+ int maxConnections = parameters.getMaxConnections();
+
+ // sanity check
+ if (minConnections < 0) {
+ throw new IllegalArgumentException("Negative min connections: " + minConnections);
+ }
+
+ if (maxConnections < 0) {
+ throw new IllegalArgumentException("Negative max connections: " + maxConnections);
+ }
+
+ if (minConnections > maxConnections) {
+ throw new IllegalArgumentException("Min connections (" + minConnections
+ + ") is greater than max connections (" + maxConnections + ")");
+ }
+
+ this.nonPoolingDataSource = nonPoolingDataSource;
+ this.maxQueueWaitTime = parameters.getMaxQueueWaitTime();
+ this.validationQuery = parameters.getValidationQuery();
+ this.minConnections = minConnections;
+ this.pool = new ConcurrentHashMap<PoolAwareConnection, Object>((int) (maxConnections / 0.75));
+ this.available = new ArrayBlockingQueue<PoolAwareConnection>(maxConnections);
+ this.poolCap = new Semaphore(maxConnections);
+ this.maxIdleConnections = maxIdleConnections(minConnections, maxConnections);
+
+ // grow pull to min connections
+ try {
+ for (int i = 0; i < minConnections; i++) {
+ PoolAwareConnection c = createUnchecked();
+ reclaim(c);
+ }
+ } catch (BadValidationQueryException e) {
+ throw new CayenneRuntimeException("Bad validation query: " + validationQuery, e);
+ } catch (SQLException e) {
+ LOGGER.info("Error creating new connection when starting connection pool, ignoring", e);
+ }
+ }
+
+ int poolSize() {
+ return pool.size();
+ }
+
+ int availableSize() {
+ return available.size();
+ }
+
+ void shutdown() {
+
+ // expecting surrounding environment to block new requests for
+ // connections before calling this method. Still previously unchecked
+ // connections may be returned. I.e. "pool" will not grow during
+ // shutdown, which is the only thing that we need
+
+ for (PoolAwareConnection c : pool.keySet()) {
+ retire(c);
+ }
+
+ available.clear();
+ pool = Collections.emptyMap();
+ }
+
+ void managePool() {
+
+ // do not grow or shrink abruptly ... open or close one connection on
+ // each call
+
+ if (available.size() < minConnections) {
+
+ try {
+ PoolAwareConnection c = createUnchecked();
+ reclaim(c);
+ } catch (SQLException e) {
+ LOGGER.info("Error creating new connection when managing connection pool, ignoring", e);
+ }
+
+ } else if (available.size() > maxIdleConnections) {
+
+ PoolAwareConnection c = uncheckNonBlocking(false);
+ if (c != null) {
+ retire(c);
+ }
+ }
+
+ }
+
+ /**
+ * Closes the connection and removes it from the pool. The connection must
+ * be an unchecked connection.
+ */
+ void retire(PoolAwareConnection connection) {
+ pool.remove(connection);
+
+ poolCap.release();
+
+ try {
+ connection.getConnection().close();
+ } catch (SQLException e) {
+ // ignore?
+ }
+ }
+
+ /**
+ * Returns connection back to the pool if possible. The connection must be
+ * an unchecked connection.
+ */
+ void reclaim(PoolAwareConnection connection) {
+
+ // the queue may overflow potentially and we won't be able to add the
+ // object
+ if (!available.offer(connection)) {
+ retire(connection);
+ }
+ }
+
+ PoolAwareConnection uncheckNonBlocking(boolean validate) {
+ PoolAwareConnection c = available.poll();
+ return validate ? validateUnchecked(c) : c;
+ }
+
+ PoolAwareConnection uncheckBlocking(boolean validate) {
+ PoolAwareConnection c;
+ try {
+ c = available.poll(maxQueueWaitTime, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return null;
+ }
+
+ return validate ? validateUnchecked(c) : c;
+ }
+
+ PoolAwareConnection validateUnchecked(PoolAwareConnection c) {
+
+ if (c == null || c.validate()) {
+ return c;
+ }
+
+ // this will recursively validate all connections that exist in the pool
+ // until a valid one is found or a pool is exhausted
+ retire(c);
+ return validateUnchecked(available.poll());
+ }
+
+ PoolAwareConnection createUnchecked() throws SQLException {
+
+ if (!poolCap.tryAcquire()) {
+ return null;
+ }
+
+ PoolAwareConnection c = createWrapped();
+
+ pool.put(c, 1);
+
+ // even though we got a fresh connection, let's still validate it...
+ // This will provide consistent behavior between cached and uncached
+ // connections in respect to invalid validation queries
+ if (!c.validate()) {
+ throw new BadValidationQueryException(
+ "Can't validate a fresh connection. Likely validation query is wrong: " + validationQuery);
+ }
+
+ return c;
+ }
+
+ PoolAwareConnection createWrapped() throws SQLException {
+ return new PoolAwareConnection(this, createUnwrapped(), validationQuery);
+ }
+
+ Connection createUnwrapped() throws SQLException {
+ return nonPoolingDataSource.getConnection();
+ }
+
+ @Override
+ public Connection getConnection() throws SQLException {
+
+ // strategy for getting a connection -
+ // 1. quick peek for available connections
+ // 2. create new one
+ // 3. wait for a user to return connection
+
+ PoolAwareConnection c;
+
+ c = uncheckNonBlocking(true);
+ if (c != null) {
+ return c;
+ }
+
+ c = createUnchecked();
+ if (c != null) {
+ return c;
+ }
+
+ c = uncheckBlocking(true);
+ if (c != null) {
+ return c;
+ }
+
+ throw new SQLException("Can't obtain connection. Request to pool timed out. Total pool size: " + pool.size());
+ }
+
+ @Override
+ public Connection getConnection(String userName, String password) throws SQLException {
+ throw new UnsupportedOperationException(
+ "Connections for a specific user are not supported by the pooled DataSource");
+ }
+
+ @Override
+ public int getLoginTimeout() throws java.sql.SQLException {
+ return nonPoolingDataSource.getLoginTimeout();
+ }
+
+ @Override
+ public void setLoginTimeout(int seconds) throws java.sql.SQLException {
+ nonPoolingDataSource.setLoginTimeout(seconds);
+ }
+
+ @Override
+ public PrintWriter getLogWriter() throws java.sql.SQLException {
+ return nonPoolingDataSource.getLogWriter();
+ }
+
+ @Override
+ public void setLogWriter(PrintWriter out) throws java.sql.SQLException {
+ nonPoolingDataSource.setLogWriter(out);
+ }
+
+ @Override
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ return (PoolingDataSource.class.equals(iface)) ? true : nonPoolingDataSource.isWrapperFor(iface);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ return PoolingDataSource.class.equals(iface) ? (T) this : nonPoolingDataSource.unwrap(iface);
+ }
+
+ // JDBC 4.1 compatibility under Java pre 1.7
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ throw new SQLFeatureNotSupportedException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSourceManager.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSourceManager.java b/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSourceManager.java
new file mode 100644
index 0000000..6dacdd6
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSourceManager.java
@@ -0,0 +1,65 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+/**
+ * Manages the state of a {@link PoolingDataSource} instance, performing
+ * periodic expansion/contraction of pooled connections, and orchestrating
+ * shutdown.
+ *
+ * @since 4.0
+ */
+class PoolingDataSourceManager extends Thread {
+
+ private volatile boolean shouldStop;
+ private PoolingDataSource dataSource;
+
+ PoolingDataSourceManager(PoolingDataSource dataSource) {
+ setName("PoolManagerCleanup-" + dataSource.hashCode());
+ setDaemon(true);
+
+ this.dataSource = dataSource;
+ this.shouldStop = false;
+ }
+
+ public void shutdown() {
+ shouldStop = true;
+ dataSource.shutdown();
+ interrupt();
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+
+ try {
+ // don't do it too often
+ Thread.sleep(600000);
+ } catch (InterruptedException iex) {
+ // ignore...
+ }
+
+ if (shouldStop) {
+ break;
+ }
+
+ dataSource.managePool();
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSourceParameters.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSourceParameters.java b/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSourceParameters.java
new file mode 100644
index 0000000..545155b
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSourceParameters.java
@@ -0,0 +1,64 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+/**
+ * A collection of pooling parameters used by {@link PoolingDataSource}.
+ *
+ * @since 4.0
+ */
+public class PoolingDataSourceParameters {
+
+ private String validationQuery;
+ private int minConnections;
+ private int maxConnections;
+ private long maxQueueWaitTime;
+
+ public int getMinConnections() {
+ return minConnections;
+ }
+
+ public void setMinConnections(int minConnections) {
+ this.minConnections = minConnections;
+ }
+
+ public int getMaxConnections() {
+ return maxConnections;
+ }
+
+ public void setMaxConnections(int maxConnections) {
+ this.maxConnections = maxConnections;
+ }
+
+ public long getMaxQueueWaitTime() {
+ return maxQueueWaitTime;
+ }
+
+ public void setMaxQueueWaitTime(long maxQueueWaitTime) {
+ this.maxQueueWaitTime = maxQueueWaitTime;
+ }
+
+ public String getValidationQuery() {
+ return validationQuery;
+ }
+
+ public void setValidationQuery(String validationQuery) {
+ this.validationQuery = validationQuery;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/main/java/org/apache/cayenne/datasource/StoppedDataSource.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/datasource/StoppedDataSource.java b/cayenne-server/src/main/java/org/apache/cayenne/datasource/StoppedDataSource.java
new file mode 100644
index 0000000..383c7b7
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/datasource/StoppedDataSource.java
@@ -0,0 +1,88 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.logging.Logger;
+
+import javax.sql.DataSource;
+
+/**
+ * A DataSource wrapper that prevents callers from obtaining connections from
+ * another {@link DataSource}.
+ *
+ * @since 4.0
+ */
+class StoppedDataSource implements DataSource {
+
+ private DataSource dataSource;
+
+ public StoppedDataSource(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ @Override
+ public Connection getConnection() throws SQLException {
+ throw new SQLException("DataSource is stopped");
+ }
+
+ @Override
+ public Connection getConnection(String arg0, String arg1) throws SQLException {
+ throw new SQLException("DataSource is stopped");
+ }
+
+ @Override
+ public PrintWriter getLogWriter() throws SQLException {
+ return dataSource.getLogWriter();
+ }
+
+ @Override
+ public int getLoginTimeout() throws SQLException {
+ return dataSource.getLoginTimeout();
+ }
+
+ @Override
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ return (StoppedDataSource.class.equals(iface)) ? true : dataSource.isWrapperFor(iface);
+ }
+
+ @Override
+ public void setLogWriter(PrintWriter arg0) throws SQLException {
+ dataSource.setLogWriter(arg0);
+ }
+
+ @Override
+ public void setLoginTimeout(int arg0) throws SQLException {
+ dataSource.setLoginTimeout(arg0);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ return StoppedDataSource.class.equals(iface) ? (T) this : dataSource.unwrap(iface);
+ }
+
+ // JDBC 4.1 compatibility under Java pre 1.7
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ throw new SQLFeatureNotSupportedException();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/conn/BasePoolingDataSourceIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/conn/BasePoolingDataSourceIT.java b/cayenne-server/src/test/java/org/apache/cayenne/conn/BasePoolingDataSourceIT.java
deleted file mode 100644
index ef81d1a..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/conn/BasePoolingDataSourceIT.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*****************************************************************
- * 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.cayenne.conn;
-
-import java.sql.Driver;
-import java.sql.SQLException;
-
-import org.apache.cayenne.di.AdhocObjectFactory;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.log.JdbcEventLogger;
-import org.apache.cayenne.unit.di.server.CayenneProjects;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import org.junit.After;
-import org.junit.Before;
-
-@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
-public class BasePoolingDataSourceIT extends ServerCase {
-
- @Inject
- private DataSourceInfo dataSourceInfo;
-
- @Inject
- private AdhocObjectFactory objectFactory;
-
- @Inject
- private JdbcEventLogger logger;
-
- protected PoolingDataSource dataSource;
-
- @Before
- public void before() throws SQLException {
-
- Driver driver = objectFactory.newInstance(Driver.class, dataSourceInfo.getJdbcDriver());
- DriverDataSource nonPooling = new DriverDataSource(driver, dataSourceInfo.getDataSourceUrl(),
- dataSourceInfo.getUserName(), dataSourceInfo.getPassword());
- nonPooling.setLogger(logger);
-
- PoolingDataSourceParameters poolParameters = createParameters();
- this.dataSource = new PoolingDataSource(new PooledConnectionFactory(nonPooling), poolParameters);
- }
-
- @After
- public void after() throws SQLException {
- if (dataSource != null) {
- dataSource.beforeScopeEnd();
- }
- }
-
- protected PoolingDataSourceParameters createParameters() {
- PoolingDataSourceParameters poolParameters = new PoolingDataSourceParameters();
- poolParameters.setMinConnections(2);
- poolParameters.setMaxConnections(3);
- poolParameters.setMaxQueueWaitTime(1000);
- return poolParameters;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/conn/DriverDataSourceTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/conn/DriverDataSourceTest.java b/cayenne-server/src/test/java/org/apache/cayenne/conn/DriverDataSourceTest.java
deleted file mode 100644
index bd3ecd7..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/conn/DriverDataSourceTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*****************************************************************
- * 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.cayenne.conn;
-
-import org.junit.Test;
-
-import java.sql.SQLException;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-public class DriverDataSourceTest {
-
- @Test
- public void testLazyInstantiationOfDriverClass() {
- DriverDataSource dataSource = new DriverDataSource("does.not.exist.Driver", "jdbc:postgresql://localhost/database");
- assertNotNull(dataSource);
-
- try {
- dataSource.getConnection();
- fail();
- } catch (SQLException e) {
- // expected because driver class does not exist
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/conn/PooledConnectionImplTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/conn/PooledConnectionImplTest.java b/cayenne-server/src/test/java/org/apache/cayenne/conn/PooledConnectionImplTest.java
deleted file mode 100644
index 829ceb6..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/conn/PooledConnectionImplTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*****************************************************************
- * 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.cayenne.conn;
-
-import static org.mockito.Mockito.mock;
-
-import java.sql.SQLException;
-
-import javax.sql.ConnectionPoolDataSource;
-import javax.sql.DataSource;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class PooledConnectionImplTest {
-
- private PoolingDataSource dataSource;
-
- @Before
- public void before() throws SQLException {
- PoolingDataSourceParameters poolParameters = new PoolingDataSourceParameters();
- poolParameters.setMinConnections(0);
- poolParameters.setMaxConnections(0);
- poolParameters.setMaxQueueWaitTime(1000);
-
- this.dataSource = new PoolingDataSource(mock(ConnectionPoolDataSource.class), poolParameters);
- }
-
- @Test
- public void testConnectionErrorNotificationConcurrency() throws Exception {
- // test a case when error notification is sent to connection
- // that has been removed from the pool, but when pool is still a
- // listener for its events.
-
- PooledConnectionImpl con = new PooledConnectionImpl(mock(DataSource.class), "un", "password");
- con.addConnectionEventListener(dataSource);
- con.connectionErrorNotification(new java.sql.SQLException("Bad SQL Exception.."));
- }
-
- @Test
- public void testConnectionClosedNotificationConcurrency() throws Exception {
- // test a case when closed notification is sent to connection
- // that has been removed from the pool, but when pool is still a
- // listener for its events.
- PooledConnectionImpl con = new PooledConnectionImpl(mock(DataSource.class), "un", "password");
- con.addConnectionEventListener(dataSource);
- con.connectionClosedNotification();
- }
-
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/conn/PoolingDataSourceIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/conn/PoolingDataSourceIT.java b/cayenne-server/src/test/java/org/apache/cayenne/conn/PoolingDataSourceIT.java
deleted file mode 100644
index d2814d9..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/conn/PoolingDataSourceIT.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*****************************************************************
- * 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.cayenne.conn;
-
-import static org.junit.Assert.assertEquals;
-
-import java.sql.Connection;
-
-import org.apache.cayenne.unit.di.server.CayenneProjects;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import org.junit.Test;
-
-@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
-public class PoolingDataSourceIT extends BasePoolingDataSourceIT {
-
- @Test(expected = UnsupportedOperationException.class)
- public void testGetConnectionWithUserName() throws Exception {
- dataSource.getConnection("user", "password");
- }
-
- @Test
- public void testGetConnection() throws Exception {
-
- assertEquals(0, dataSource.getCurrentlyInUse());
- assertEquals(2, dataSource.getCurrentlyUnused());
-
- Connection c1 = dataSource.getConnection();
- assertEquals(1, dataSource.getCurrentlyInUse());
- assertEquals(1, dataSource.getCurrentlyUnused());
-
- Connection c2 = dataSource.getConnection();
- assertEquals(2, dataSource.getCurrentlyInUse());
- assertEquals(0, dataSource.getCurrentlyUnused());
-
- c1.close();
- assertEquals(1, dataSource.getCurrentlyInUse());
- assertEquals(1, dataSource.getCurrentlyUnused());
-
- c2.close();
- assertEquals(0, dataSource.getCurrentlyInUse());
- assertEquals(2, dataSource.getCurrentlyUnused());
- }
-
- @Test
- public void testGetConnection_BeforeScopeEnd() throws Exception {
-
- assertEquals(0, dataSource.getCurrentlyInUse());
- assertEquals(2, dataSource.getCurrentlyUnused());
-
- dataSource.beforeScopeEnd();
-
- assertEquals(0, dataSource.getCurrentlyInUse());
- assertEquals(0, dataSource.getCurrentlyUnused());
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/conn/PoolingDataSource_FailingValidationQueryIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/conn/PoolingDataSource_FailingValidationQueryIT.java b/cayenne-server/src/test/java/org/apache/cayenne/conn/PoolingDataSource_FailingValidationQueryIT.java
deleted file mode 100644
index d832ae5..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/conn/PoolingDataSource_FailingValidationQueryIT.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*****************************************************************
- * 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.cayenne.conn;
-
-import java.sql.Connection;
-import java.sql.SQLException;
-
-import org.apache.cayenne.unit.di.server.CayenneProjects;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import org.junit.Test;
-
-@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
-public class PoolingDataSource_FailingValidationQueryIT extends BasePoolingDataSourceIT {
-
- @Override
- protected PoolingDataSourceParameters createParameters() {
- PoolingDataSourceParameters params = super.createParameters();
- params.setValidationQuery("SELECT count(1) FROM NO_SUCH_TABLE");
- return params;
- }
-
- @Test(expected = SQLException.class)
- public void testGetConnection_ValidationQuery() throws Exception {
- Connection c1 = dataSource.getConnection();
- c1.close();
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/conn/PoolingDataSource_ValidationQueryIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/conn/PoolingDataSource_ValidationQueryIT.java b/cayenne-server/src/test/java/org/apache/cayenne/conn/PoolingDataSource_ValidationQueryIT.java
deleted file mode 100644
index 45a5689..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/conn/PoolingDataSource_ValidationQueryIT.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*****************************************************************
- * 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.cayenne.conn;
-
-import static org.junit.Assert.assertEquals;
-
-import java.sql.Connection;
-
-import org.apache.cayenne.unit.di.server.CayenneProjects;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import org.junit.Test;
-
-@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
-public class PoolingDataSource_ValidationQueryIT extends BasePoolingDataSourceIT {
-
- @Override
- protected PoolingDataSourceParameters createParameters() {
- PoolingDataSourceParameters params = super.createParameters();
- params.setValidationQuery("SELECT count(1) FROM ARTIST");
- return params;
- }
-
- @Test
- public void testGetConnection_ValidationQuery() throws Exception {
-
- assertEquals(0, dataSource.getCurrentlyInUse());
- assertEquals(2, dataSource.getCurrentlyUnused());
-
- // TODO: we are not testing much here... we really need to mock
- // validation query execution somehow and verify that it is taken into
- // account
-
- Connection c1 = dataSource.getConnection();
- assertEquals(1, dataSource.getCurrentlyInUse());
- assertEquals(1, dataSource.getCurrentlyUnused());
-
- c1.close();
- }
-}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/datasource/BasePoolingDataSourceIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/datasource/BasePoolingDataSourceIT.java b/cayenne-server/src/test/java/org/apache/cayenne/datasource/BasePoolingDataSourceIT.java
new file mode 100644
index 0000000..0c9ea45
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/datasource/BasePoolingDataSourceIT.java
@@ -0,0 +1,77 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import java.sql.Driver;
+import java.sql.SQLException;
+
+import org.apache.cayenne.conn.DataSourceInfo;
+import org.apache.cayenne.datasource.PoolingDataSource;
+import org.apache.cayenne.datasource.PoolingDataSourceParameters;
+import org.apache.cayenne.di.AdhocObjectFactory;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.log.JdbcEventLogger;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.After;
+import org.junit.Before;
+
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class BasePoolingDataSourceIT extends ServerCase {
+
+ @Inject
+ private DataSourceInfo dataSourceInfo;
+
+ @Inject
+ private AdhocObjectFactory objectFactory;
+
+ @Inject
+ private JdbcEventLogger logger;
+
+ protected PoolingDataSource dataSource;
+
+ @Before
+ public void before() throws SQLException {
+
+ Driver driver = objectFactory.newInstance(Driver.class, dataSourceInfo.getJdbcDriver());
+ DriverDataSource nonPooling = new DriverDataSource(driver, dataSourceInfo.getDataSourceUrl(),
+ dataSourceInfo.getUserName(), dataSourceInfo.getPassword());
+ nonPooling.setLogger(logger);
+
+ PoolingDataSourceParameters poolParameters = createParameters();
+ this.dataSource = new PoolingDataSource(nonPooling, poolParameters);
+ }
+
+ @After
+ public void after() throws SQLException {
+ if (dataSource != null) {
+ dataSource.shutdown();
+ }
+ }
+
+ protected PoolingDataSourceParameters createParameters() {
+ PoolingDataSourceParameters poolParameters = new PoolingDataSourceParameters();
+ poolParameters.setMinConnections(2);
+ poolParameters.setMaxConnections(3);
+ poolParameters.setMaxQueueWaitTime(1000);
+ return poolParameters;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/datasource/DriverDataSourceTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/datasource/DriverDataSourceTest.java b/cayenne-server/src/test/java/org/apache/cayenne/datasource/DriverDataSourceTest.java
new file mode 100644
index 0000000..cb361f2
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/datasource/DriverDataSourceTest.java
@@ -0,0 +1,44 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import org.apache.cayenne.datasource.DriverDataSource;
+import org.junit.Test;
+
+import java.sql.SQLException;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+public class DriverDataSourceTest {
+
+ @Test
+ public void testLazyInstantiationOfDriverClass() {
+ DriverDataSource dataSource = new DriverDataSource("does.not.exist.Driver", "jdbc:postgresql://localhost/database");
+ assertNotNull(dataSource);
+
+ try {
+ dataSource.getConnection();
+ fail();
+ } catch (SQLException e) {
+ // expected because driver class does not exist
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolAwareConnectionTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolAwareConnectionTest.java b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolAwareConnectionTest.java
new file mode 100644
index 0000000..da94b94
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolAwareConnectionTest.java
@@ -0,0 +1,99 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+import org.apache.cayenne.datasource.PoolAwareConnection;
+import org.apache.cayenne.datasource.PoolingDataSource;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PoolAwareConnectionTest {
+
+ private PoolingDataSource parentMock;
+ private Connection connectionMock;
+
+ @Before
+ public void before() throws SQLException {
+ connectionMock = mock(Connection.class);
+
+ parentMock = mock(PoolingDataSource.class);
+ when(parentMock.createUnwrapped()).thenReturn(connectionMock);
+ }
+
+ @Test
+ public void testRecover() throws SQLException {
+ PoolAwareConnection paConnection = new PoolAwareConnection(parentMock, connectionMock, null);
+ SQLException e = mock(SQLException.class);
+
+ verify(parentMock, times(0)).createUnwrapped();
+ paConnection.recover(e);
+ verify(parentMock, times(1)).createUnwrapped();
+
+ assertSame(connectionMock, paConnection.getConnection());
+ }
+
+ @Test
+ public void testPrepareStatement() throws SQLException {
+ PreparedStatement firstTry = mock(PreparedStatement.class);
+ PreparedStatement secondTry = mock(PreparedStatement.class);
+
+ when(connectionMock.prepareStatement(anyString())).thenReturn(firstTry, secondTry);
+
+ PoolAwareConnection paConnection = new PoolAwareConnection(parentMock, connectionMock, null);
+ PreparedStatement st = paConnection.prepareStatement("SELECT 1");
+ assertSame(firstTry, st);
+ }
+
+ @Test
+ public void testPrepareStatement_Recover() throws SQLException {
+
+ PreparedStatement secondTry = mock(PreparedStatement.class);
+ when(connectionMock.prepareStatement(anyString())).thenThrow(new SQLException("E1")).thenReturn(secondTry);
+
+ PoolAwareConnection paConnection = new PoolAwareConnection(parentMock, connectionMock, null);
+ PreparedStatement st = paConnection.prepareStatement("SELECT 1");
+ assertSame(secondTry, st);
+ }
+
+ @Test
+ public void testPrepareStatement_Recover_Impossible() throws SQLException {
+
+ SQLException original = new SQLException("E1");
+ when(connectionMock.prepareStatement(anyString())).thenThrow(original);
+ PoolAwareConnection paConnection = new PoolAwareConnection(parentMock, connectionMock, null);
+
+ try {
+ paConnection.prepareStatement("SELECT 1");
+ } catch (SQLException e) {
+ assertSame(original, e);
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSourceIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSourceIT.java b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSourceIT.java
new file mode 100644
index 0000000..e9b0746
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSourceIT.java
@@ -0,0 +1,160 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.Test;
+
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class PoolingDataSourceIT extends BasePoolingDataSourceIT {
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testGetConnectionWithUserName() throws Exception {
+ dataSource.getConnection("user", "password");
+ }
+
+ @Test
+ public void testGetConnection() throws Exception {
+
+ assertEquals(2, dataSource.poolSize());
+ assertEquals(2, dataSource.availableSize());
+
+ Connection c1 = dataSource.getConnection();
+ assertEquals(2, dataSource.poolSize());
+ assertEquals(1, dataSource.availableSize());
+
+ Connection c2 = dataSource.getConnection();
+ assertEquals(2, dataSource.poolSize());
+ assertEquals(0, dataSource.availableSize());
+
+ Connection c3 = dataSource.getConnection();
+ assertEquals(3, dataSource.poolSize());
+ assertEquals(0, dataSource.availableSize());
+
+ c1.close();
+ assertEquals(3, dataSource.poolSize());
+ assertEquals(1, dataSource.availableSize());
+
+ c2.close();
+ assertEquals(3, dataSource.poolSize());
+ assertEquals(2, dataSource.availableSize());
+
+ c3.close();
+ assertEquals(3, dataSource.poolSize());
+ assertEquals(3, dataSource.availableSize());
+ }
+
+ @Test
+ public void testGetConnection_BeforeScopeEnd() throws Exception {
+
+ assertEquals(2, dataSource.poolSize());
+ assertEquals(2, dataSource.availableSize());
+
+ dataSource.shutdown();
+
+ assertEquals(0, dataSource.poolSize());
+ assertEquals(0, dataSource.availableSize());
+ }
+
+ @Test
+ public void testGetConnection_Concurrent() {
+
+ PoolTask[] tasks = new PoolTask[2];
+ for (int i = 0; i < tasks.length; i++) {
+ tasks[i] = new PoolTask();
+ }
+
+ ExecutorService executor = Executors.newFixedThreadPool(tasks.length);
+
+ for (int j = 0; j < 100; j++) {
+ for (int i = 0; i < tasks.length; i++) {
+ executor.submit(tasks[i]);
+ }
+ }
+
+ // check for completion or deadlock
+ executor.shutdown();
+ try {
+ // normally this completes in less than 2 seconds. If it takes 30
+ // then it failed.
+ boolean didFinish = executor.awaitTermination(30, TimeUnit.SECONDS);
+ if (!didFinish) {
+ fail("Connection pool either deadlocked or contended over the lock too long.");
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
+ for (int i = 0; i < tasks.length; i++) {
+ assertEquals(100, tasks[i].i.get());
+ }
+ }
+
+ class PoolTask implements Runnable {
+
+ AtomicInteger i = new AtomicInteger();
+
+ @Override
+ public void run() {
+
+ i.incrementAndGet();
+ try {
+ Connection c = dataSource.getConnection();
+ try {
+
+ Statement st = c.createStatement();
+ try {
+
+ ResultSet rs = st.executeQuery("SELECT ARTIST_ID FROM ARTIST");
+
+ try {
+ rs.next();
+
+ } finally {
+ rs.close();
+ }
+ } finally {
+ st.close();
+ }
+
+ } finally {
+ c.close();
+ }
+
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/517df07b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSourceTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSourceTest.java b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSourceTest.java
new file mode 100644
index 0000000..25b7e7e
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolingDataSourceTest.java
@@ -0,0 +1,196 @@
+/*****************************************************************
+ * 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.cayenne.datasource;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.sql.DataSource;
+
+import org.apache.cayenne.datasource.PoolAwareConnection;
+import org.apache.cayenne.datasource.PoolingDataSource;
+import org.apache.cayenne.datasource.PoolingDataSourceParameters;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class PoolingDataSourceTest {
+
+ private DataSource nonPooling;
+ private PoolingDataSourceParameters params;
+
+ @Before
+ public void before() throws SQLException {
+ nonPooling = mock(DataSource.class);
+ when(nonPooling.getConnection()).thenAnswer(new Answer<Connection>() {
+ @Override
+ public Connection answer(InvocationOnMock invocation) throws Throwable {
+ return mock(Connection.class);
+ }
+ });
+ params = new PoolingDataSourceParameters();
+ }
+
+ @Test
+ public void testManagePool_High() throws SQLException {
+
+ int max = 5;
+
+ params.setMinConnections(1);
+ params.setMaxConnections(max);
+ PoolingDataSource ds = new PoolingDataSource(nonPooling, params);
+
+ // opening and closing 'max' connections should fill the pool to the
+ // top...
+ Connection[] open = new Connection[max];
+ for (int i = 0; i < max; i++) {
+ open[i] = ds.getConnection();
+ }
+
+ for (Connection c : open) {
+ c.close();
+ }
+
+ // now we can start calling 'managePool', and it would close connections
+ // one at a time until we reach a threshold on idle
+ assertEquals(max, ds.poolSize());
+ ds.managePool();
+ assertEquals(max - 1, ds.poolSize());
+ ds.managePool();
+ assertEquals(max - 2, ds.poolSize());
+
+ // pool equilibrium was reached. subsequent calls should not open or
+ // close connections
+ ds.managePool();
+ assertEquals(max - 2, ds.poolSize());
+ ds.managePool();
+ assertEquals(max - 2, ds.poolSize());
+ }
+
+ @Test
+ public void testManagePool_Low() throws SQLException {
+
+ int min = 2;
+
+ params.setMinConnections(min);
+ params.setMaxConnections(min + 5);
+ PoolingDataSource ds = new PoolingDataSource(nonPooling, params);
+
+ // we start with a min number of connections
+ assertEquals(min, ds.poolSize());
+
+ // now lets evict a bunch of connections before we can start growing the
+ // pool again
+ for (int i = 0; i < min; i++) {
+ ds.retire(ds.uncheckNonBlocking(false));
+ }
+
+ // now we can start calling 'managePool', and it would open connections
+ // one at a time
+ assertEquals(0, ds.poolSize());
+ ds.managePool();
+ assertEquals(1, ds.poolSize());
+ ds.managePool();
+ assertEquals(2, ds.poolSize());
+
+ // pool equilibrium was reached. subsequent calls should not open or
+ // close connections
+ ds.managePool();
+ assertEquals(2, ds.poolSize());
+ ds.managePool();
+ assertEquals(2, ds.poolSize());
+ }
+
+ @Test
+ public void testValidateUnchecked() {
+
+ final PoolAwareConnection[] connections = validConnections(4);
+
+ params.setMinConnections(4);
+ params.setMaxConnections(10);
+
+ PoolingDataSource ds = new PoolingDataSource(nonPooling, params) {
+
+ int i;
+
+ @Override
+ PoolAwareConnection createWrapped() throws SQLException {
+ return connections[i++];
+ }
+ };
+
+ // now that the pool is created, invalidate a few leading connections
+ when(connections[0].validate()).thenReturn(false);
+ when(connections[1].validate()).thenReturn(false);
+
+ Connection faceHeadConnection = mock(Connection.class);
+ PoolAwareConnection fakeHead = mock(PoolAwareConnection.class);
+ when(fakeHead.getConnection()).thenReturn(faceHeadConnection);
+
+ assertSame(connections[2], ds.validateUnchecked(fakeHead));
+ }
+
+ @Test
+ public void testGetConnection_UpperCap() throws SQLException {
+ int max = 5;
+ params.setMaxConnections(max);
+ params.setMaxQueueWaitTime(1000);
+ PoolingDataSource ds = new PoolingDataSource(nonPooling, params);
+
+ Connection[] unchecked = new Connection[max];
+
+ for (int i = 0; i < max; i++) {
+ unchecked[i] = ds.getConnection();
+ }
+
+ try {
+ ds.getConnection();
+ fail("Pool overflow not checked");
+ } catch (SQLException e) {
+ // expected ... all connections are taken
+ }
+
+ // return one connection ... it should become immediately available
+ unchecked[0].close();
+
+ Connection c = ds.getConnection();
+ assertNotNull(c);
+ }
+
+ PoolAwareConnection[] validConnections(int size) {
+ PoolAwareConnection[] connections = new PoolAwareConnection[size];
+ for (int i = 0; i < size; i++) {
+ Connection c = mock(Connection.class);
+
+ connections[i] = mock(PoolAwareConnection.class);
+ when(connections[i].getConnection()).thenReturn(c);
+ when(connections[i].validate()).thenReturn(true);
+ }
+ return connections;
+ }
+
+}