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.
- */ - 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; - } - } - } - } --- 0 ---- diff -rcN -xCVS clean/org/postgresql/ds/jdbc23/AbstractJdbc23PooledConnection.java j4/org/postgresql/ds/jdbc23/AbstractJdbc23PooledConnection.java *** clean/org/postgresql/ds/jdbc23/AbstractJdbc23PooledConnection.java 1969-12-31 17:00:00.000000000 -0700 --- j4/org/postgresql/ds/jdbc23/AbstractJdbc23PooledConnection.java 2006-11-03 01:46:14.000000000 -0700 *************** *** 0 **** --- 1,480 ---- + /*------------------------------------------------------------------------- + * + * Copyright (c) 2004-2005, PostgreSQL Global Development Group + * + * IDENTIFICATION + * $PostgreSQL$ + * + *------------------------------------------------------------------------- + */ + package org.postgresql.ds.jdbc23; + + 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 abstract class AbstractJdbc23PooledConnection + { + 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 AbstractJdbc23PooledConnection(Connection con, boolean autoCommit, boolean isXA) + { + this.con = con; + this.autoCommit = autoCommit; + this.isXA = isXA; + } + + /** + * 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. + * + *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.
+ */ + 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 = createConnectionEvent(null); + } + 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 = createConnectionEvent(e); + } + listener.connectionErrorOccurred(evt); + } + } + + protected abstract ConnectionEvent createConnectionEvent(SQLException e); + + // 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 AbstractJdbc23PooledConnection.ConnectionHandler con; + private Statement st; + + public StatementHandler(AbstractJdbc23PooledConnection.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 -rcN -xCVS clean/org/postgresql/ds/jdbc23/AbstractJdbc23PoolingDataSource.java j4/org/postgresql/ds/jdbc23/AbstractJdbc23PoolingDataSource.java *** clean/org/postgresql/ds/jdbc23/AbstractJdbc23PoolingDataSource.java 1969-12-31 17:00:00.000000000 -0700 --- j4/org/postgresql/ds/jdbc23/AbstractJdbc23PoolingDataSource.java 2006-11-03 02:03:01.000000000 -0700 *************** *** 0 **** --- 1,515 ---- + /*------------------------------------------------------------------------- + * + * Copyright (c) 2004-2005, PostgreSQL Global Development Group + * + * IDENTIFICATION + * $PostgreSQL$ + * + *------------------------------------------------------------------------- + */ + package org.postgresql.ds.jdbc23; + + 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.*; + import org.postgresql.ds.common.*; + + /** + * DataSource which uses connection pooling. Don't use this if + * your server/middleware vendor provides a connection pooling implementation + * which interfaces with the PostgreSQL ConnectionPoolDataSource implementation! + * 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. + * + *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 only connections + * for the default user will be pooled! Connections for other users will + * be normal non-pooled connections, and will not count against the maximum pool + * size limit.
+ * + *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.
+ * + *This implementation supports JDK 1.3 and higher.
+ * + * @author Aaron Mulder (ammulder@chariotsolutions.com) + */ + public abstract class AbstractJdbc23PoolingDataSource extends BaseDataSource + { + protected 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; + addDataSource(dataSourceName); + } + } + + /** + * 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 non-pooled 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) + { + PGPooledConnection pci = (PGPooledConnection)available.pop(); + try + { + pci.close(); + } + catch (SQLException e) + { + } + } + available = null; + while (used.size() > 0) + { + PGPooledConnection pci = (PGPooledConnection)used.pop(); + pci.removeConnectionEventListener(connectionEventListener); + try + { + pci.close(); + } + catch (SQLException e) + { + } + } + used = null; + } + removeStoredDataSource(); + } + + protected void removeStoredDataSource() { + synchronized (dataSources) + { + dataSources.remove(dataSourceName); + } + } + + protected abstract void addDataSource(String 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 -rcN -xCVS clean/org/postgresql/ds/jdbc23/AbstractJdbc23SimpleDataSource.java j4/org/postgresql/ds/jdbc23/AbstractJdbc23SimpleDataSource.java *** clean/org/postgresql/ds/jdbc23/AbstractJdbc23SimpleDataSource.java 1969-12-31 17:00:00.000000000 -0700 --- j4/org/postgresql/ds/jdbc23/AbstractJdbc23SimpleDataSource.java 2006-11-03 00:54:48.000000000 -0700 *************** *** 0 **** --- 1,47 ---- + /*------------------------------------------------------------------------- + * + * Copyright (c) 2004-2005, PostgreSQL Global Development Group + * + * IDENTIFICATION + * $PostgreSQL$ + * + *------------------------------------------------------------------------- + */ + package org.postgresql.ds.jdbc23; + + 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 AbstractJdbc23SimpleDataSource extends BaseDataSource implements Serializable + { + /** + * 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 -rcN -xCVS clean/org/postgresql/ds/jdbc4/AbstractJdbc4PooledConnection.java j4/org/postgresql/ds/jdbc4/AbstractJdbc4PooledConnection.java *** clean/org/postgresql/ds/jdbc4/AbstractJdbc4PooledConnection.java 1969-12-31 17:00:00.000000000 -0700 --- j4/org/postgresql/ds/jdbc4/AbstractJdbc4PooledConnection.java 2006-11-03 02:18:32.000000000 -0700 *************** *** 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 -rcN -xCVS clean/org/postgresql/ds/jdbc4/AbstractJdbc4PoolingDataSource.java j4/org/postgresql/ds/jdbc4/AbstractJdbc4PoolingDataSource.java *** clean/org/postgresql/ds/jdbc4/AbstractJdbc4PoolingDataSource.java 1969-12-31 17:00:00.000000000 -0700 --- j4/org/postgresql/ds/jdbc4/AbstractJdbc4PoolingDataSource.java 2006-11-03 02:21:29.000000000 -0700 *************** *** 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>)"); + } + + publicIf 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 only connections - * for the default user will be pooled! Connections for other users will - * be normal non-pooled connections, and will not count against the maximum pool - * size limit.
- * - *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.
- * - *This implementation supports JDK 1.3 and higher.
- * - * @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 non-pooled 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; - } - } --- 0 ---- diff -rcN -xCVS clean/org/postgresql/ds/PGPoolingDataSource.java.in j4/org/postgresql/ds/PGPoolingDataSource.java.in *** clean/org/postgresql/ds/PGPoolingDataSource.java.in 1969-12-31 17:00:00.000000000 -0700 --- j4/org/postgresql/ds/PGPoolingDataSource.java.in 2006-11-03 02:02:06.000000000 -0700 *************** *** 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. Don't use this if + * your server/middleware vendor provides a connection pooling implementation + * which interfaces with the PostgreSQL ConnectionPoolDataSource implementation! + * 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. + * + *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 only connections + * for the default user will be pooled! Connections for other users will + * be normal non-pooled connections, and will not count against the maximum pool + * size limit.
+ * + *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.
+ * + *This implementation supports JDK 1.3 and higher.
+ * + * @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 -rcN -xCVS clean/org/postgresql/ds/PGSimpleDataSource.java j4/org/postgresql/ds/PGSimpleDataSource.java *** clean/org/postgresql/ds/PGSimpleDataSource.java 2005-01-11 01:25:44.000000000 -0700 --- j4/org/postgresql/ds/PGSimpleDataSource.java 1969-12-31 17:00:00.000000000 -0700 *************** *** 1,47 **** - /*------------------------------------------------------------------------- - * - * Copyright (c) 2004-2005, PostgreSQL Global Development Group - * - * IDENTIFICATION - * $PostgreSQL: pgjdbc/org/postgresql/ds/PGSimpleDataSource.java,v 1.4 2005/01/11 08:25:44 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); - } - } --- 0 ---- diff -rcN -xCVS clean/org/postgresql/ds/PGSimpleDataSource.java.in j4/org/postgresql/ds/PGSimpleDataSource.java.in *** clean/org/postgresql/ds/PGSimpleDataSource.java.in 1969-12-31 17:00:00.000000000 -0700 --- j4/org/postgresql/ds/PGSimpleDataSource.java.in 2006-11-03 01:22:28.000000000 -0700 *************** *** 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 -rcN -xCVS clean/org/postgresql/xa/PGXAConnection.java j4/org/postgresql/xa/PGXAConnection.java *** clean/org/postgresql/xa/PGXAConnection.java 2006-04-26 12:19:27.000000000 -0600 --- j4/org/postgresql/xa/PGXAConnection.java 2006-11-03 01:28:40.000000000 -0700 *************** *** 1,7 **** package org.postgresql.xa; import org.postgresql.Driver; ! import org.postgresql.ds.common.PooledConnectionImpl; import org.postgresql.core.BaseConnection; import org.postgresql.core.Logger; --- 1,7 ---- package org.postgresql.xa; import org.postgresql.Driver; ! import org.postgresql.ds.PGPooledConnection; import org.postgresql.core.BaseConnection; import org.postgresql.core.Logger; *************** *** 27,33 **** * * @author Heikki Linnakangas (heikki.linnakangas@iki.fi) */ ! public class PGXAConnection extends PooledConnectionImpl implements XAConnection, XAResource { /** * Underlying physical database connection. It's used for issuing PREPARE TRANSACTION/ --- 27,33 ---- * * @author Heikki Linnakangas (heikki.linnakangas@iki.fi) */ ! public class PGXAConnection extends PGPooledConnection implements XAConnection, XAResource { /** * Underlying physical database connection. It's used for issuing PREPARE TRANSACTION/