diff --git a/akka-actor/src/main/scala/stm/Transaction.scala b/akka-actor/src/main/scala/stm/Transaction.scala index 682e9dd8f1..60e0cd6772 100644 --- a/akka-actor/src/main/scala/stm/Transaction.scala +++ b/akka-actor/src/main/scala/stm/Transaction.scala @@ -9,7 +9,7 @@ import java.util.concurrent.atomic.AtomicInteger import scala.collection.mutable.HashMap -import se.scalablesolutions.akka.util.ReflectiveAccess.JTAModule._ +import se.scalablesolutions.akka.util.ReflectiveAccess.JtaModule import se.scalablesolutions.akka.util.Logging import se.scalablesolutions.akka.config.Config._ @@ -92,8 +92,8 @@ object Transaction { private[this] val persistentStateMap = new HashMap[String, Committable with Abortable] private[akka] val depth = new AtomicInteger(0) - val jta: Option[TransactionContainer] = - if (JTA_AWARE) Some(createTransactionContainer) + val jta: Option[JtaModule.TransactionContainer] = + if (JTA_AWARE) Some(JtaModule.createTransactionContainer) else None log.trace("Creating transaction " + toString) diff --git a/akka-actor/src/main/scala/util/ReflectiveAccess.scala b/akka-actor/src/main/scala/util/ReflectiveAccess.scala index 6a050ef085..4582304188 100644 --- a/akka-actor/src/main/scala/util/ReflectiveAccess.scala +++ b/akka-actor/src/main/scala/util/ReflectiveAccess.scala @@ -23,9 +23,11 @@ object ReflectiveAccess { lazy val isRemotingEnabled = RemoteClientModule.isRemotingEnabled lazy val isTypedActorEnabled = TypedActorModule.isTypedActorEnabled + lazy val isJtaEnabled = JtaModule.isJtaEnabled def ensureRemotingEnabled = RemoteClientModule.ensureRemotingEnabled def ensureTypedActorEnabled = TypedActorModule.ensureTypedActorEnabled + def ensureJtaEnabled = JtaModule.ensureJtaEnabled /** * Reflective access to the RemoteClient module. @@ -193,7 +195,11 @@ object ReflectiveAccess { } } - object JTAModule { + object JtaModule { + + type TransactionContainerObject = { + def apply(): TransactionContainer + } type TransactionContainer = { def beginWithStmSynchronization(transaction: Transaction): Unit @@ -201,15 +207,23 @@ object ReflectiveAccess { def rollback: Unit } - def createTransactionContainer: TransactionContainer = { - try { - val clazz = Class.forName("se.scalablesolutions.akka.stm.TransactionContainer$") - val instance = clazz.getDeclaredField("MODULE$") - val applyMethod = clazz.getDeclaredMethod("apply") - applyMethod.invoke(instance.get(null)).asInstanceOf[TransactionContainer] - } catch { - case cnfe: ClassNotFoundException => throw new IllegalStateException("Couldn't locale akka-jta, make sure you have it on your classpath") + lazy val isJtaEnabled = transactionContainerObjectInstance.isDefined + + def ensureJtaEnabled = if (!isJtaEnabled) throw new ModuleNotAvailableException( + "Can't load the typed actor module, make sure that akka-jta.jar is on the classpath") + + val transactionContainerObjectInstance: Option[TransactionContainerObject] = { + try { + val clazz = loader.loadClass("se.scalablesolutions.akka.actor.TransactionContainer$") + val ctor = clazz.getDeclaredConstructor(Array[Class[_]](): _*) + ctor.setAccessible(true) + Some(ctor.newInstance(Array[AnyRef](): _*).asInstanceOf[TransactionContainerObject]) + } catch { case e: Exception => None } } + + def createTransactionContainer: TransactionContainer = { + ensureJtaEnabled + transactionContainerObjectInstance.get.apply.asInstanceOf[TransactionContainer] } } } diff --git a/akka-jta/src/main/scala/AtomikosTransactionService.scala b/akka-jta/src/main/scala/AtomikosTransactionService.scala index f85ff56e6a..305ddb6ace 100644 --- a/akka-jta/src/main/scala/AtomikosTransactionService.scala +++ b/akka-jta/src/main/scala/AtomikosTransactionService.scala @@ -11,7 +11,6 @@ import com.atomikos.icatch.config.{TSInitInfo, UserTransactionService, UserTrans import se.scalablesolutions.akka.config.Config._ import se.scalablesolutions.akka.util.Duration -import se.scalablesolutions.akka.stm.{TransactionService, TransactionContainer} object AtomikosTransactionService extends AtomikosTransactionService diff --git a/akka-jta/src/main/scala/JTA.scala b/akka-jta/src/main/scala/JTA.scala index 72c5a9894d..d3c1ade168 100644 --- a/akka-jta/src/main/scala/JTA.scala +++ b/akka-jta/src/main/scala/JTA.scala @@ -2,7 +2,7 @@ * Copyright (C) 2009-2010 Scalable Solutions AB */ -package se.scalablesolutions.akka.stm +package se.scalablesolutions.akka.jta import javax.transaction.{TransactionManager, UserTransaction, Transaction => JtaTransaction, SystemException, @@ -11,8 +11,11 @@ import javax.naming.{InitialContext, Context, NamingException} import se.scalablesolutions.akka.config.Config._ import se.scalablesolutions.akka.util.Logging +import se.scalablesolutions.akka.stm.Transaction import se.scalablesolutions.akka.AkkaException +class JtaConfigurationException(message: String) extends AkkaException(message) + /** * Detects if there is a UserTransaction or TransactionManager available in the JNDI. * @@ -47,12 +50,12 @@ object TransactionContainer extends Logging { .transactionContainer } catch { case e: ClassNotFoundException => - throw new StmConfigurationException( + throw new JtaConfigurationException( "JTA provider defined as 'atomikos', but the AtomikosTransactionService classes can not be found." + "\n\tPlease make sure you have 'akka-jta' JAR and its dependencies on your classpath.") } case _ => - throw new StmConfigurationException( + throw new JtaConfigurationException( "No UserTransaction on TransactionManager could be found in scope." + "\n\tEither add 'akka-jta' to the classpath or make sure there is a" + "\n\tTransactionManager or UserTransaction defined in the JNDI.") @@ -133,7 +136,7 @@ class TransactionContainer private ( tm match { case Left(Some(userTx)) => userTx.begin case Right(Some(txMan)) => txMan.begin - case _ => throw new StmConfigurationException("Does not have a UserTransaction or TransactionManager in scope") + case _ => throw new JtaConfigurationException("Does not have a UserTransaction or TransactionManager in scope") } } @@ -142,7 +145,7 @@ class TransactionContainer private ( tm match { case Left(Some(userTx)) => userTx.commit case Right(Some(txMan)) => txMan.commit - case _ => throw new StmConfigurationException("Does not have a UserTransaction or TransactionManager in scope") + case _ => throw new JtaConfigurationException("Does not have a UserTransaction or TransactionManager in scope") } } @@ -151,42 +154,42 @@ class TransactionContainer private ( tm match { case Left(Some(userTx)) => userTx.rollback case Right(Some(txMan)) => txMan.rollback - case _ => throw new StmConfigurationException("Does not have a UserTransaction or TransactionManager in scope") + case _ => throw new JtaConfigurationException("Does not have a UserTransaction or TransactionManager in scope") } } def getStatus = tm match { case Left(Some(userTx)) => userTx.getStatus case Right(Some(txMan)) => txMan.getStatus - case _ => throw new StmConfigurationException("Does not have a UserTransaction or TransactionManager in scope") + case _ => throw new JtaConfigurationException("Does not have a UserTransaction or TransactionManager in scope") } def isInExistingTransaction = tm match { case Left(Some(userTx)) => userTx.getStatus == Status.STATUS_ACTIVE case Right(Some(txMan)) => txMan.getStatus == Status.STATUS_ACTIVE - case _ => throw new StmConfigurationException("Does not have a UserTransaction or TransactionManager in scope") + case _ => throw new JtaConfigurationException("Does not have a UserTransaction or TransactionManager in scope") } def isRollbackOnly = tm match { case Left(Some(userTx)) => userTx.getStatus == Status.STATUS_MARKED_ROLLBACK case Right(Some(txMan)) => txMan.getStatus == Status.STATUS_MARKED_ROLLBACK - case _ => throw new StmConfigurationException("Does not have a UserTransaction or TransactionManager in scope") + case _ => throw new JtaConfigurationException("Does not have a UserTransaction or TransactionManager in scope") } def setRollbackOnly = tm match { case Left(Some(userTx)) => userTx.setRollbackOnly case Right(Some(txMan)) => txMan.setRollbackOnly - case _ => throw new StmConfigurationException("Does not have a UserTransaction or TransactionManager in scope") + case _ => throw new JtaConfigurationException("Does not have a UserTransaction or TransactionManager in scope") } def suspend = tm match { case Right(Some(txMan)) => txMan.suspend - case _ => throw new StmConfigurationException("Does not have a TransactionManager in scope") + case _ => throw new JtaConfigurationException("Does not have a TransactionManager in scope") } def resume(tx: JtaTransaction) = tm match { case Right(Some(txMan)) => txMan.resume(tx) - case _ => throw new StmConfigurationException("Does not have a TransactionManager in scope") + case _ => throw new JtaConfigurationException("Does not have a TransactionManager in scope") } } diff --git a/akka-jta/src/main/scala/TransactionContext.scala b/akka-jta/src/main/scala/TransactionContext.scala index c66c48d5b9..79d6f7366d 100644 --- a/akka-jta/src/main/scala/TransactionContext.scala +++ b/akka-jta/src/main/scala/TransactionContext.scala @@ -6,7 +6,6 @@ package se.scalablesolutions.akka.jta import javax.transaction.{Transaction, Status, TransactionManager, Synchronization} -import se.scalablesolutions.akka.stm.{TransactionService, TransactionContainer} import se.scalablesolutions.akka.util.Logging import se.scalablesolutions.akka.config.Config._ diff --git a/akka-jta/src/main/scala/TransactionProtocol.scala b/akka-jta/src/main/scala/TransactionProtocol.scala index 96567916a3..f85b7ee1e3 100644 --- a/akka-jta/src/main/scala/TransactionProtocol.scala +++ b/akka-jta/src/main/scala/TransactionProtocol.scala @@ -5,7 +5,6 @@ package se.scalablesolutions.akka.jta import se.scalablesolutions.akka.util.Logging -import se.scalablesolutions.akka.stm.TransactionContainer import java.util.{List => JList} import java.util.concurrent.CopyOnWriteArrayList