From 92a3aba2339672e420808a05c5e78e7874106c44 Mon Sep 17 00:00:00 2001 From: fhanik Date: Fri, 20 Nov 2009 21:39:36 +0000 Subject: [PATCH] Add in DataSource supprot Add in XA support git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@882723 13f79535-47bb-0310-9956-ffa450edef68 --- modules/jdbc-pool/.classpath | 1 + modules/jdbc-pool/doc/jdbc-pool.xml | 11 ++++ .../apache/tomcat/jdbc/pool/ConnectionPool.java | 2 +- .../apache/tomcat/jdbc/pool/DataSourceFactory.java | 18 +++++- .../apache/tomcat/jdbc/pool/DataSourceProxy.java | 29 ++++++++++ .../apache/tomcat/jdbc/pool/PoolConfiguration.java | 34 +++++++++++ .../apache/tomcat/jdbc/pool/PoolProperties.java | 34 ++++++++++- .../apache/tomcat/jdbc/pool/PooledConnection.java | 65 ++++++++++++++++++---- .../apache/tomcat/jdbc/pool/ProxyConnection.java | 13 +++++ .../tomcat/jdbc/pool/jmx/ConnectionPool.java | 29 ++++++++++ 10 files changed, 223 insertions(+), 13 deletions(-) diff --git a/modules/jdbc-pool/.classpath b/modules/jdbc-pool/.classpath index ef54a92d6..575cb2bfb 100644 --- a/modules/jdbc-pool/.classpath +++ b/modules/jdbc-pool/.classpath @@ -7,5 +7,6 @@ + diff --git a/modules/jdbc-pool/doc/jdbc-pool.xml b/modules/jdbc-pool/doc/jdbc-pool.xml index 83e99b70c..325d8f3e1 100644 --- a/modules/jdbc-pool/doc/jdbc-pool.xml +++ b/modules/jdbc-pool/doc/jdbc-pool.xml @@ -88,6 +88,9 @@
  • Get JMX notifications and log entries when connections are suspected for being abandoned. This is similar to the removeAbandonedTimeout but it doesn't take any action, only reports the information. This is achieved using the suspectTimeout attribute.
  • +
  • Connections can be retrieved from a java.sql.Driver or a javax.sql.DataSource + This is achieved using the dataSource and dataSourceJNDI attributes.
  • +
  • XA connection support
  • @@ -401,6 +404,14 @@ logged and a JMX notification gets sent once.

    + +

    (javax.sql.DataSource) +

    +
    + +

    (String) +

    +
    diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java index f44c0a5e9..37d0976bf 100644 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java @@ -277,7 +277,7 @@ public class ConnectionPool { } try { - getProxyConstructor(con.getConnection() instanceof XAConnection); + getProxyConstructor(con.getXAConnection() != null); //create the proxy //TODO possible optimization, keep track if this connection was returned properly, and don't generate a new facade Connection connection = (Connection)proxyClassConstructor.newInstance(new Object[] { handler }); diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java index fbfc005a1..60066d3c8 100644 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceFactory.java @@ -104,6 +104,10 @@ public class DataSourceFactory implements ObjectFactory { protected static final String PROP_USE_EQUALS = "useEquals"; protected static final String PROP_USE_CON_LOCK = "useLock"; + protected static final String PROP_DATASOURCE= "dataSource"; + protected static final String PROP_DATASOURCE_JNDI = "dataSourceJNDI"; + + public static final int UNKNOWN_TRANSACTIONISOLATION = -1; public static final String OBJECT_NAME = "object_name"; @@ -147,7 +151,9 @@ public class DataSourceFactory implements ObjectFactory { OBJECT_NAME, PROP_ABANDONWHENPERCENTAGEFULL, PROP_MAXAGE, - PROP_USE_CON_LOCK + PROP_USE_CON_LOCK, + PROP_DATASOURCE, + PROP_DATASOURCE_JNDI, }; // -------------------------------------------------- ObjectFactory Methods @@ -425,6 +431,16 @@ public class DataSourceFactory implements ObjectFactory { poolProperties.setUseLock(Boolean.parseBoolean(value)); } + value = properties.getProperty(PROP_DATASOURCE); + if (value != null) { + //this should never happen + log.error("Can't set dataSource property as a string, this must be a javax.sql.DataSource object."); + } + + value = properties.getProperty(PROP_DATASOURCE_JNDI); + if (value != null) { + poolProperties.setDataSourceJNDI(value); + } return poolProperties; } diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java index 1db507d29..91f6b0d87 100644 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java @@ -1011,4 +1011,33 @@ public class DataSourceProxy implements PoolConfiguration { getPoolProperties().setName(name); } + /** + * {@inheritDoc} + */ + public void setDataSource(javax.sql.DataSource ds) { + getPoolProperties().setDataSource(ds); + } + + /** + * {@inheritDoc} + */ + public javax.sql.DataSource getDataSource() { + return getPoolProperties().getDataSource(); + } + + + /** + * {@inheritDoc} + */ + public void setDataSourceJNDI(String jndiDS) { + getPoolProperties().setDataSourceJNDI(jndiDS); + } + + /** + * {@inheritDoc} + */ + public String getDataSourceJNDI() { + return getPoolProperties().getDataSourceJNDI(); + } + } diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java index d325323f0..0368a6cb7 100644 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolConfiguration.java @@ -717,5 +717,39 @@ public interface PoolConfiguration { */ public int getSuspectTimeout(); + /** + * Injects a datasource that will be used to retrieve/create connections. + * If a data source is set, the {@link PoolConfiguration#getUrl()} and {@link PoolConfiguration#getDriverClassName()} methods are ignored + * and not used by the pool. If the {@link PoolConfiguration#getUsername()} and {@link PoolConfiguration#getPassword()} + * values are set, the method {@link javax.sql.DataSource#getConnection(String, String)} method will be called instead of the + * {@link javax.sql.DataSource#getConnection()} method. + * If the data source implements {@link javax.sql.XADataSource} the methods + * {@link javax.sql.XADataSource#getXAConnection()} and {@link javax.sql.XADataSource#getXAConnection(String,String)} + * will be invoked. + * @param ds the {@link javax.sql.DataSource} to be used for creating connections to be pooled. + */ + public void setDataSource(javax.sql.DataSource ds); + + /** + * Returns a datasource, if one exists that is being used to create connections. + * This method will return null if the pool is using a {@link java.sql.Driver} + * @return the {@link javax.sql.DataSource} to be used for creating connections to be pooled or null if a Driver is used. + */ + public javax.sql.DataSource getDataSource(); + + /** + * Configure the connection pool to use a DataSource according to {@link PoolConfiguration#setDataSource(javax.sql.DataSource)} + * But instead of injecting the object, specify the JNDI location. + * After a successful JNDI look, the {@link PoolConfiguration#getDataSource()} will not return null. + * @param jndiDS -the JNDI string @TODO specify the rules here. + */ + public void setDataSourceJNDI(String jndiDS); + + /** + * Returns the JNDI string configured for data source usage. + * @return + */ + public String getDataSourceJNDI(); + } \ No newline at end of file diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java index 62b31c556..3b6c86bec 100644 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PoolProperties.java @@ -73,8 +73,10 @@ public class PoolProperties implements PoolConfiguration { protected int abandonWhenPercentageFull = 0; protected long maxAge = 0; protected boolean useLock = false; - private InterceptorDefinition[] interceptors = null; + protected InterceptorDefinition[] interceptors = null; protected int suspectTimeout = 0; + protected javax.sql.DataSource dataSource = null; + protected String dataSourceJNDI = null; /** @@ -870,6 +872,36 @@ public class PoolProperties implements PoolConfiguration { this.useLock = useLock; } + + /** + * {@inheritDoc} + */ + public void setDataSource(javax.sql.DataSource ds) { + this.dataSource = ds; + } + + /** + * {@inheritDoc} + */ + public javax.sql.DataSource getDataSource() { + return dataSource; + } + + + /** + * {@inheritDoc} + */ + public void setDataSourceJNDI(String jndiDS) { + this.dataSourceJNDI = jndiDS; + } + + /** + * {@inheritDoc} + */ + public String getDataSourceJNDI() { + return this.dataSourceJNDI; + } + public static Properties getProperties(String propText, Properties props) { if (props==null) props = new Properties(); diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java index eff788dcd..c548a4809 100644 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/PooledConnection.java @@ -69,6 +69,11 @@ public class PooledConnection { * The underlying database connection */ private volatile java.sql.Connection connection; + + /** + * If using a XAConnection underneath. + */ + private volatile javax.sql.XAConnection xaConnection; /** * When we track abandon traces, this string holds the thread dump */ @@ -142,6 +147,47 @@ public class PooledConnection { log.debug("Unable to disconnect previous connection.", x); } //catch } //end if + if (poolProperties.getDataSource()==null && poolProperties.getDataSourceJNDI()!=null) { + //TODO lookup JNDI name + } + + if (poolProperties.getDataSource()!=null) { + connectUsingDataSource(); + } else { + connectUsingDriver(); + } + + //set up the default state, unless we expect the interceptor to do it + if (poolProperties.getJdbcInterceptors()==null || poolProperties.getJdbcInterceptors().indexOf(ConnectionState.class.getName())<0) { + if (poolProperties.getDefaultReadOnly()!=null) connection.setReadOnly(poolProperties.getDefaultReadOnly().booleanValue()); + if (poolProperties.getDefaultAutoCommit()!=null) connection.setAutoCommit(poolProperties.getDefaultAutoCommit().booleanValue()); + if (poolProperties.getDefaultCatalog()!=null) connection.setCatalog(poolProperties.getDefaultCatalog()); + if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) connection.setTransactionIsolation(poolProperties.getDefaultTransactionIsolation()); + } + this.discarded = false; + this.lastConnected = System.currentTimeMillis(); + } + + protected void connectUsingDataSource() throws SQLException { + if (poolProperties.getDataSource() instanceof javax.sql.XADataSource) { + javax.sql.XADataSource xds = (javax.sql.XADataSource)poolProperties.getDataSource(); + if (poolProperties.getUsername()!=null && poolProperties.getPassword()!=null) { + xaConnection = xds.getXAConnection(poolProperties.getUsername(), poolProperties.getPassword()); + connection = xaConnection.getConnection(); + } else { + xaConnection = xds.getXAConnection(); + connection = xaConnection.getConnection(); + } + } else { + javax.sql.DataSource ds = poolProperties.getDataSource(); + if (poolProperties.getUsername()!=null && poolProperties.getPassword()!=null) { + connection = ds.getConnection(poolProperties.getUsername(), poolProperties.getPassword()); + } else { + connection = ds.getConnection(); + } + } + } + protected void connectUsingDriver() throws SQLException { java.sql.Driver driver = null; try { driver = (java.sql.Driver) Class.forName(poolProperties.getDriverClassName(), @@ -180,16 +226,6 @@ public class PooledConnection { if (connection==null) { throw new SQLException("Driver:"+driver+" returned null for URL:"+driverURL); } - - //set up the default state, unless we expect the interceptor to do it - if (poolProperties.getJdbcInterceptors()==null || poolProperties.getJdbcInterceptors().indexOf(ConnectionState.class.getName())<0) { - if (poolProperties.getDefaultReadOnly()!=null) connection.setReadOnly(poolProperties.getDefaultReadOnly().booleanValue()); - if (poolProperties.getDefaultAutoCommit()!=null) connection.setAutoCommit(poolProperties.getDefaultAutoCommit().booleanValue()); - if (poolProperties.getDefaultCatalog()!=null) connection.setCatalog(poolProperties.getDefaultCatalog()); - if (poolProperties.getDefaultTransactionIsolation()!=DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION) connection.setTransactionIsolation(poolProperties.getDefaultTransactionIsolation()); - } - this.discarded = false; - this.lastConnected = System.currentTimeMillis(); } /** @@ -229,6 +265,7 @@ public class PooledConnection { } } connection = null; + xaConnection = null; lastConnected = -1; if (finalize) parent.finalize(this); } @@ -502,6 +539,14 @@ public class PooledConnection { return this.connection; } + /** + * Returns the underlying XA connection + * @return the underlying XA connection as it was returned from the Datasource + */ + public javax.sql.XAConnection getXAConnection() { + return this.xaConnection; + } + /** * Returns the timestamp of when the connection was last connected to the database. diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java index 6d8ef5b1f..503b7d941 100644 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ProxyConnection.java @@ -19,6 +19,8 @@ package org.apache.tomcat.jdbc.pool; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.SQLException; + +import javax.sql.XAConnection; /** * A ProxyConnection object is the bottom most interceptor that wraps an object of type * {@link PooledConnection}. The ProxyConnection intercepts three methods: @@ -95,6 +97,17 @@ public class ProxyConnection extends JdbcInterceptor { return this.toString(); } else if (compare(GETCONNECTION_VAL,method) && connection!=null) { return connection.getConnection(); + } else if (method.getClass().equals(XAConnection.class)) { + try { + return method.invoke(connection.getXAConnection(),args); + }catch (Throwable t) { + if (t instanceof InvocationTargetException) { + InvocationTargetException it = (InvocationTargetException)t; + throw it.getCause()!=null?it.getCause():it; + } else { + throw t; + } + } } if (isClosed()) throw new SQLException("Connection has already been closed."); if (compare(UNWRAP_VAL,method)) { diff --git a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java index d53e491f9..fcb4812a1 100644 --- a/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java +++ b/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java @@ -570,5 +570,34 @@ public class ConnectionPool extends NotificationBroadcasterSupport implements Co public void setSuspectTimeout(int seconds) { //no op } + + /** + * {@inheritDoc} + */ + public void setDataSource(javax.sql.DataSource ds) { + getPoolProperties().setDataSource(ds); + } + + /** + * {@inheritDoc} + */ + public javax.sql.DataSource getDataSource() { + return getPoolProperties().getDataSource(); + } + + + /** + * {@inheritDoc} + */ + public void setDataSourceJNDI(String jndiDS) { + //noop + } + + /** + * {@inheritDoc} + */ + public String getDataSourceJNDI() { + return getPoolProperties().getDataSourceJNDI(); + } } -- 2.11.0