Changed JtaModule to use structural typing instead of Field reflection, plus added a guard

This commit is contained in:
Jonas Bonér 2010-08-30 19:47:35 +02:00
parent 8e884df116
commit ea60588c21
6 changed files with 41 additions and 27 deletions

View file

@ -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)

View file

@ -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]
}
}
}

View file

@ -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

View file

@ -2,7 +2,7 @@
* Copyright (C) 2009-2010 Scalable Solutions AB <http://scalablesolutions.se>
*/
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")
}
}

View file

@ -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._

View file

@ -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