postgresql-jdbc.git / summary / log / commit / refs

commit    3f3bb0f7d7c17d6ce88d7b028f7ea7ec0dc97d5c
Author:   Kris Jurka <books@ejurka.com>
Date:     Wed Nov 29 04:00:27 2006 +0000

    Allow datasource code to build with JDK1.6 by splitting off jdbcN
    directories in the fashion of the core driver.  To maintain the
    generic interfaces like PGPoolingDataSource I had to use ant's
    conditional compilation to determine which implementation class to
    extend from.  It's ugly, but contained and works.


build.xml | 73 ++- org/postgresql/ds/PGConnectionPoolDataSource.java | 6 +- org/postgresql/ds/PGPooledConnection.java.in | 46 ++ org/postgresql/ds/PGPoolingDataSource.java | 512 --------------------- org/postgresql/ds/PGPoolingDataSource.java.in | 52 +++ org/postgresql/ds/PGSimpleDataSource.java | 47 -- org/postgresql/ds/PGSimpleDataSource.java.in | 26 ++ org/postgresql/ds/common/PooledConnectionImpl.java | 483 ------------------- .../ds/jdbc4/AbstractJdbc4PooledConnection.java | 32 ++ .../ds/jdbc4/AbstractJdbc4PoolingDataSource.java | 29 ++ .../ds/jdbc4/AbstractJdbc4SimpleDataSource.java | 28 ++ org/postgresql/xa/PGXAConnection.java | 4 +- 12 files changed, 281 insertions(+), 1057 deletions(-) diff --git a/build.xml b/build.xml index 40aefc60..27c906a9 100644 --- a/build.xml +++ b/build.xml @@ -8,7 +8,7 @@ This file now requires Ant 1.4.1. 2002-04-18 - $PostgreSQL: pgjdbc/build.xml,v 1.69 2006/06/08 10:34:50 jurka Exp $ + $PostgreSQL: pgjdbc/build.xml,v 1.70 2006/07/03 15:11:58 jurka Exp $ --> @@ -67,12 +67,7 @@ <available property="junit.task" classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTask"/> <condition property="datasource"> - <and> - <isset property="datasourceclass" /> - <not> - <isset property="jdbc4" /> - </not> - </and> + <isset property="datasourceclass" /> </condition> <condition property="jdbc2optionaltests"> @@ -173,10 +168,13 @@ <include name="${package}/jdbc3/Jdbc3PoolingDataSource.java" if="jdbc3any" /> <include name="${package}/jdbc3/Jdbc3SimpleDataSource.java" if="jdbc3any" /> - <include name="${package}/ds/**/*.java" if="datasource" /> + <include name="${package}/ds/*.java" if="datasource" /> + <include name="${package}/ds/common/*.java" if="datasource" /> + <include name="${package}/ds/jdbc23/*.java" if="datasource" /> + <include name="${package}/ds/jdbc4/*.java" if="jdbc4" /> <!-- XA stuff --> - <include name="${package}/xa/*.java" if="jdbc3any" /> + <include name="${package}/xa/*.java" if="jdbc3plus" /> </javac> </target> @@ -186,6 +184,9 @@ <srcfiles dir="."> <include name="${package}/util/PSQLException.java.in"/> <include name="${package}/Driver.java.in"/> + <include name="${package}/ds/PGSimpleDataSource.java.in"/> + <include name="${package}/ds/PGPoolingDataSource.java.in"/> + <include name="${package}/ds/PGPooledConnection.java.in"/> <include name="build.properties"/> <include name="build.local.properties" /> </srcfiles> @@ -232,6 +233,39 @@ <equals arg1="${jdbc4}" arg2="true" /> </condition> + <condition property="simpledsclass" value="org.postgresql.ds.jdbc23.AbstractJdbc23SimpleDataSource"> + <or> + <equals arg1="${jdbc2}" arg2="true" /> + <equals arg1="${jdbc3}" arg2="true" /> + <equals arg1="${jdbc3g}" arg2="true" /> + </or> + </condition> + <condition property="simpledsclass" value="org.postgresql.ds.jdbc4.AbstractJdbc4SimpleDataSource"> + <equals arg1="${jdbc4}" arg2="true" /> + </condition> + + <condition property="poolingdsclass" value="org.postgresql.ds.jdbc23.AbstractJdbc23PoolingDataSource"> + <or> + <equals arg1="${jdbc2}" arg2="true" /> + <equals arg1="${jdbc3}" arg2="true" /> + <equals arg1="${jdbc3g}" arg2="true" /> + </or> + </condition> + <condition property="poolingdsclass" value="org.postgresql.ds.jdbc4.AbstractJdbc4PoolingDataSource"> + <equals arg1="${jdbc4}" arg2="true" /> +</condition> + + <condition property="pooledconnclass" value="org.postgresql.ds.jdbc23.AbstractJdbc23PooledConnection"> + <or> + <equals arg1="${jdbc2}" arg2="true" /> + <equals arg1="${jdbc3}" arg2="true" /> + <equals arg1="${jdbc3g}" arg2="true" /> + </or> + </condition> + <condition property="pooledconnclass" value="org.postgresql.ds.jdbc4.AbstractJdbc4PooledConnection"> + <equals arg1="${jdbc4}" arg2="true" /> + </condition> + <!-- Determine if we have Throwable.initCause() if so we use it in org.postgresql.util.PSQLException instead of appending any nested exception to the message. --> @@ -266,6 +300,9 @@ <filter token="MINORVERSION" value="${minor}" /> <filter token="VERSION" value="PostgreSQL ${fullversion} ${edition} with ${ssl_edition}" /> <filter token="JDBCCONNECTCLASS" value="${connectclass}" /> + <filter token="POOLING_DS_CLASS" value="${poolingdsclass}" /> + <filter token="SIMPLE_DS_CLASS" value="${simpledsclass}" /> + <filter token="POOLED_CONN_CLASS" value="${pooledconnclass}" /> <filter token="DEF_PGPORT" value="${def_pgport}" /> <filter token="SSL" value="${ssl_config}" /> <filter token="NOINITCAUSE" value="${noInitCause}" /> @@ -287,6 +324,18 @@ overwrite="true" tofile="${package}/util/PSQLException.java" filtering="yes" /> + <copy file="${package}/ds/PGPoolingDataSource.java.in" + overwrite="true" + tofile="${package}/ds/PGPoolingDataSource.java" + filtering="yes" /> + <copy file="${package}/ds/PGSimpleDataSource.java.in" + overwrite="true" + tofile="${package}/ds/PGSimpleDataSource.java" + filtering="yes" /> + <copy file="${package}/ds/PGPooledConnection.java.in" + overwrite="true" + tofile="${package}/ds/PGPooledConnection.java" + filtering="yes" /> <echo message="Configured build for the ${edition} edition driver with ${ssl_edition}" /> </target> @@ -311,6 +360,9 @@ <delete quiet="true" dir="${jardir}" /> <delete quiet="true" file="${package}/Driver.java" /> <delete quiet="true" file="${package}/util/PSQLException.java" /> + <delete quiet="true" file="${package}/ds/PGPoolingDataSource.java" /> + <delete quiet="true" file="${package}/ds/PGSimpleDataSource.java" /> + <delete quiet="true" file="${package}/ds/PGPooledConnection.java" /> </target> <!-- This compiles and executes the JUnit tests --> @@ -340,7 +392,7 @@ <exclude name="${package}/test/jdbc2/optional/**" unless="jdbc2optionaltests" /> <exclude name="${package}/test/jdbc3/**" unless="jdbc3tests" /> <exclude name="${package}/test/util/**" unless="jdbc2optionaltests" /> - <exclude name="${package}/test/xa/**" unless="jdbc3any" /> + <exclude name="${package}/test/xa/**" unless="jdbc3plus" /> <classpath> <pathelement location="${jardir}/postgresql.jar"/> @@ -417,6 +469,7 @@ <exclude name="jdbc3/Jdbc3*.java" unless="jdbc3" /> <exclude name="jdbc3g/Jdbc3g*.java" unless="jdbc3g" /> <exclude name="jdbc4/*.java" unless="jdbc4" /> + <exclude name="ds/jdbc4/*.java" unless="jdbc4" /> <exclude name="test/**/*.java"/> </fileset> </javadoc> diff --git a/org/postgresql/ds/PGConnectionPoolDataSource.java b/org/postgresql/ds/PGConnectionPoolDataSource.java index 90a3dbb4..5bedf846 100644 --- a/org/postgresql/ds/PGConnectionPoolDataSource.java +++ b/org/postgresql/ds/PGConnectionPoolDataSource.java @@ -3,7 +3,7 @@ * Copyright (c) 2004-2005, PostgreSQL Global Development Group * * IDENTIFICATION -* $PostgreSQL: pgjdbc/org/postgresql/ds/PGConnectionPoolDataSource.java,v 1.2 2005/01/11 08:25:44 jurka Exp $ +* $PostgreSQL: pgjdbc/org/postgresql/ds/PGConnectionPoolDataSource.java,v 1.3 2005/01/14 01:20:17 oliver Exp $ * *------------------------------------------------------------------------- */ @@ -57,7 +57,7 @@ public class PGConnectionPoolDataSource extends BaseDataSource implements Serial */ public PooledConnection getPooledConnection() throws SQLException { - return new PooledConnectionImpl(getConnection(), defaultAutoCommit); + return new PGPooledConnection(getConnection(), defaultAutoCommit); } /** @@ -69,7 +69,7 @@ public class PGConnectionPoolDataSource extends BaseDataSource implements Serial */ public PooledConnection getPooledConnection(String user, String password) throws SQLException { - return new PooledConnectionImpl(getConnection(user, password), defaultAutoCommit); + return new PGPooledConnection(getConnection(user, password), defaultAutoCommit); } /** diff --git a/org/postgresql/ds/PGPooledConnection.java.in b/org/postgresql/ds/PGPooledConnection.java.in new file mode 100644 index 00000000..ceecb0aa --- /dev/null +++ b/org/postgresql/ds/PGPooledConnection.java.in @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------- +* +* Copyright (c) 2004-2005, PostgreSQL Global Development Group +* +* IDENTIFICATION +* $PostgreSQL$ +* +*------------------------------------------------------------------------- +*/ +package org.postgresql.ds; + +import java.sql.Connection; +import java.sql.SQLException; +import javax.sql.PooledConnection; +import javax.sql.ConnectionEvent; + +/** + * PostgreSQL implementation of the PooledConnection interface. This shouldn't + * be used directly, as the pooling client should just interact with the + * ConnectionPool instead. + * @see org.postgresql.ds.PGConnectionPoolDataSource + * + * @author Aaron Mulder (ammulder@chariotsolutions.com) + * @author Csaba Nagy (ncsaba@yahoo.com) + */ +public class PGPooledConnection + extends @POOLED_CONN_CLASS@ + implements PooledConnection +{ + + public PGPooledConnection(Connection con, boolean autoCommit, boolean isXA) + { + super(con, autoCommit, isXA); + } + + public PGPooledConnection(Connection con, boolean autoCommit) + { + this(con, autoCommit, false); + } + + protected ConnectionEvent createConnectionEvent(SQLException sqle) + { + return new ConnectionEvent(this, sqle); + } + +} diff --git a/org/postgresql/ds/PGPoolingDataSource.java b/org/postgresql/ds/PGPoolingDataSource.java deleted file mode 100644 index ade7d44f..00000000 --- a/org/postgresql/ds/PGPoolingDataSource.java +++ /dev/null @@ -1,512 +0,0 @@ -/*------------------------------------------------------------------------- -* -* Copyright (c) 2004-2005, PostgreSQL Global Development Group -* -* IDENTIFICATION -* $PostgreSQL: pgjdbc/org/postgresql/ds/PGPoolingDataSource.java,v 1.6 2005/01/11 08:25:44 jurka Exp $ -* -*------------------------------------------------------------------------- -*/ -package org.postgresql.ds; - -import javax.sql.*; -import javax.naming.*; -import java.util.*; -import java.sql.Connection; -import java.sql.SQLException; - -import org.postgresql.util.GT; -import org.postgresql.util.PSQLState; -import org.postgresql.util.PSQLException; -import org.postgresql.ds.common.*; - -/** - * DataSource which uses connection pooling. <font color="red">Don't use this if - * your server/middleware vendor provides a connection pooling implementation - * which interfaces with the PostgreSQL ConnectionPoolDataSource implementation!</font> - * This class is provided as a convenience, but the JDBC Driver is really not - * supposed to handle the connection pooling algorithm. Instead, the server or - * middleware product is supposed to handle the mechanics of connection pooling, - * and use the PostgreSQL implementation of ConnectionPoolDataSource to provide - * the connections to pool. - * - * <p>If you're sure you want to use this, then you must set the properties - * dataSourceName, databaseName, user, and password (if required for the user). - * The settings for serverName, portNumber, initialConnections, and - * maxConnections are optional. Note that <i>only connections - * for the default user will be pooled!</i> Connections for other users will - * be normal non-pooled connections, and will not count against the maximum pool - * size limit.</p> - * - * <p>If you put this DataSource in JNDI, and access it from different JVMs (or - * otherwise load this class from different ClassLoaders), you'll end up with one - * pool per ClassLoader or VM. This is another area where a server-specific - * implementation may provide advanced features, such as using a single pool - * across all VMs in a cluster.</p> - * - * <p>This implementation supports JDK 1.3 and higher.</p> - * - * @author Aaron Mulder (ammulder@chariotsolutions.com) - */ -public class PGPoolingDataSource extends BaseDataSource implements DataSource -{ - private static Map dataSources = new HashMap(); - - public static PGPoolingDataSource getDataSource(String name) - { - return (PGPoolingDataSource)dataSources.get(name); - } - - // Additional Data Source properties - protected String dataSourceName; // Must be protected for subclasses to sync updates to it - private int initialConnections = 0; - private int maxConnections = 0; - // State variables - private boolean initialized = false; - private Stack available = new Stack(); - private Stack used = new Stack(); - private Object lock = new Object() - ; - private PGConnectionPoolDataSource source; - - /** - * Gets a description of this DataSource. - */ - public String getDescription() - { - return "Pooling DataSource '" + dataSourceName + " from " + org.postgresql.Driver.getVersion(); - } - - /** - * Ensures the DataSource properties are not changed after the DataSource has - * been used. - * - * @throws java.lang.IllegalStateException - * The Server Name cannot be changed after the DataSource has been - * used. - */ - public void setServerName(String serverName) - { - if (initialized) - { - throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); - } - super.setServerName(serverName); - } - - /** - * Ensures the DataSource properties are not changed after the DataSource has - * been used. - * - * @throws java.lang.IllegalStateException - * The Database Name cannot be changed after the DataSource has been - * used. - */ - public void setDatabaseName(String databaseName) - { - if (initialized) - { - throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); - } - super.setDatabaseName(databaseName); - } - - /** - * Ensures the DataSource properties are not changed after the DataSource has - * been used. - * - * @throws java.lang.IllegalStateException - * The User cannot be changed after the DataSource has been - * used. - */ - public void setUser(String user) - { - if (initialized) - { - throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); - } - super.setUser(user); - } - - /** - * Ensures the DataSource properties are not changed after the DataSource has - * been used. - * - * @throws java.lang.IllegalStateException - * The Password cannot be changed after the DataSource has been - * used. - */ - public void setPassword(String password) - { - if (initialized) - { - throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); - } - super.setPassword(password); - } - - /** - * Ensures the DataSource properties are not changed after the DataSource has - * been used. - * - * @throws java.lang.IllegalStateException - * The Port Number cannot be changed after the DataSource has been - * used. - */ - public void setPortNumber(int portNumber) - { - if (initialized) - { - throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); - } - super.setPortNumber(portNumber); - } - - /** - * Gets the number of connections that will be created when this DataSource - * is initialized. If you do not call initialize explicitly, it will be - * initialized the first time a connection is drawn from it. - */ - public int getInitialConnections() - { - return initialConnections; - } - - /** - * Sets the number of connections that will be created when this DataSource - * is initialized. If you do not call initialize explicitly, it will be - * initialized the first time a connection is drawn from it. - * - * @throws java.lang.IllegalStateException - * The Initial Connections cannot be changed after the DataSource has been - * used. - */ - public void setInitialConnections(int initialConnections) - { - if (initialized) - { - throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); - } - this.initialConnections = initialConnections; - } - - /** - * Gets the maximum number of connections that the pool will allow. If a request - * comes in and this many connections are in use, the request will block until a - * connection is available. Note that connections for a user other than the - * default user will not be pooled and don't count against this limit. - * - * @return The maximum number of pooled connection allowed, or 0 for no maximum. - */ - public int getMaxConnections() - { - return maxConnections; - } - - /** - * Sets the maximum number of connections that the pool will allow. If a request - * comes in and this many connections are in use, the request will block until a - * connection is available. Note that connections for a user other than the - * default user will not be pooled and don't count against this limit. - * - * @param maxConnections The maximum number of pooled connection to allow, or - * 0 for no maximum. - * - * @throws java.lang.IllegalStateException - * The Maximum Connections cannot be changed after the DataSource has been - * used. - */ - public void setMaxConnections(int maxConnections) - { - if (initialized) - { - throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); - } - this.maxConnections = maxConnections; - } - - /** - * Gets the name of this DataSource. This uniquely identifies the DataSource. - * You cannot use more than one DataSource in the same VM with the same name. - */ - public String getDataSourceName() - { - return dataSourceName; - } - - /** - * Sets the name of this DataSource. This is required, and uniquely identifies - * the DataSource. You cannot create or use more than one DataSource in the - * same VM with the same name. - * - * @throws java.lang.IllegalStateException - * The Data Source Name cannot be changed after the DataSource has been - * used. - * @throws java.lang.IllegalArgumentException - * Another PoolingDataSource with the same dataSourceName already - * exists. - */ - public void setDataSourceName(String dataSourceName) - { - if (initialized) - { - throw new IllegalStateException("Cannot set Data Source properties after DataSource has been used"); - } - if (this.dataSourceName != null && dataSourceName != null && dataSourceName.equals(this.dataSourceName)) - { - return ; - } - synchronized (dataSources) - { - if (getDataSource(dataSourceName) != null) - { - throw new IllegalArgumentException("DataSource with name '" + dataSourceName + "' already exists!"); - } - if (this.dataSourceName != null) - { - dataSources.remove(this.dataSourceName); - } - this.dataSourceName = dataSourceName; - dataSources.put(dataSourceName, this); - } - } - - /** - * Initializes this DataSource. If the initialConnections is greater than zero, - * that number of connections will be created. After this method is called, - * the DataSource properties cannot be changed. If you do not call this - * explicitly, it will be called the first time you get a connection from the - * DataSource. - * @throws java.sql.SQLException - * Occurs when the initialConnections is greater than zero, but the - * DataSource is not able to create enough physical connections. - */ - public void initialize() throws SQLException - { - synchronized (lock ) - { - source = createConnectionPool(); - source.setDatabaseName(getDatabaseName()); - source.setPassword(getPassword()); - source.setPortNumber(getPortNumber()); - source.setServerName(getServerName()); - source.setUser(getUser()); - while (available.size() < initialConnections) - { - available.push(source.getPooledConnection()); - } - initialized = true; - } - } - - protected boolean isInitialized() { - return initialized; - } - - /** - * Creates the appropriate ConnectionPool to use for this DataSource. - */ - protected PGConnectionPoolDataSource createConnectionPool() { - return new PGConnectionPoolDataSource(); - } - - /** - * Gets a <b>non-pooled</b> connection, unless the user and password are the - * same as the default values for this connection pool. - * - * @return A pooled connection. - * @throws SQLException - * Occurs when no pooled connection is available, and a new physical - * connection cannot be created. - */ - public Connection getConnection(String user, String password) throws SQLException - { - // If this is for the default user/password, use a pooled connection - if (user == null || - (user.equals(getUser()) && ((password == null && getPassword() == null) || (password != null && password.equals(getPassword()))))) - { - return getConnection(); - } - // Otherwise, use a non-pooled connection - if (!initialized) - { - initialize(); - } - return super.getConnection(user, password); - } - - /** - * Gets a connection from the connection pool. - * - * @return A pooled connection. - * @throws SQLException - * Occurs when no pooled connection is available, and a new physical - * connection cannot be created. - */ - public Connection getConnection() throws SQLException - { - if (!initialized) - { - initialize(); - } - return getPooledConnection(); - } - - /** - * Closes this DataSource, and all the pooled connections, whether in use or not. - */ - public void close() - { - synchronized (lock ) - { - while (available.size() > 0) - { - PooledConnectionImpl pci = (PooledConnectionImpl)available.pop(); - try - { - pci.close(); - } - catch (SQLException e) - { - } - } - available = null; - while (used.size() > 0) - { - PooledConnectionImpl pci = (PooledConnectionImpl)used.pop(); - pci.removeConnectionEventListener(connectionEventListener); - try - { - pci.close(); - } - catch (SQLException e) - { - } - } - used = null; - } - removeStoredDataSource(); - } - - protected void removeStoredDataSource() { - synchronized (dataSources) - { - dataSources.remove(dataSourceName); - } - } - - /** - * Gets a connection from the pool. Will get an available one if - * present, or create a new one if under the max limit. Will - * block if all used and a new one would exceed the max. - */ - private Connection getPooledConnection() throws SQLException - { - PooledConnection pc = null; - synchronized (lock ) - { - if (available == null) - { - throw new PSQLException(GT.tr("DataSource has been closed."), - PSQLState.CONNECTION_DOES_NOT_EXIST); - } - while (true) - { - if (available.size() > 0) - { - pc = (PooledConnection)available.pop(); - used.push(pc); - break; - } - if (maxConnections == 0 || used.size() < maxConnections) - { - pc = source.getPooledConnection(); - used.push(pc); - break; - } - else - { - try - { - // Wake up every second at a minimum - lock.wait(1000L); - } - catch (InterruptedException e) - { - } - } - } - } - pc.addConnectionEventListener(connectionEventListener); - return pc.getConnection(); - } - - /** - * Notified when a pooled connection is closed, or a fatal error occurs - * on a pooled connection. This is the only way connections are marked - * as unused. - */ - private ConnectionEventListener connectionEventListener = new ConnectionEventListener() - { - public void connectionClosed(ConnectionEvent event) - { - ((PooledConnection)event.getSource()).removeConnectionEventListener(this); - synchronized (lock ) - { - if (available == null) - { - return ; // DataSource has been closed - } - boolean removed = used.remove(event.getSource()); - if (removed) - { - available.push(event.getSource()); - // There's now a new connection available - lock.notify(); - } - else - { - // a connection error occured - } - } - } - - /** - * This is only called for fatal errors, where the physical connection is - * useless afterward and should be removed from the pool. - */ - public void connectionErrorOccurred(ConnectionEvent event) - { - ((PooledConnection) event.getSource()).removeConnectionEventListener(this); - synchronized (lock ) - { - if (available == null) - { - return ; // DataSource has been closed - } - used.remove(event.getSource()); - // We're now at least 1 connection under the max - lock.notify(); - } - } - }; - - /** - * Adds custom properties for this DataSource to the properties defined in - * the superclass. - */ - public Reference getReference() throws NamingException - { - Reference ref = super.getReference(); - ref.add(new StringRefAddr("dataSourceName", dataSourceName)); - if (initialConnections > 0) - { - ref.add(new StringRefAddr("initialConnections", Integer.toString(initialConnections))); - } - if (maxConnections > 0) - { - ref.add(new StringRefAddr("maxConnections", Integer.toString(maxConnections))); - } - return ref; - } -} diff --git a/org/postgresql/ds/PGPoolingDataSource.java.in b/org/postgresql/ds/PGPoolingDataSource.java.in new file mode 100644 index 00000000..0fc5dd84 --- /dev/null +++ b/org/postgresql/ds/PGPoolingDataSource.java.in @@ -0,0 +1,52 @@ +/*------------------------------------------------------------------------- +* +* Copyright (c) 2004-2005, PostgreSQL Global Development Group +* +* IDENTIFICATION +* $PostgreSQL$ +* +*------------------------------------------------------------------------- +*/ +package org.postgresql.ds; + +import javax.sql.DataSource; + +/** + * DataSource which uses connection pooling. <font color="red">Don't use this if + * your server/middleware vendor provides a connection pooling implementation + * which interfaces with the PostgreSQL ConnectionPoolDataSource implementation!</font> + * This class is provided as a convenience, but the JDBC Driver is really not + * supposed to handle the connection pooling algorithm. Instead, the server or + * middleware product is supposed to handle the mechanics of connection pooling, + * and use the PostgreSQL implementation of ConnectionPoolDataSource to provide + * the connections to pool. + * + * <p>If you're sure you want to use this, then you must set the properties + * dataSourceName, databaseName, user, and password (if required for the user). + * The settings for serverName, portNumber, initialConnections, and + * maxConnections are optional. Note that <i>only connections + * for the default user will be pooled!</i> Connections for other users will + * be normal non-pooled connections, and will not count against the maximum pool + * size limit.</p> + * + * <p>If you put this DataSource in JNDI, and access it from different JVMs (or + * otherwise load this class from different ClassLoaders), you'll end up with one + * pool per ClassLoader or VM. This is another area where a server-specific + * implementation may provide advanced features, such as using a single pool + * across all VMs in a cluster.</p> + * + * <p>This implementation supports JDK 1.3 and higher.</p> + * + * @author Aaron Mulder (ammulder@chariotsolutions.com) + */ +public class PGPoolingDataSource + extends @POOLING_DS_CLASS@ + implements DataSource +{ + + protected void addDataSource(String dataSourceName) + { + dataSources.put(dataSourceName, this); + } + +} diff --git a/org/postgresql/ds/PGSimpleDataSource.java b/org/postgresql/ds/PGSimpleDataSource.java deleted file mode 100644 index 6c9cc9f9..00000000 --- a/org/postgresql/ds/PGSimpleDataSource.java +++ /dev/null @@ -1,47 +0,0 @@ -/*------------------------------------------------------------------------- -* -* Copyright (c) 2004-2005, PostgreSQL Global Development Group -* -* IDENTIFICATION -* $PostgreSQL: pgjdbc/org/postgresql/ds/PGSimpleDataSource.java,v 1.3 2004/11/09 08:46:49 jurka Exp $ -* -*------------------------------------------------------------------------- -*/ -package org.postgresql.ds; - -import javax.sql.DataSource; -import java.io.Serializable; -import java.io.ObjectOutputStream; -import java.io.ObjectInputStream; -import java.io.IOException; - -import org.postgresql.ds.common.*; - -/** - * Simple DataSource which does not perform connection pooling. In order to use - * the DataSource, you must set the property databaseName. The settings for - * serverName, portNumber, user, and password are optional. Note: these properties - * are declared in the superclass. - * - * @author Aaron Mulder (ammulder@chariotsolutions.com) - */ -public class PGSimpleDataSource extends BaseDataSource implements Serializable, DataSource -{ - /** - * Gets a description of this DataSource. - */ - public String getDescription() - { - return "Non-Pooling DataSource from " + org.postgresql.Driver.getVersion(); - } - - private void writeObject(ObjectOutputStream out) throws IOException - { - writeBaseObject(out); - } - - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException - { - readBaseObject(in); - } -} diff --git a/org/postgresql/ds/PGSimpleDataSource.java.in b/org/postgresql/ds/PGSimpleDataSource.java.in new file mode 100644 index 00000000..8c74eab3 --- /dev/null +++ b/org/postgresql/ds/PGSimpleDataSource.java.in @@ -0,0 +1,26 @@ +/*------------------------------------------------------------------------- +* +* Copyright (c) 2004-2005, PostgreSQL Global Development Group +* +* IDENTIFICATION +* $PostgreSQL$ +* +*------------------------------------------------------------------------- +*/ +package org.postgresql.ds; + +import javax.sql.DataSource; + +/** + * Simple DataSource which does not perform connection pooling. In order to use + * the DataSource, you must set the property databaseName. The settings for + * serverName, portNumber, user, and password are optional. Note: these properties + * are declared in the superclass. + * + * @author Aaron Mulder (ammulder@chariotsolutions.com) + */ +public class PGSimpleDataSource + extends @SIMPLE_DS_CLASS@ + implements DataSource +{ +} diff --git a/org/postgresql/ds/common/PooledConnectionImpl.java b/org/postgresql/ds/common/PooledConnectionImpl.java deleted file mode 100644 index d8a61159..00000000 --- a/org/postgresql/ds/common/PooledConnectionImpl.java +++ /dev/null @@ -1,483 +0,0 @@ -/*------------------------------------------------------------------------- -* -* Copyright (c) 2004-2005, PostgreSQL Global Development Group -* -* IDENTIFICATION -* $PostgreSQL: pgjdbc/org/postgresql/ds/common/PooledConnectionImpl.java,v 1.10 2005/01/17 10:59:04 jurka Exp $ -* -*------------------------------------------------------------------------- -*/ -package org.postgresql.ds.common; - -import javax.sql.*; -import java.sql.*; -import java.util.*; -import java.lang.reflect.*; -import org.postgresql.PGConnection; -import org.postgresql.util.GT; -import org.postgresql.util.PSQLException; -import org.postgresql.util.PSQLState; - -/** - * PostgreSQL implementation of the PooledConnection interface. This shouldn't - * be used directly, as the pooling client should just interact with the - * ConnectionPool instead. - * @see org.postgresql.ds.PGConnectionPoolDataSource - * - * @author Aaron Mulder (ammulder@chariotsolutions.com) - * @author Csaba Nagy (ncsaba@yahoo.com) - */ -public class PooledConnectionImpl implements PooledConnection -{ - private List listeners = new LinkedList(); - private Connection con; - private ConnectionHandler last; - private final boolean autoCommit; - private final boolean isXA; - - /** - * Creates a new PooledConnection representing the specified physical - * connection. - */ - public PooledConnectionImpl(Connection con, boolean autoCommit, boolean isXA) - { - this.con = con; - this.autoCommit = autoCommit; - this.isXA = isXA; - } - - public PooledConnectionImpl(Connection con, boolean autoCommit) - { - this(con, autoCommit, false); - } - - /** - * Adds a listener for close or fatal error events on the connection - * handed out to a client. - */ - public void addConnectionEventListener(ConnectionEventListener connectionEventListener) - { - listeners.add(connectionEventListener); - } - - /** - * Removes a listener for close or fatal error events on the connection - * handed out to a client. - */ - public void removeConnectionEventListener(ConnectionEventListener connectionEventListener) - { - listeners.remove(connectionEventListener); - } - - /** - * Closes the physical database connection represented by this - * PooledConnection. If any client has a connection based on - * this PooledConnection, it is forcibly closed as well. - */ - public void close() throws SQLException - { - if (last != null) - { - last.close(); - if (!con.getAutoCommit()) - { - try - { - con.rollback(); - } - catch (SQLException e) - { - } - } - } - try - { - con.close(); - } - finally - { - con = null; - } - } - - /** - * Gets a handle for a client to use. This is a wrapper around the - * physical connection, so the client can call close and it will just - * return the connection to the pool without really closing the - * pgysical connection. - * - * <p>According to the JDBC 2.0 Optional Package spec (6.2.3), only one - * client may have an active handle to the connection at a time, so if - * there is a previous handle active when this is called, the previous - * one is forcibly closed and its work rolled back.</p> - */ - public Connection getConnection() throws SQLException - { - if (con == null) - { - // Before throwing the exception, let's notify the registered listeners about the error - PSQLException sqlException = new PSQLException(GT.tr("This PooledConnection has already been closed."), - PSQLState.CONNECTION_DOES_NOT_EXIST); - fireConnectionFatalError(sqlException); - throw sqlException; - } - // If any error occures while opening a new connection, the listeners - // have to be notified. This gives a chance to connection pools to - // elliminate bad pooled connections. - try - { - // Only one connection can be open at a time from this PooledConnection. See JDBC 2.0 Optional Package spec section 6.2.3 - if (last != null) - { - last.close(); - if (!con.getAutoCommit()) - { - try - { - con.rollback(); - } - catch (SQLException e) - { - } - } - con.clearWarnings(); - } - con.setAutoCommit(autoCommit); - } - catch (SQLException sqlException) - { - fireConnectionFatalError(sqlException); - throw (SQLException)sqlException.fillInStackTrace(); - } - ConnectionHandler handler = new ConnectionHandler(con); - last = handler; - - Connection proxyCon = (Connection)Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Connection.class, PGConnection.class}, handler); - last.setProxy(proxyCon); - return proxyCon; - } - - /** - * Used to fire a connection closed event to all listeners. - */ - void fireConnectionClosed() - { - ConnectionEvent evt = null; - // Copy the listener list so the listener can remove itself during this method call - ConnectionEventListener[] local = (ConnectionEventListener[]) listeners.toArray(new ConnectionEventListener[listeners.size()]); - for (int i = 0; i < local.length; i++) - { - ConnectionEventListener listener = local[i]; - if (evt == null) - { - evt = new ConnectionEvent(this); - } - listener.connectionClosed(evt); - } - } - - /** - * Used to fire a connection error event to all listeners. - */ - void fireConnectionFatalError(SQLException e) - { - ConnectionEvent evt = null; - // Copy the listener list so the listener can remove itself during this method call - ConnectionEventListener[] local = (ConnectionEventListener[])listeners.toArray(new ConnectionEventListener[listeners.size()]); - for (int i = 0; i < local.length; i++) - { - ConnectionEventListener listener = local[i]; - if (evt == null) - { - evt = new ConnectionEvent(this, e); - } - listener.connectionErrorOccurred(evt); - } - } - - // Classes we consider fatal. - private static String[] fatalClasses = { - "08", // connection error - "53", // insufficient resources - - // nb: not just "57" as that includes query cancel which is nonfatal - "57P01", // admin shutdown - "57P02", // crash shutdown - "57P03", // cannot connect now - - "58", // system error (backend) - "60", // system error (driver) - "99", // unexpected error - "F0", // configuration file error (backend) - "XX", // internal error (backend) - }; - - private static boolean isFatalState(String state) { - if (state == null) // no info, assume fatal - return true; - if (state.length() < 2) // no class info, assume fatal - return true; - - for (int i = 0; i < fatalClasses.length; ++i) - if (state.startsWith(fatalClasses[i])) - return true; // fatal - - return false; - } - - /** - * Fires a connection error event, but only if we - * think the exception is fatal. - * - * @param e the SQLException to consider - */ - private void fireConnectionError(SQLException e) - { - if (!isFatalState(e.getSQLState())) - return; - - fireConnectionFatalError(e); - } - - /** - * Instead of declaring a class implementing Connection, which would have - * to be updated for every JDK rev, use a dynamic proxy to handle all - * calls through the Connection interface. This is the part that - * requires JDK 1.3 or higher, though JDK 1.2 could be supported with a - * 3rd-party proxy package. - */ - private class ConnectionHandler implements InvocationHandler - { - private Connection con; - private Connection proxy; // the Connection the client is currently using, which is a proxy - private boolean automatic = false; - - public ConnectionHandler(Connection con) - { - this.con = con; - } - - public Object invoke(Object proxy, Method method, Object[] args) - throws Throwable - { - // From Object - if (method.getDeclaringClass().getName().equals("java.lang.Object")) - { - if (method.getName().equals("toString")) - { - return "Pooled connection wrapping physical connection " + con; - } - if (method.getName().equals("hashCode")) - { - return new Integer(con.hashCode()); - } - if (method.getName().equals("equals")) - { - if (args[0] == null) - { - return Boolean.FALSE; - } - try - { - return Proxy.isProxyClass(args[0].getClass()) && ((ConnectionHandler) Proxy.getInvocationHandler(args[0])).con == con ? Boolean.TRUE : Boolean.FALSE; - } - catch (ClassCastException e) - { - return Boolean.FALSE; - } - } - try - { - return method.invoke(con, args); - } - catch (InvocationTargetException e) - { - throw e.getTargetException(); - } - } - // All the rest is from the Connection or PGConnection interface - if (method.getName().equals("isClosed")) - { - return con == null ? Boolean.TRUE : Boolean.FALSE; - } - if (con == null && !method.getName().equals("close")) - { - throw new PSQLException(automatic ? GT.tr("Connection has been closed automatically because a new connection was opened for the same PooledConnection or the PooledConnection has been closed.") : GT.tr("Connection has been closed."), - PSQLState.CONNECTION_DOES_NOT_EXIST); - } - if (method.getName().equals("close")) - { - // we are already closed and a double close - // is not an error. - if (con == null) - return null; - - SQLException ex = null; - if (!isXA && !con.getAutoCommit()) - { - try - { - con.rollback(); - } - catch (SQLException e) - { - ex = e; - } - } - con.clearWarnings(); - con = null; - proxy = null; - last = null; - fireConnectionClosed(); - if (ex != null) - { - throw ex; - } - return null; - } - - // From here on in, we invoke via reflection, catch exceptions, - // and check if they're fatal before rethrowing. - - try { - if (method.getName().equals("createStatement")) - { - Statement st = (Statement)method.invoke(con, args); - return Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Statement.class, org.postgresql.PGStatement.class}, new StatementHandler(this, st)); - } - else if (method.getName().equals("prepareCall")) - { - Statement st = (Statement)method.invoke(con, args); - return Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{CallableStatement.class, org.postgresql.PGStatement.class}, new StatementHandler(this, st)); - } - else if (method.getName().equals("prepareStatement")) - { - Statement st = (Statement)method.invoke(con, args); - return Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{PreparedStatement.class, org.postgresql.PGStatement.class}, new StatementHandler(this, st)); - } - else - { - return method.invoke(con, args); - } - } catch (InvocationTargetException e) { - Throwable te = e.getTargetException(); - if (te instanceof SQLException) - fireConnectionError((SQLException)te); // Tell listeners about exception if it's fatal - throw te; - } - } - - Connection getProxy() { - return proxy; - } - - void setProxy(Connection proxy) { - this.proxy = proxy; - } - - public void close() - { - if (con != null) - { - automatic = true; - } - con = null; - proxy = null; - // No close event fired here: see JDBC 2.0 Optional Package spec section 6.3 - } - - public boolean isClosed() { - return con == null; - } - } - - /** - * Instead of declaring classes implementing Statement, PreparedStatement, - * and CallableStatement, which would have to be updated for every JDK rev, - * use a dynamic proxy to handle all calls through the Statement - * interfaces. This is the part that requires JDK 1.3 or higher, though - * JDK 1.2 could be supported with a 3rd-party proxy package. - * - * The StatementHandler is required in order to return the proper - * Connection proxy for the getConnection method. - */ - private class StatementHandler implements InvocationHandler { - private PooledConnectionImpl.ConnectionHandler con; - private Statement st; - - public StatementHandler(PooledConnectionImpl.ConnectionHandler con, Statement st) { - this.con = con; - this.st = st; - } - public Object invoke(Object proxy, Method method, Object[] args) - throws Throwable - { - // From Object - if (method.getDeclaringClass().getName().equals("java.lang.Object")) - { - if (method.getName().equals("toString")) - { - return "Pooled statement wrapping physical statement " + st; - } - if (method.getName().equals("hashCode")) - { - return new Integer(st.hashCode()); - } - if (method.getName().equals("equals")) - { - if (args[0] == null) - { - return Boolean.FALSE; - } - try - { - return Proxy.isProxyClass(args[0].getClass()) && ((StatementHandler) Proxy.getInvocationHandler(args[0])).st == st ? Boolean.TRUE : Boolean.FALSE; - } - catch (ClassCastException e) - { - return Boolean.FALSE; - } - } - return method.invoke(st, args); - } - // All the rest is from the Statement interface - if (method.getName().equals("close")) - { - // closing an already closed object is a no-op - if (st == null || con.isClosed()) - return null; - - try - { - st.close(); - } - finally - { - con = null; - st = null; - } - return null; - } - if (st == null || con.isClosed()) - { - throw new PSQLException(GT.tr("Statement has been closed."), - PSQLState.OBJECT_NOT_IN_STATE); - } - - if (method.getName().equals("getConnection")) - { - return con.getProxy(); // the proxied connection, not a physical connection - } - - try - { - return method.invoke(st, args); - } catch (InvocationTargetException e) { - Throwable te = e.getTargetException(); - if (te instanceof SQLException) - fireConnectionError((SQLException)te); // Tell listeners about exception if it's fatal - throw te; - } - } - } -} diff --git a/org/postgresql/ds/jdbc4/AbstractJdbc4PooledConnection.java b/org/postgresql/ds/jdbc4/AbstractJdbc4PooledConnection.java new file mode 100644 index 00000000..4b2aa739 --- /dev/null +++ b/org/postgresql/ds/jdbc4/AbstractJdbc4PooledConnection.java @@ -0,0 +1,32 @@ +/*------------------------------------------------------------------------- +* +* Copyright (c) 2004-2005, PostgreSQL Global Development Group +* +* IDENTIFICATION +* $PostgreSQL$ +* +*------------------------------------------------------------------------- +*/ +package org.postgresql.ds.jdbc4; + +import java.sql.Connection; +import javax.sql.StatementEventListener; +import org.postgresql.ds.jdbc23.AbstractJdbc23PooledConnection; + +public abstract class AbstractJdbc4PooledConnection extends AbstractJdbc23PooledConnection +{ + + public AbstractJdbc4PooledConnection(Connection con, boolean autoCommit, boolean isXA) + { + super(con, autoCommit, isXA); + } + + public void removeStatementEventListener(StatementEventListener listener) + { + } + + public void addStatementEventListener(StatementEventListener listener) + { + } + +} diff --git a/org/postgresql/ds/jdbc4/AbstractJdbc4PoolingDataSource.java b/org/postgresql/ds/jdbc4/AbstractJdbc4PoolingDataSource.java new file mode 100644 index 00000000..2a839203 --- /dev/null +++ b/org/postgresql/ds/jdbc4/AbstractJdbc4PoolingDataSource.java @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- +* +* Copyright (c) 2004-2005, PostgreSQL Global Development Group +* +* IDENTIFICATION +* $PostgreSQL$ +* +*------------------------------------------------------------------------- +*/ +package org.postgresql.ds.jdbc4; + +import java.sql.SQLException; + +import org.postgresql.ds.jdbc23.AbstractJdbc23PoolingDataSource; + +public abstract class AbstractJdbc4PoolingDataSource extends AbstractJdbc23PoolingDataSource +{ + + public boolean isWrapperFor(Class<?> iface) throws SQLException + { + throw org.postgresql.Driver.notImplemented(this.getClass(), "isWrapperFor(Class<?>)"); + } + + public <T> T unwrap(Class<T> iface) throws SQLException + { + throw org.postgresql.Driver.notImplemented(this.getClass(), "unwrap(Class<T>)"); + } + +} diff --git a/org/postgresql/ds/jdbc4/AbstractJdbc4SimpleDataSource.java b/org/postgresql/ds/jdbc4/AbstractJdbc4SimpleDataSource.java new file mode 100644 index 00000000..18135f8d --- /dev/null +++ b/org/postgresql/ds/jdbc4/AbstractJdbc4SimpleDataSource.java @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- +* +* Copyright (c) 2004-2005, PostgreSQL Global Development Group +* +* IDENTIFICATION +* $PostgreSQL$ +* +*------------------------------------------------------------------------- +*/ +package org.postgresql.ds.jdbc4; + +import java.sql.SQLException; + +import org.postgresql.ds.jdbc23.AbstractJdbc23SimpleDataSource; + +public class AbstractJdbc4SimpleDataSource extends AbstractJdbc23SimpleDataSource +{ + public boolean isWrapperFor(Class<?> iface) throws SQLException + { + throw org.postgresql.Driver.notImplemented(this.getClass(), "isWrapperFor(Class<?>)"); + } + + public <T> T unwrap(Class<T> iface) throws SQLException + { + throw org.postgresql.Driver.notImplemented(this.getClass(), "unwrap(Class<T>)"); + } + +} diff --git a/org/postgresql/xa/PGXAConnection.java b/org/postgresql/xa/PGXAConnection.java index 773fa016..bb20a0e2 100644 --- a/org/postgresql/xa/PGXAConnection.java +++ b/org/postgresql/xa/PGXAConnection.java @@ -1,7 +1,7 @@ package org.postgresql.xa; import org.postgresql.Driver; -import org.postgresql.ds.common.PooledConnectionImpl; +import org.postgresql.ds.PGPooledConnection; import org.postgresql.core.BaseConnection; import org.postgresql.core.Logger; @@ -27,7 +27,7 @@ import javax.transaction.xa.XAException; * * @author Heikki Linnakangas (heikki.linnakangas@iki.fi) */ -public class PGXAConnection extends PooledConnectionImpl implements XAConnection, XAResource +public class PGXAConnection extends PGPooledConnection implements XAConnection, XAResource { /** * Underlying physical database connection. It's used for issuing PREPARE TRANSACTION/ [parent: 743041f45d5b]