/**
* 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.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.jms.JMSException;
import javax.jms.Session;
import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import com.atomikos.beans.PropertyUtils;
import com.atomikos.datasource.pool.Reapable;
import com.atomikos.datasource.xa.session.SessionHandleStateChangeListener;
import com.atomikos.icatch.CompositeTransaction;
import com.atomikos.icatch.jta.TransactionManagerImp;
import com.atomikos.logging.Logger;
import com.atomikos.logging.LoggerFactory;
import com.atomikos.util.ClassLoadingHelper;
import com.atomikos.util.DynamicProxy;
class AtomikosJmsNonXaSessionProxy extends AbstractJmsSessionProxy
{
private static final Logger LOGGER = LoggerFactory.createLogger(AtomikosJmsNonXaSessionProxy.class);
private final static String CLOSE_METHOD = "close";
private static Class<?>[] MINIMUM_SET_OF_INTERFACES = {Reapable.class, DynamicProxy.class, javax.jms.Session.class };
public static Object newInstance ( Session s , SessionHandleStateChangeListener pooledConnection , SessionHandleStateChangeListener connectionProxy ) throws JMSException
{
AtomikosJmsNonXaSessionProxy proxy = new AtomikosJmsNonXaSessionProxy ( s , pooledConnection , connectionProxy );
Set<Class<?>> interfaces = PropertyUtils.getAllImplementedInterfaces ( s.getClass() );
//see case 24532
interfaces.add ( DynamicProxy.class );
Class<?>[] interfaceClasses = ( Class[] ) interfaces.toArray ( new Class[0] );
List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
classLoaders.add ( Thread.currentThread().getContextClassLoader() );
classLoaders.add ( s.getClass().getClassLoader() );
classLoaders.add ( AtomikosJmsNonXaSessionProxy.class.getClassLoader() );
return ( Session ) ClassLoadingHelper.newProxyInstance ( classLoaders , MINIMUM_SET_OF_INTERFACES , interfaceClasses , proxy );
}
private Session delegate;
private boolean closed = false;
private boolean errorsOccurred = false;
private SessionHandleStateChangeListener owner;
private SessionHandleStateChangeListener connectionProxy;
private AtomikosJmsNonXaSessionProxy ( Session s , SessionHandleStateChangeListener pooledConnection , SessionHandleStateChangeListener connectionProxy )
{
this.delegate = s;
this.owner = pooledConnection;
this.connectionProxy = connectionProxy;
}
private void checkForTransactionContextAndLogWarningIfSo()
{
TransactionManager tm = TransactionManagerImp.getTransactionManager();
if ( tm != null ) {
Transaction tx = null;
try {
tx = tm.getTransaction();
} catch (SystemException e) {
if ( LOGGER.isTraceEnabled() ) LOGGER.logTrace ( this + ": Failed to get transaction." , e );
//ignore
}
if ( tx != null ) {
String msg = this + ": WARNING - detected JTA transaction context while using non-transactional session." + "\n" +
"Beware that any JMS operations you perform are NOT part of the JTA transaction." + "\n" +
"To enable JTA, make sure to do all of the following:" + "\n" +
"1. Make sure that the AtomikosConnectionFactoryBean is configured with localTransactionMode=false, and" + "\n" +
"2. Make sure to call create JMS sessions with the transacted flag set to true.";
if ( LOGGER.isDebugEnabled() ) LOGGER.logDebug ( msg );
}
}
}
//threaded: invoked by application thread as well as by pool maintenance thread
public Object invoke ( Object proxy, Method method, Object[] args ) throws JMSException
{
String methodName = method.getName();
//see case 24532
if ( methodName.equals ( "getInvocationHandler" ) ) return this;
//synchronized only now to avoid deadlock - cf case 33703
synchronized ( this ) {
if (closed) {
if (!methodName.equals(CLOSE_METHOD)) {
String msg = "Session was closed already - calling " + methodName + " is no longer allowed.";
LOGGER.logWarning ( this + ": " + msg );
throw new javax.jms.IllegalStateException(msg);
}
return null;
}
if ( CLOSE_METHOD.equals ( methodName ) ) {
if ( LOGGER.isDebugEnabled() ) LOGGER.logDebug ( this + ": close...");
destroy();
return null;
}
checkForTransactionContextAndLogWarningIfSo();
try {
if ( LOGGER.isDebugEnabled() ) LOGGER.logDebug ( this + ": calling " + methodName + " on vendor session..." );
Object ret = method.invoke(delegate, args);
if ( LOGGER.isTraceEnabled() ) LOGGER.logTrace ( this + ": " + methodName + " returning " + ret );
return ret;
} catch (Exception ex) {
errorsOccurred = true;
String msg = "Error delegating " + methodName + " call to JMS driver";
convertProxyError ( ex , msg );
}
}
//dummy return to make compiler happy
return null;
}
protected void destroy() {
try {
if ( LOGGER.isDebugEnabled() ) LOGGER.logDebug ( this + ": destroying session...");
if ( !closed ) {
closed = true;
delegate.close();
owner.onTerminated();
connectionProxy.onTerminated();
}
} catch ( JMSException e ) {
LOGGER.logWarning ( this + ": could not close JMS session" , e );
}
}
protected boolean isAvailable() {
return closed;
}
protected boolean isErroneous() {
return errorsOccurred;
}
protected boolean isInTransaction ( CompositeTransaction ct ) {
return false;
}
public String toString()
{
return "atomikos non-xa session proxy for vendor instance " + delegate;
}
}