/**
* Copyright (C) 2000-2016 Atomikos <info@atomikos.com>
*
* LICENSE CONDITIONS
*
* See http://www.atomikos.com/Main/WhichLicenseApplies for details.
*/
package com.atomikos.jms;
import java.lang.reflect.Proxy;
import javax.jms.JMSException;
import javax.jms.XAConnection;
import com.atomikos.datasource.pool.AbstractXPooledConnection;
import com.atomikos.datasource.pool.ConnectionPoolProperties;
import com.atomikos.datasource.pool.CreateConnectionException;
import com.atomikos.datasource.pool.Reapable;
import com.atomikos.datasource.xa.XATransactionalResource;
import com.atomikos.datasource.xa.session.SessionHandleStateChangeListener;
import com.atomikos.icatch.CompositeTransaction;
import com.atomikos.icatch.CompositeTransactionManager;
import com.atomikos.icatch.config.Configuration;
import com.atomikos.icatch.jta.TransactionManagerImp;
import com.atomikos.logging.Logger;
import com.atomikos.logging.LoggerFactory;
import com.atomikos.util.DynamicProxy;
class AtomikosPooledJmsConnection extends AbstractXPooledConnection implements SessionHandleStateChangeListener {
private static final Logger LOGGER = LoggerFactory.createLogger(AtomikosPooledJmsConnection.class);
private XAConnection xaConnection;
private XATransactionalResource jmsTransactionalResource;
private Reapable currentProxy;
private ConnectionPoolProperties props;
private boolean erroneous;
private boolean ignoreSessionTransactedFlag;
protected AtomikosPooledJmsConnection(boolean ignoreSessionTransactedFlag, XAConnection xac, XATransactionalResource jmsTransactionalResource, ConnectionPoolProperties props) {
super(props);
this.jmsTransactionalResource = jmsTransactionalResource;
this.xaConnection = xac;
this.props = props;
this.erroneous = false;
this.ignoreSessionTransactedFlag = ignoreSessionTransactedFlag;
}
protected Reapable doCreateConnectionProxy() throws CreateConnectionException {
currentProxy = AtomikosJmsConnectionProxy.newInstance (ignoreSessionTransactedFlag, xaConnection , jmsTransactionalResource , this , props );
return currentProxy;
}
protected void testUnderlyingConnection() throws CreateConnectionException {
if ( isErroneous() ) throw new CreateConnectionException ( this + ": connection is erroneous" );
}
public void destroy() {
if ( LOGGER.isTraceEnabled() ) LOGGER.logTrace ( this + ": destroying connection..." );
if (xaConnection != null) {
try {
xaConnection.close();
} catch (JMSException ex) {
//ignore but log
LOGGER.logWarning ( this + ": error closing XAConnection: " , ex );
}
}
xaConnection = null;
}
public synchronized boolean isAvailable() {
boolean ret = true;
if ( currentProxy != null ) {
DynamicProxy dproxy = ( DynamicProxy ) currentProxy;
AtomikosJmsConnectionProxy proxy = (AtomikosJmsConnectionProxy) dproxy.getInvocationHandler();
ret = proxy.isAvailable();
}
return ret;
}
public synchronized boolean isErroneous() {
boolean ret = erroneous;
if ( currentProxy != null ) {
AtomikosJmsConnectionProxy proxy = (AtomikosJmsConnectionProxy) Proxy.getInvocationHandler ( currentProxy );
ret = ret || proxy.isErroneous();
}
return ret;
}
public synchronized boolean isInTransaction ( CompositeTransaction ct ) {
boolean ret = false;
if ( currentProxy != null ) {
DynamicProxy dproxy = ( DynamicProxy ) currentProxy;
AtomikosJmsConnectionProxy proxy = (AtomikosJmsConnectionProxy) dproxy.getInvocationHandler();
ret = proxy.isInTransaction ( ct );
}
return ret;
}
public void onTerminated() {
boolean fireTerminatedEvent = false;
synchronized ( this ) {
//a session has terminated -> check reusability of all remaining
if ( LOGGER.isTraceEnabled() ) LOGGER.logTrace ( this + ": a session has terminated, is connection now available ? " + isAvailable() );
if ( isAvailable() ) {
if ( currentProxy != null ) {
DynamicProxy dproxy = ( DynamicProxy ) currentProxy;
AtomikosJmsConnectionProxy proxy = (AtomikosJmsConnectionProxy) dproxy.getInvocationHandler();
if ( proxy.isErroneous() ) erroneous = true;
proxy.destroy();
}
fireTerminatedEvent = true;
} else {
//not yet available, but check if the connection is erroneous
//which happens if the session being terminated is erroneous
if ( currentProxy != null ) {
DynamicProxy dproxy = ( DynamicProxy ) currentProxy;
AtomikosJmsConnectionProxy proxy = (AtomikosJmsConnectionProxy) dproxy.getInvocationHandler();
if ( proxy.isErroneous() ) erroneous = true;
}
}
}
if ( fireTerminatedEvent ) {
//callbacks done outside synch to avoid deadlock in case 27614
fireOnXPooledConnectionTerminated();
}
}
public boolean canBeRecycledForCallingThread ()
{
boolean ret = false;
if ( currentProxy != null ) {
CompositeTransactionManager tm = Configuration.getCompositeTransactionManager();
CompositeTransaction current = tm.getCompositeTransaction();
if ( ( current != null ) && ( current.getProperty ( TransactionManagerImp.JTA_PROPERTY_NAME) != null )) {
DynamicProxy dproxy = ( DynamicProxy ) currentProxy;
AtomikosJmsConnectionProxy proxy = (AtomikosJmsConnectionProxy) dproxy.getInvocationHandler();
//recycle only if inactive in this tx - i.e., if proxy was closed!
ret = proxy.isInactiveInTransaction(current);
}
}
return ret;
}
public String toString()
{
return "atomikos pooled connection for resource " + jmsTransactionalResource.getName();
}
}