/*
 * XAPool: Open Source XA JDBC Pool
 * Copyright (C) 2003 Objectweb.org
 * Initial Developer: Lutris Technologies Inc.
 * Contact: xapool-public@lists.debian-sf.objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 */
package org.enhydra.jdbc.pool;

import java.sql.SQLException;
import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.sql.ConnectionEvent;
import javax.sql.XAConnection;
import javax.sql.XADataSource;
import javax.transaction.TransactionManager;
import javax.transaction.Transaction;
import javax.transaction.SystemException;
import javax.transaction.xa.XAResource;
import org.enhydra.jdbc.standard.StandardXADataSource;
import org.enhydra.jdbc.standard.StandardXAConnection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.sql.Connection;
import java.sql.Statement;
import javax.sql.PooledConnection;
import javax.transaction.Status;

StandardXAPoolDataSource class allows to make some operations on XAConnection. It implements PoolHelper for the 3 methods :

create : create an XAConnection

create(user,password) : create a PooledConnection with an other user/password

testThisObject : check if the object is still valid

checkThisObject : check if the object is closed

expire : kill the object

/** * StandardXAPoolDataSource class allows to make some operations on * XAConnection. It implements PoolHelper for the 3 methods :<p> * create : create an XAConnection<p> * create(user,password) : create a PooledConnection with an other user/password<p> * testThisObject : check if the object is still valid<p> * checkThisObject : check if the object is closed<p> * expire : kill the object<p> */
public class StandardXAPoolDataSource extends StandardPoolDataSource { public XADataSource xads; // object to build XAConnection public TransactionManager transactionManager; // the current Transaction Manager public Log glog = LogFactory.getLog("org.enhydra.jdbc.xapool");
Constructor
/** * Constructor */
public StandardXAPoolDataSource() { super(); }
Constructor
/** * Constructor */
public StandardXAPoolDataSource(int initSize) { super(initSize); }
Constructor
/** * Constructor */
public StandardXAPoolDataSource(StandardXADataSource ds) { super(ds); setDataSource(ds); }
Constructor
/** * Constructor */
public StandardXAPoolDataSource(StandardXADataSource ds, int initSize) { super(ds, initSize); setDataSource(ds); } public void setTransactionManager(TransactionManager tm) { log.debug("StandardXAPoolDataSource:setTransactionManager"); transactionManager = tm; }
Invoked when the application calls close() on its representation of the connection
/** * Invoked when the application calls close() * on its representation of the connection */
public void connectionClosed(ConnectionEvent event) { Object obj = event.getSource(); log.debug("StandardXAPoolDataSource:connectionClosed"); XAConnection xac = (XAConnection) obj; // cast it into an xaConnection Transaction tx = null; try { if (transactionManager == null) { TransactionManager tm = ((StandardXADataSource) xads).getTransactionManager(); if (tm == null) { throw new NullPointerException("TM is null"); } else // here we use tm instead to setup transactionManager = tm // if the current transactionManager property is null, it stays // there, and we continue to use the TM from the XADataSource tx = tm.getTransaction(); } else { tx = transactionManager.getTransaction(); } log.debug( "StandardXAPoolDataSource:connectionClosed get a transaction"); } catch (NullPointerException n) { // current is null: we are not in EJBServer. log.error( "StandardXAPoolDataSource:connectionClosed should not be used outside an EJBServer"); } catch (SystemException e) { log.error( "StandardXAPoolDataSource:connectionClosed getTransaction failed:" + e); } // delist Resource if in transaction // We must keep the connection till commit or rollback if ((tx != null) && (((StandardXAConnection) xac).connectionHandle.isReallyUsed)) { try { tx.delistResource(xac.getXAResource(), XAResource.TMSUCCESS); // delist the xaResource log.debug( "StandardXAPoolDataSource:connectionClosed the resourse is delisted"); } catch (Exception e) { log.error( "StandardXAPoolDataSource:connectionClosed Exception in connectionClosed:" + e); } } log.debug( "StandardXAPoolDataSource:connectionClosed checkIn an object to the pool"); pool.checkIn(obj); // return the connection to the pool } public GenerationObject create(String _user, String _password) throws SQLException { GenerationObject genObject; XAConnection xaCon = xads.getXAConnection(_user, _password); // get the xa connection xaCon.addConnectionEventListener(this); // add it to the event listener log.debug( "StandardXAPoolDataSource:create create a object for the pool"); genObject = new GenerationObject(xaCon, pool.getGeneration(), _user, _password); return genObject; }
Retrieves the Reference of this object. Used at binding time by JNDI to build a reference on this object.
Throws:
  • NamingException – If a naming exception was encountered while retrieving the reference.
Returns: The non-null Reference of this object.
/** * Retrieves the Reference of this object. Used at binding time by JNDI * to build a reference on this object. * * @return The non-null Reference of this object. * @exception NamingException If a naming exception was encountered while * retrieving the reference. */
public Reference getReference() throws NamingException { log.debug( "StandardXAPoolDataSource:getReference return a reference of the object"); Reference ref = super.getReference(); ref.add( new StringRefAddr("transactionManagerName", "TransactionManager")); return ref; } /* (non-Javadoc) * @see javax.naming.spi.ObjectFactory#getObjectInstance(java.lang.Object, javax.naming.Name, javax.naming.Context, java.util.Hashtable) */ public Object getObjectInstance( Object refObj, Name name, Context nameCtx, Hashtable env) throws Exception { super.getObjectInstance(refObj, name, nameCtx, env); Reference ref = (Reference) refObj; InitialContext ictx = new InitialContext(env); this.setTransactionManager( (TransactionManager) ictx.lookup( "javax.transaction.TransactionManager")); this.setDataSource((XADataSource) ictx.lookup(this.dataSourceName)); log.debug("StandardPoolDataSource:getObjectInstance: instance created"); return this; }
Getter for property dataSource.
Returns:Value of property dataSource.
/** Getter for property dataSource. * @return Value of property dataSource. */
public XADataSource getDataSource() { return xads; }
Setter for property dataSource.
Params:
  • dataSource – New value of property dataSource.
/** Setter for property dataSource. * @param dataSource New value of property dataSource. */
public void setDataSource(XADataSource dataSource) { this.xads = dataSource; if (transactionManager != null) ((StandardXADataSource) dataSource).setTransactionManager( transactionManager); } public String toString() { StringBuffer sb = new StringBuffer(); sb.append("StandardXAPoolDataSource:\n"); if (this.transactionManager != null) sb.append(" transaction manager=<"+this.transactionManager.toString()+">\n"); if (this.xads != null) sb.append(this.xads.toString()); sb.append(super.toString()); return sb.toString(); }
This method tests if a connection is valid or not. It overrides the method in StandardPoolDataSource to take into account global transactions: if global transaction is in progress - suspend it so that connection testing happens ouside of transaction. If connection testing fails - it will not affect transaction and next good connection can join the transaction
/** * This method tests if a connection is valid or not. It overrides the * method in StandardPoolDataSource to take into account global transactions: * if global transaction is in progress - suspend it so that * connection testing happens ouside of transaction. * If connection testing fails - it will not affect transaction * and next good connection can join the transaction */
public boolean testThisObject(Object o) { Connection ret = null; log.debug( "StandardPoolDataSource:testThisObject verify the current object"); Transaction suspended = null; try { Transaction tx = transactionManager == null ? null : transactionManager.getTransaction(); boolean isActive = tx == null ? false : tx.getStatus() == Status.STATUS_ACTIVE; if (isActive) { suspended = transactionManager.suspend(); } PooledConnection con = (PooledConnection) o; ret = con.getConnection(); Statement s = ret.createStatement(); s.execute(jdbcTestStmt); s.close(); try { ret.close(); } catch (Exception e) { log.error( "StandardPoolDataSource:checkThisObject can't closed the connection: " + e); } return true; } catch (SQLException e) { log.error( "StandardXAPoolDataSource:checkThisObject Error java.sql.SQLException in StandardXAPoolDataSource:testThisObject"); return false; } catch (SystemException e) { log.error( "StandardXAPoolDataSource:checkThisObject Error java.sql.SystemException in StandardXAPoolDataSource:testThisObject"); return false; } finally { if (suspended != null) { try { transactionManager.resume(suspended); } catch (Exception ex) { log.error( "StandardXAPoolDataSource:checkThisObject Error Exception in StandardXAPoolDataSource:testThisObject"); return false; } } } } }