[seam-commits] Seam SVN: r10652 - in modules/trunk: transaction and 7 other directories.
seam-commits at lists.jboss.org
seam-commits at lists.jboss.org
Mon Apr 27 08:50:30 EDT 2009
Author: shane.bryzak at jboss.com
Date: 2009-04-27 08:50:30 -0400 (Mon, 27 Apr 2009)
New Revision: 10652
Added:
modules/trunk/transaction/
modules/trunk/transaction/pom.xml
modules/trunk/transaction/src/
modules/trunk/transaction/src/main/
modules/trunk/transaction/src/main/java/
modules/trunk/transaction/src/main/java/org/
modules/trunk/transaction/src/main/java/org/jboss/
modules/trunk/transaction/src/main/java/org/jboss/seam/
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/AbstractUserTransaction.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/CMTTransaction.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/EjbSynchronizations.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/EjbTransaction.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/EntityTransaction.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/FacesTransactionEvents.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/HibernateTransaction.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/LocalEjbSynchronizations.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/NoTransaction.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/RollbackInterceptor.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/SeSynchronizations.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/SynchronizationRegistry.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/Synchronizations.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/Transaction.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/TransactionInterceptor.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/UTTransaction.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/UserTransaction.java
modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/package-info.java
Log:
initial import of transaction module
Added: modules/trunk/transaction/pom.xml
===================================================================
--- modules/trunk/transaction/pom.xml (rev 0)
+++ modules/trunk/transaction/pom.xml 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,44 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>seam-parent</artifactId>
+ <groupId>org.jboss.seam</groupId>
+ <version>3.0.0-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.jboss.seam</groupId>
+ <artifactId>seam-transaction</artifactId>
+ <packaging>jar</packaging>
+ <version>3.0.0-SNAPSHOT</version>
+ <name>Seam Transaction</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.webbeans</groupId>
+ <artifactId>jsr299-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.webbeans</groupId>
+ <artifactId>webbeans-logging</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.persistence</groupId>
+ <artifactId>persistence-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.transaction</groupId>
+ <artifactId>jta</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.ejb</groupId>
+ <artifactId>ejb-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.seam</groupId>
+ <artifactId>seam-el</artifactId>
+ </dependency>
+ </dependencies>
+
+</project>
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/AbstractUserTransaction.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/AbstractUserTransaction.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/AbstractUserTransaction.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,82 @@
+package org.jboss.seam.transaction;
+
+import static javax.transaction.Status.STATUS_ACTIVE;
+import static javax.transaction.Status.STATUS_MARKED_ROLLBACK;
+import static javax.transaction.Status.STATUS_ROLLEDBACK;
+import static javax.transaction.Status.STATUS_COMMITTED;
+import static javax.transaction.Status.STATUS_NO_TRANSACTION;
+
+import javax.persistence.EntityManager;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.ScopeType;
+
+/**
+ * Base implementation of UserTransaction
+ *
+ * @author Gavin King
+ *
+ */
+public abstract class AbstractUserTransaction implements UserTransaction
+{
+
+ public boolean isActive() throws SystemException
+ {
+ return getStatus() == STATUS_ACTIVE;
+ }
+
+ public boolean isActiveOrMarkedRollback() throws SystemException
+ {
+ int status = getStatus();
+ return status == STATUS_ACTIVE || status == STATUS_MARKED_ROLLBACK;
+ }
+
+ public boolean isRolledBackOrMarkedRollback() throws SystemException
+ {
+ int status = getStatus();
+ return status == STATUS_ROLLEDBACK || status == STATUS_MARKED_ROLLBACK;
+ }
+
+ public boolean isMarkedRollback() throws SystemException
+ {
+ return getStatus() == STATUS_MARKED_ROLLBACK;
+ }
+
+ public boolean isNoTransaction() throws SystemException
+ {
+ return getStatus() == STATUS_NO_TRANSACTION;
+ }
+
+ public boolean isRolledBack() throws SystemException
+ {
+ return getStatus() == STATUS_ROLLEDBACK;
+ }
+
+ public boolean isCommitted() throws SystemException
+ {
+ return getStatus() == STATUS_COMMITTED;
+ }
+
+ public boolean isConversationContextRequired()
+ {
+ return false;
+ }
+
+ public abstract void registerSynchronization(Synchronization sync);
+
+ public void enlist(EntityManager entityManager) throws SystemException
+ {
+ if ( isActiveOrMarkedRollback() )
+ {
+ entityManager.joinTransaction();
+ }
+ }
+
+ public static Synchronizations getSynchronizations()
+ {
+ return (Synchronizations) Component.getInstance("org.jboss.seam.transaction.synchronizations", ScopeType.EVENT);
+ }
+
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/CMTTransaction.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/CMTTransaction.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/CMTTransaction.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,126 @@
+package org.jboss.seam.transaction;
+
+import javax.ejb.EJBContext;
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.UserTransaction;
+
+/**
+ * Wraps EJBContext transaction management in a
+ * UserTransaction interface. Note that container managed
+ * transactions cannot be controlled by the application,
+ * so begin(), commit() and rollback() are disallowed in
+ * a CMT.
+ *
+ * @author Mike Youngstrom
+ * @author Gavin King
+ *
+ */
+public class CMTTransaction extends AbstractUserTransaction
+{
+
+ private final EJBContext ejbContext;
+
+ public CMTTransaction(EJBContext ejbContext)
+ {
+ this.ejbContext = ejbContext;
+ if (ejbContext==null)
+ {
+ throw new IllegalArgumentException("null EJBContext");
+ }
+ }
+
+ public void begin() throws NotSupportedException, SystemException
+ {
+ ejbContext.getUserTransaction().begin();
+ getSynchronizations().afterTransactionBegin();
+ }
+
+ public void commit() throws RollbackException, HeuristicMixedException,
+ HeuristicRollbackException, SecurityException, IllegalStateException, SystemException
+ {
+ UserTransaction userTransaction = ejbContext.getUserTransaction();
+ boolean success = false;
+ Synchronizations synchronizations = getSynchronizations();
+ synchronizations.beforeTransactionCommit();
+ try
+ {
+ userTransaction.commit();
+ success = true;
+ }
+ finally
+ {
+ synchronizations.afterTransactionCommit(success);
+ }
+ }
+
+ public void rollback() throws IllegalStateException, SecurityException, SystemException
+ {
+ UserTransaction userTransaction = ejbContext.getUserTransaction();
+ try
+ {
+ userTransaction.rollback();
+ }
+ finally
+ {
+ getSynchronizations().afterTransactionRollback();
+ }
+ }
+
+ public int getStatus() throws SystemException
+ {
+ try
+ {
+ //TODO: not correct for SUPPORTS or NEVER!
+ if ( !ejbContext.getRollbackOnly() )
+ {
+ return Status.STATUS_ACTIVE;
+ }
+ else
+ {
+ return Status.STATUS_MARKED_ROLLBACK;
+ }
+ }
+ catch (IllegalStateException ise)
+ {
+ try
+ {
+ return ejbContext.getUserTransaction().getStatus();
+ }
+ catch (IllegalStateException is)
+ {
+ return Status.STATUS_NO_TRANSACTION;
+ }
+ }
+ }
+
+ public void setRollbackOnly() throws IllegalStateException, SystemException
+ {
+ ejbContext.setRollbackOnly();
+ }
+
+ public void setTransactionTimeout(int timeout) throws SystemException
+ {
+ ejbContext.getUserTransaction().setTransactionTimeout(timeout);
+ }
+
+ @Override
+ public void registerSynchronization(Synchronization sync)
+ {
+ Synchronizations synchronizations = getSynchronizations();
+ if ( synchronizations.isAwareOfContainerTransactions() )
+ {
+ synchronizations.registerSynchronization(sync);
+ }
+ else
+ {
+ throw new UnsupportedOperationException("cannot register synchronization with container transaction, use <transaction:ejb-transaction/>");
+ }
+ }
+
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/EjbSynchronizations.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/EjbSynchronizations.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/EjbSynchronizations.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,108 @@
+package org.jboss.seam.transaction;
+
+import java.rmi.RemoteException;
+import java.util.LinkedList;
+
+import javax.context.RequestScoped;
+import javax.ejb.EJBException;
+import javax.ejb.Remove;
+import javax.ejb.SessionSynchronization;
+import javax.ejb.Stateful;
+import javax.ejb.TransactionAttribute;
+import javax.ejb.TransactionAttributeType;
+import javax.transaction.Synchronization;
+
+import org.jboss.webbeans.log.LogProvider;
+import org.jboss.webbeans.log.Logging;
+
+/**
+ * Receives JTA transaction completion notifications from
+ * the EJB container, and passes them on to the registered
+ * Synchronizations. This implementation
+ * is fully aware of container managed transactions and is
+ * able to register Synchronizations for the container
+ * transaction.
+ *
+ * @author Gavin King
+ *
+ */
+ at Stateful
+ at RequestScoped
+ at TransactionAttribute(TransactionAttributeType.SUPPORTS)
+public class EjbSynchronizations implements LocalEjbSynchronizations, SessionSynchronization
+{
+ private static final LogProvider log = Logging.getLogProvider(EjbSynchronizations.class);
+
+ //maintain two lists to work around a bug in JBoss EJB3 where a new SessionSynchronization
+ //gets registered each time the bean is called
+ protected LinkedList<SynchronizationRegistry> synchronizations = new LinkedList<SynchronizationRegistry>();
+ protected LinkedList<SynchronizationRegistry> committing = new LinkedList<SynchronizationRegistry>();
+
+ public void afterBegin()
+ {
+ log.debug("afterBegin");
+ synchronizations.addLast( new SynchronizationRegistry() );
+ }
+
+ public void beforeCompletion() throws EJBException, RemoteException
+ {
+ log.debug("beforeCompletion");
+ SynchronizationRegistry sync = synchronizations.removeLast();
+ sync.beforeTransactionCompletion();
+ committing.addLast(sync);
+ }
+
+ public void afterCompletion(boolean success) throws EJBException, RemoteException
+ {
+ log.debug("afterCompletion");
+ if ( committing.isEmpty() )
+ {
+ if (success)
+ {
+ throw new IllegalStateException("beforeCompletion was never called");
+ }
+ else
+ {
+ synchronizations.removeLast().afterTransactionCompletion(false);
+ }
+ }
+ else
+ {
+ committing.removeFirst().afterTransactionCompletion(success);
+ }
+ }
+
+ public boolean isAwareOfContainerTransactions()
+ {
+ return true;
+ }
+
+ public void afterTransactionBegin()
+ {
+ //noop, let JTA notify us
+ }
+
+ public void afterTransactionCommit(boolean success)
+ {
+ //noop, let JTA notify us
+ }
+
+ public void afterTransactionRollback()
+ {
+ //noop, let JTA notify us
+ }
+
+ public void beforeTransactionCommit()
+ {
+ //noop, let JTA notify us
+ }
+
+ public void registerSynchronization(Synchronization sync)
+ {
+ synchronizations.getLast().registerSynchronization(sync);
+ }
+
+ @Remove
+ public void destroy() {}
+
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/EjbTransaction.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/EjbTransaction.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/EjbTransaction.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,15 @@
+package org.jboss.seam.transaction;
+
+import javax.annotation.Named;
+
+/**
+ * Dummy component that lets us install the
+ * EjbSynchronizations via the tag
+ * transaction:ejb-transaction
+ *
+ * @see EjbSynchronizations
+ * @author Gavin King
+ *
+ */
+ at Named
+public class EjbTransaction {}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/EntityTransaction.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/EntityTransaction.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/EntityTransaction.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,226 @@
+package org.jboss.seam.transaction;
+
+import javax.annotation.Named;
+import javax.context.RequestScoped;
+import javax.inject.Current;
+import javax.inject.Initializer;
+import javax.persistence.EntityManager;
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+
+import org.jboss.seam.el.Expressions;
+import org.jboss.seam.el.Expressions.ValueExpression;
+import org.jboss.webbeans.log.LogProvider;
+import org.jboss.webbeans.log.Logging;
+import org.jboss.seam.persistence.PersistenceProvider;
+
+/**
+ * Support for the JPA EntityTransaction API.
+ *
+ * Adapts JPA transaction management to a Seam UserTransaction
+ * interface.For use in non-JTA-capable environments.
+ *
+ * @author Gavin King
+ *
+ */
+ at Named
+ at RequestScoped
+public class EntityTransaction extends AbstractUserTransaction
+{
+ private static final LogProvider log = Logging.getLogProvider(EntityTransaction.class);
+
+ private ValueExpression<EntityManager> entityManager;
+ private EntityManager currentEntityManager;
+
+ @Current Expressions expressions;
+
+ @Initializer
+ public void validate()
+ {
+ if (entityManager==null)
+ {
+ entityManager = expressions.createValueExpression("#{entityManager}", EntityManager.class);
+ }
+ }
+
+ private javax.persistence.EntityTransaction getDelegate()
+ {
+ if (currentEntityManager==null)
+ {
+ //should never occur
+ throw new IllegalStateException("entity manager is null");
+ }
+ return currentEntityManager.getTransaction();
+ }
+
+ private void initEntityManager()
+ {
+ currentEntityManager = entityManager.getValue();
+ if (currentEntityManager==null)
+ {
+ throw new IllegalStateException("entity manager was null: " + entityManager.getExpressionString());
+ }
+ }
+
+ public void begin() throws NotSupportedException, SystemException
+ {
+ log.debug("beginning JPA resource-local transaction");
+ //TODO: translate exceptions that occur into the correct JTA exception
+ assertNotActive();
+ initEntityManager();
+ try
+ {
+ getDelegate().begin();
+ getSynchronizations().afterTransactionBegin();
+ }
+ catch (RuntimeException re)
+ {
+ clearEntityManager();
+ throw re;
+ }
+ }
+
+ public void commit() throws RollbackException, HeuristicMixedException,
+ HeuristicRollbackException, SecurityException, IllegalStateException, SystemException
+ {
+ log.debug("committing JPA resource-local transaction");
+ assertActive();
+ javax.persistence.EntityTransaction delegate = getDelegate();
+ clearEntityManager();
+ boolean success = false;
+ try
+ {
+ if ( delegate.getRollbackOnly() )
+ {
+ delegate.rollback();
+ throw new RollbackException();
+ }
+ else
+ {
+ getSynchronizations().beforeTransactionCommit();
+ delegate.commit();
+ success = true;
+ }
+ }
+ finally
+ {
+ getSynchronizations().afterTransactionCommit(success);
+ }
+ }
+
+ public void rollback() throws IllegalStateException, SecurityException, SystemException
+ {
+ log.debug("rolling back JPA resource-local transaction");
+ //TODO: translate exceptions that occur into the correct JTA exception
+ assertActive();
+ javax.persistence.EntityTransaction delegate = getDelegate();
+ clearEntityManager();
+ try
+ {
+ delegate.rollback();
+ }
+ finally
+ {
+ getSynchronizations().afterTransactionRollback();
+ }
+ }
+
+ public void setRollbackOnly() throws IllegalStateException, SystemException
+ {
+ log.debug("marking JPA resource-local transaction for rollback");
+ assertActive();
+ getDelegate().setRollbackOnly();
+ }
+
+ public int getStatus() throws SystemException
+ {
+ if ( isEntityManagerSet() && getDelegate().getRollbackOnly() )
+ {
+ return Status.STATUS_MARKED_ROLLBACK;
+ }
+ else if ( isEntityManagerSet() && getDelegate().isActive() )
+ {
+ return Status.STATUS_ACTIVE;
+ }
+ else
+ {
+ return Status.STATUS_NO_TRANSACTION;
+ }
+ }
+
+ public void setTransactionTimeout(int timeout) throws SystemException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ private boolean isEntityManagerSet()
+ {
+ return currentEntityManager!=null;
+ }
+
+ private void clearEntityManager()
+ {
+ currentEntityManager = null;
+ }
+
+ private void assertActive()
+ {
+ if ( !isEntityManagerSet() )
+ {
+ throw new IllegalStateException("transaction is not active");
+ }
+ }
+
+ private void assertNotActive() throws NotSupportedException
+ {
+ if ( isEntityManagerSet() )
+ {
+ throw new NotSupportedException("transaction is already active");
+ }
+ }
+
+ @Override
+ public void registerSynchronization(Synchronization sync)
+ {
+ if ( log.isDebugEnabled() )
+ {
+ log.debug("registering synchronization: " + sync);
+ }
+ assertActive();
+ //try to register the synchronization directly with the
+ //persistence provider, but if this fails, just hold
+ //on to it myself
+ if ( !PersistenceProvider.instance().registerSynchronization(sync, currentEntityManager) )
+ {
+ getSynchronizations().registerSynchronization(sync);
+ }
+ }
+
+ @Override
+ public boolean isConversationContextRequired()
+ {
+ return true;
+ }
+
+ public ValueExpression<EntityManager> getEntityManager()
+ {
+ return entityManager;
+ }
+
+ public void setEntityManager(ValueExpression<EntityManager> entityManager)
+ {
+ this.entityManager = entityManager;
+ }
+
+ @Override
+ public void enlist(EntityManager entityManager)
+ {
+ //no-op
+ }
+
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/FacesTransactionEvents.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/FacesTransactionEvents.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/FacesTransactionEvents.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,66 @@
+package org.jboss.seam.transaction;
+
+import static org.jboss.seam.ScopeType.APPLICATION;
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Observer;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Startup;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.international.StatusMessages;
+import org.jboss.seam.international.StatusMessage.Severity;
+
+/**
+ * Produces StatusMessages for JSF in response of certain transaction events.
+ * These events can be observed by support classes for other UI frameworks
+ * to produce similar messages.
+ *
+ * @author Dan Allen
+ */
+ at Name("org.jboss.seam.transaction.facesTransactionEvents")
+ at Scope(APPLICATION)
+ at Install(precedence = BUILT_IN, classDependencies = "javax.faces.context.FacesContext")
+ at BypassInterceptors
+ at Startup
+public class FacesTransactionEvents
+{
+ private boolean transactionFailedMessageEnabled = true;
+
+ @Observer(Transaction.TRANSACTION_FAILED)
+ public void addTransactionFailedMessage(int status)
+ {
+ if (transactionFailedMessageEnabled) {
+ StatusMessages.instance().addFromResourceBundleOrDefault(
+ getTransactionFailedMessageSeverity(),
+ getTransactionFailedMessageKey(),
+ getTransactionFailedMessage());
+ }
+ }
+
+ public String getTransactionFailedMessage()
+ {
+ return "Transaction failed";
+ }
+
+ public Severity getTransactionFailedMessageSeverity()
+ {
+ return Severity.WARN;
+ }
+
+ public String getTransactionFailedMessageKey()
+ {
+ return "org.jboss.seam.TransactionFailed";
+ }
+
+ public boolean isTransactionFailedMessageEnabled()
+ {
+ return transactionFailedMessageEnabled;
+ }
+
+ public void setTransactionFailedMessageEnabled(boolean enabled)
+ {
+ this.transactionFailedMessageEnabled = enabled;
+ }
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/HibernateTransaction.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/HibernateTransaction.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/HibernateTransaction.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,212 @@
+package org.jboss.seam.transaction;
+
+import static org.jboss.seam.annotations.Install.FRAMEWORK;
+
+import javax.persistence.EntityManager;
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Create;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.core.Expressions;
+import org.jboss.seam.core.Expressions.ValueExpression;
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+
+/**
+ * Support for the Hibernate Transaction API.
+ *
+ * Adapts Hibernate transaction management to a Seam UserTransaction
+ * interface. For use in non-JTA-capable environments.
+ *
+ * @author Gavin King
+ *
+ */
+ at Name("org.jboss.seam.transaction.transaction")
+ at Scope(ScopeType.EVENT)
+ at Install(value=false, precedence=FRAMEWORK)
+ at BypassInterceptors
+public class HibernateTransaction extends AbstractUserTransaction
+{
+ private static final LogProvider log = Logging.getLogProvider(HibernateTransaction.class);
+
+ private ValueExpression<Session> session;
+ private Session currentSession;
+ private boolean rollbackOnly; //Hibernate Transaction doesn't have a "rollback only" state
+
+ @Create
+ public void validate()
+ {
+ if (session==null)
+ {
+ session = Expressions.instance().createValueExpression("#{session}", Session.class);
+ }
+ }
+
+ private org.hibernate.Transaction getDelegate()
+ {
+ if (currentSession==null)
+ {
+ //should never occur
+ throw new IllegalStateException("session is null");
+ }
+ return currentSession.getTransaction();
+ }
+
+ private void initSession()
+ {
+ currentSession = session.getValue();
+ if (currentSession==null)
+ {
+ throw new IllegalStateException("session was null: " + session.getExpressionString());
+ }
+ }
+
+ public void begin() throws NotSupportedException, SystemException
+ {
+ log.debug("beginning Hibernate transaction");
+ assertNotActive();
+ initSession();
+ try
+ {
+ getDelegate().begin();
+ }
+ catch (RuntimeException re)
+ {
+ clearSession();
+ throw re;
+ }
+ }
+
+ public void commit() throws RollbackException, HeuristicMixedException,
+ HeuristicRollbackException, SecurityException, IllegalStateException, SystemException
+ {
+ log.debug("committing Hibernate transaction");
+ //TODO: translate exceptions that occur into the correct JTA exception
+ assertActive();
+ Transaction delegate = getDelegate();
+ clearSession();
+ if (rollbackOnly)
+ {
+ rollbackOnly = false;
+ delegate.rollback();
+ throw new RollbackException();
+ }
+ else
+ {
+ delegate.commit();
+ }
+ }
+
+ public void rollback() throws IllegalStateException, SecurityException, SystemException
+ {
+ log.debug("rolling back Hibernate transaction");
+ //TODO: translate exceptions that occur into the correct JTA exception
+ assertActive();
+ Transaction delegate = getDelegate();
+ clearSession();
+ rollbackOnly = false;
+ delegate.rollback();
+ }
+
+ public void setRollbackOnly() throws IllegalStateException, SystemException
+ {
+ log.debug("marking Hibernate transaction for rollback");
+ assertActive();
+ rollbackOnly = true;
+ }
+
+ public int getStatus() throws SystemException
+ {
+ if (rollbackOnly)
+ {
+ return Status.STATUS_MARKED_ROLLBACK;
+ }
+ else if ( isSessionSet() && getDelegate().isActive() )
+ {
+ return Status.STATUS_ACTIVE;
+ }
+ else
+ {
+ return Status.STATUS_NO_TRANSACTION;
+ }
+ }
+
+ public void setTransactionTimeout(int timeout) throws SystemException
+ {
+ assertActive();
+ getDelegate().setTimeout(timeout);
+ }
+
+ private boolean isSessionSet()
+ {
+ return currentSession!=null;
+ }
+
+ private void clearSession()
+ {
+ currentSession = null;
+ }
+
+ private void assertActive()
+ {
+ if ( !isSessionSet() )
+ {
+ throw new IllegalStateException("transaction is not active");
+ }
+ }
+
+ private void assertNotActive() throws NotSupportedException
+ {
+ //TODO: translate exceptions that occur into the correct JTA exception
+ if ( isSessionSet() )
+ {
+ throw new NotSupportedException("transaction is already active");
+ }
+ }
+
+ @Override
+ public void registerSynchronization(Synchronization sync)
+ {
+ if ( log.isDebugEnabled() )
+ {
+ log.debug("registering synchronization: " + sync);
+ }
+ assertActive();
+ getDelegate().registerSynchronization(sync);
+ }
+
+ @Override
+ public void enlist(EntityManager entityManager) throws SystemException
+ {
+ throw new UnsupportedOperationException("JPA EntityManager should not be used with Hibernate Transaction API");
+ }
+
+ @Override
+ public boolean isConversationContextRequired()
+ {
+ return true;
+ }
+
+ public ValueExpression<Session> getSession()
+ {
+ return session;
+ }
+
+ public void setSession(ValueExpression<Session> entityManager)
+ {
+ this.session = entityManager;
+ }
+
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/LocalEjbSynchronizations.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/LocalEjbSynchronizations.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/LocalEjbSynchronizations.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,15 @@
+package org.jboss.seam.transaction;
+
+import javax.ejb.Local;
+
+/**
+ * Local interface for EjbTransaction
+ *
+ * @author Gavin King
+ *
+ */
+ at Local
+public interface LocalEjbSynchronizations extends Synchronizations
+{
+ public void destroy();
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/NoTransaction.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/NoTransaction.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/NoTransaction.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,77 @@
+package org.jboss.seam.transaction;
+
+import static org.jboss.seam.annotations.Install.FRAMEWORK;
+
+import javax.persistence.EntityManager;
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+
+/**
+ * When no kind of transaction management exists.
+ *
+ * @author Mike Youngstrom
+ * @author Gavin King
+ *
+ */
+ at Name("org.jboss.seam.transaction.transaction")
+ at Scope(ScopeType.EVENT)
+ at Install(value = false, precedence = FRAMEWORK)
+ at BypassInterceptors
+public class NoTransaction extends AbstractUserTransaction
+{
+
+ public void begin() throws NotSupportedException, SystemException
+ {
+ throw new UnsupportedOperationException("no transaction");
+ }
+
+ public void commit() throws RollbackException, HeuristicMixedException,
+ HeuristicRollbackException, SecurityException, IllegalStateException, SystemException
+ {
+ throw new UnsupportedOperationException("no transaction");
+ }
+
+ public int getStatus() throws SystemException
+ {
+ return Status.STATUS_NO_TRANSACTION;
+ }
+
+ public void rollback() throws IllegalStateException, SecurityException, SystemException
+ {
+ throw new UnsupportedOperationException("no transaction");
+ }
+
+ public void setRollbackOnly() throws IllegalStateException, SystemException
+ {
+ throw new UnsupportedOperationException("no transaction");
+ }
+
+ public void setTransactionTimeout(int timeout) throws SystemException
+ {
+ throw new UnsupportedOperationException("no transaction");
+ }
+
+ @Override
+ public void registerSynchronization(Synchronization sync)
+ {
+ throw new UnsupportedOperationException("no transaction");
+ }
+
+ @Override
+ public void enlist(EntityManager entityManager) throws SystemException
+ {
+ //no-op
+ }
+
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/RollbackInterceptor.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/RollbackInterceptor.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/RollbackInterceptor.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,50 @@
+//$Id: RollbackInterceptor.java 8626 2008-08-07 19:50:09Z pete.muir at jboss.org $
+package org.jboss.seam.transaction;
+
+import static org.jboss.seam.ComponentType.JAVA_BEAN;
+import static org.jboss.seam.util.Work.isRollbackRequired;
+
+import org.jboss.seam.annotations.intercept.AroundInvoke;
+import org.jboss.seam.annotations.intercept.Interceptor;
+import org.jboss.seam.intercept.AbstractInterceptor;
+import org.jboss.seam.intercept.InvocationContext;
+
+/**
+ * Automatically sets the current transaction to rollback
+ * only when an exception is thrown.
+ *
+ * @author Gavin King
+ */
+ at Interceptor(stateless=true)
+public class RollbackInterceptor extends AbstractInterceptor
+{
+ private static final long serialVersionUID = 5551801508325093417L;
+
+ @AroundInvoke
+ public Object aroundInvoke(InvocationContext invocation) throws Exception
+ {
+ try
+ {
+ return invocation.proceed();
+ }
+ catch (Exception e)
+ {
+ if ( isRollbackRequired(e, getComponent().getType() == JAVA_BEAN) )
+ {
+ try
+ {
+ Transaction.instance().setRollbackOnly();
+ }
+ catch (Exception te) {} //swallow
+ }
+ throw e;
+ }
+ }
+
+ public boolean isInterceptorEnabled()
+ {
+ // Just here for consistency
+ return true;
+ }
+
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/SeSynchronizations.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/SeSynchronizations.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/SeSynchronizations.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,71 @@
+package org.jboss.seam.transaction;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import java.util.Stack;
+
+import javax.transaction.Synchronization;
+
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+
+/**
+ * This implementation does not have access
+ * to the JTA TransactionManager, so it is not fully aware
+ * of container managed transaction lifecycle, and is not
+ * able to register Synchronizations with a container managed
+ * transaction.
+ *
+ * @author Gavin King
+ *
+ */
+ at Name("org.jboss.seam.transaction.synchronizations")
+ at Scope(ScopeType.EVENT)
+ at Install(precedence=BUILT_IN)
+ at BypassInterceptors
+public class SeSynchronizations implements Synchronizations
+{
+ protected Stack<SynchronizationRegistry> synchronizations = new Stack<SynchronizationRegistry>();
+
+ public void afterTransactionBegin()
+ {
+ synchronizations.push( new SynchronizationRegistry() );
+ }
+
+ public void afterTransactionCommit(boolean success)
+ {
+ synchronizations.pop().afterTransactionCompletion(success);
+ }
+
+ public void afterTransactionRollback()
+ {
+ synchronizations.pop().afterTransactionCompletion(false);
+ }
+
+ public void beforeTransactionCommit()
+ {
+ synchronizations.peek().beforeTransactionCompletion();
+ }
+
+ public void registerSynchronization(Synchronization sync)
+ {
+ if (synchronizations.isEmpty())
+ {
+ throw new IllegalStateException("Transaction begin not detected, " +
+ "try installing transaction:ejb-transaction in components.xml");
+ }
+ else
+ {
+ synchronizations.peek().registerSynchronization(sync);
+ }
+ }
+
+ public boolean isAwareOfContainerTransactions()
+ {
+ return false;
+ }
+
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/SynchronizationRegistry.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/SynchronizationRegistry.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/SynchronizationRegistry.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,71 @@
+package org.jboss.seam.transaction;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+
+import org.jboss.seam.core.Events;
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+
+/**
+ * A list of Synchronizations to be invoked before and after transaction
+ * completion. This class is used when we can't register a synchronization
+ * directly with JTA.
+ *
+ * @author Gavin King
+ *
+ */
+class SynchronizationRegistry
+{
+ private static final LogProvider log = Logging.getLogProvider(SynchronizationRegistry.class);
+
+ private List<Synchronization> synchronizations = new ArrayList<Synchronization>();
+
+ void registerSynchronization(Synchronization sync)
+ {
+ synchronizations.add(sync);
+ }
+
+ void afterTransactionCompletion(boolean success)
+ {
+ if ( Events.exists() )
+ {
+ Events.instance().raiseEvent("org.jboss.seam.afterTransactionCompletion", success);
+ }
+ for (Synchronization sync: synchronizations)
+ {
+ try
+ {
+ sync.afterCompletion(success ? Status.STATUS_COMMITTED : Status.STATUS_ROLLEDBACK);
+ }
+ catch (Exception e)
+ {
+ log.error("Exception processing transaction Synchronization after completion", e);
+ }
+ }
+ synchronizations.clear();
+ }
+
+ void beforeTransactionCompletion()
+ {
+ if ( Events.exists() )
+ {
+ Events.instance().raiseEvent("org.jboss.seam.beforeTransactionCompletion");
+ }
+ for (Synchronization sync: synchronizations)
+ {
+ try
+ {
+ sync.beforeCompletion();
+ }
+ catch (Exception e)
+ {
+ log.error("Exception processing transaction Synchronization before completion", e);
+ }
+ }
+ }
+
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/Synchronizations.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/Synchronizations.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/Synchronizations.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,19 @@
+package org.jboss.seam.transaction;
+
+import javax.transaction.Synchronization;
+
+/**
+ * Interface for registering transaction synchronizations
+ *
+ * @author Gavin King
+ *
+ */
+public interface Synchronizations
+{
+ public void afterTransactionBegin();
+ public void afterTransactionCommit(boolean success);
+ public void afterTransactionRollback();
+ public void beforeTransactionCommit();
+ public void registerSynchronization(Synchronization sync);
+ public boolean isAwareOfContainerTransactions();
+}
\ No newline at end of file
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/Transaction.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/Transaction.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/Transaction.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,100 @@
+package org.jboss.seam.transaction;
+
+import static org.jboss.seam.annotations.Install.BUILT_IN;
+
+import javax.naming.InitialContext;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+
+import org.jboss.seam.Component;
+import org.jboss.seam.ScopeType;
+import org.jboss.seam.annotations.Install;
+import org.jboss.seam.annotations.Name;
+import org.jboss.seam.annotations.Scope;
+import org.jboss.seam.annotations.Unwrap;
+import org.jboss.seam.annotations.intercept.BypassInterceptors;
+import org.jboss.seam.util.EJB;
+import org.jboss.seam.util.Naming;
+
+/**
+ * Supports injection of a Seam UserTransaction object that
+ * wraps the current JTA transaction or EJB container managed
+ * transaction.
+ *
+ * @author Mike Youngstrom
+ * @author Gavin King
+ *
+ */
+ at Name("org.jboss.seam.transaction.transaction")
+ at Scope(ScopeType.EVENT)
+ at Install(precedence=BUILT_IN)
+ at BypassInterceptors
+public class Transaction
+{
+ // Event keys
+ public static final String TRANSACTION_FAILED = "org.jboss.seam.transaction.transactionFailed";
+
+ public static UserTransaction instance()
+ {
+ return (UserTransaction) Component.getInstance(Transaction.class, ScopeType.EVENT);
+ }
+
+ @Unwrap
+ public UserTransaction getTransaction() throws NamingException
+ {
+ try
+ {
+ return createUTTransaction();
+ }
+ catch (NameNotFoundException nnfe)
+ {
+ try
+ {
+ return createCMTTransaction();
+ }
+ catch (NameNotFoundException nnfe2)
+ {
+ return createNoTransaction();
+ }
+ }
+ }
+
+ protected UserTransaction createNoTransaction()
+ {
+ return new NoTransaction();
+ }
+
+ protected UserTransaction createCMTTransaction() throws NamingException
+ {
+ return new CMTTransaction( EJB.getEJBContext() );
+ }
+
+ protected UserTransaction createUTTransaction() throws NamingException
+ {
+ return new UTTransaction( getUserTransaction() );
+ }
+
+ protected javax.transaction.UserTransaction getUserTransaction() throws NamingException
+ {
+ InitialContext context = Naming.getInitialContext();
+ try
+ {
+ return (javax.transaction.UserTransaction) context.lookup("java:comp/UserTransaction");
+ }
+ catch (NameNotFoundException nnfe)
+ {
+ try
+ {
+ //Embedded JBoss has no java:comp/UserTransaction
+ javax.transaction.UserTransaction ut = (javax.transaction.UserTransaction) context.lookup("UserTransaction");
+ ut.getStatus(); //for glassfish, which can return an unusable UT
+ return ut;
+ }
+ catch (Exception e)
+ {
+ throw nnfe;
+ }
+ }
+ }
+
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/TransactionInterceptor.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/TransactionInterceptor.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/TransactionInterceptor.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,128 @@
+package org.jboss.seam.transaction;
+
+import static org.jboss.seam.ComponentType.JAVA_BEAN;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jboss.seam.annotations.TransactionPropagationType;
+import org.jboss.seam.annotations.Transactional;
+import org.jboss.seam.annotations.intercept.AroundInvoke;
+import org.jboss.seam.annotations.intercept.Interceptor;
+import org.jboss.seam.bpm.BusinessProcessInterceptor;
+import org.jboss.seam.core.BijectionInterceptor;
+import org.jboss.seam.core.ConversationInterceptor;
+import org.jboss.seam.intercept.AbstractInterceptor;
+import org.jboss.seam.intercept.InvocationContext;
+import org.jboss.seam.util.Work;
+
+/**
+ * Implements transaction propagation rules for Seam JavaBean components.
+ *
+ * @author Gavin King
+ * @author Shane Bryzak
+ */
+ at Interceptor(stateless=false,
+ around={RollbackInterceptor.class, BusinessProcessInterceptor.class,
+ ConversationInterceptor.class, BijectionInterceptor.class})
+public class TransactionInterceptor extends AbstractInterceptor
+{
+ private static final long serialVersionUID = -4364203056333738988L;
+
+ transient
+ private Map<AnnotatedElement,TransactionMetadata> transactionMetadata = new HashMap<AnnotatedElement, TransactionMetadata>();
+
+ private class TransactionMetadata
+ {
+ private boolean annotationPresent;
+ TransactionPropagationType propType;
+
+ public TransactionMetadata(AnnotatedElement element)
+ {
+ annotationPresent = element.isAnnotationPresent(Transactional.class);
+
+ if (annotationPresent)
+ {
+ propType = element.getAnnotation(Transactional.class).value();
+ }
+ }
+
+ public boolean isAnnotationPresent()
+ {
+ return annotationPresent;
+ }
+
+ public boolean isNewTransactionRequired(boolean transactionActive)
+ {
+ return propType != null && propType.isNewTransactionRequired(transactionActive);
+ }
+ }
+
+ private TransactionMetadata lookupTransactionMetadata(AnnotatedElement element) {
+ if (transactionMetadata == null) {
+ transactionMetadata = new HashMap<AnnotatedElement, TransactionMetadata>();
+ }
+
+ TransactionMetadata metadata = transactionMetadata.get(element);
+
+ if (metadata == null) {
+ metadata = loadMetadata(element);
+ }
+
+ return metadata;
+ }
+
+ private synchronized TransactionMetadata loadMetadata(AnnotatedElement element) {
+ if (!transactionMetadata.containsKey(element)) {
+ TransactionMetadata metadata = new TransactionMetadata(element);
+ transactionMetadata.put(element, metadata);
+ return metadata;
+ }
+
+ return transactionMetadata.get(element);
+ }
+
+
+ @AroundInvoke
+ public Object aroundInvoke(final InvocationContext invocation) throws Exception
+ {
+ return new Work()
+ {
+
+ @Override
+ protected Object work() throws Exception
+ {
+ return invocation.proceed();
+ }
+
+ @Override
+ protected boolean isNewTransactionRequired(boolean transactionActive)
+ {
+ return isNewTransactionRequired( invocation.getMethod(), getComponent().getBeanClass(), transactionActive );
+ }
+
+ private boolean isNewTransactionRequired(Method method, Class beanClass, boolean transactionActive)
+ {
+ TransactionMetadata metadata = lookupTransactionMetadata(method);
+ if (metadata.isAnnotationPresent())
+ {
+ return metadata.isNewTransactionRequired(transactionActive);
+ }
+ else
+ {
+ metadata = lookupTransactionMetadata(beanClass);
+ return metadata.isNewTransactionRequired(transactionActive);
+ }
+ }
+
+ }.workInTransaction();
+ }
+
+ public boolean isInterceptorEnabled()
+ {
+ return getComponent().getType()==JAVA_BEAN && getComponent().beanClassHasAnnotation(Transactional.class);
+ }
+
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/UTTransaction.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/UTTransaction.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/UTTransaction.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,95 @@
+package org.jboss.seam.transaction;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+
+/**
+ * Wraps JTA transaction management in a Seam UserTransaction
+ * interface.
+ *
+ * @author Mike Youngstrom
+ * @author Gavin King
+ *
+ */
+public class UTTransaction extends AbstractUserTransaction
+{
+ private static final LogProvider log = Logging.getLogProvider(UTTransaction.class);
+
+ private final javax.transaction.UserTransaction delegate;
+
+ UTTransaction(javax.transaction.UserTransaction delegate)
+ {
+ this.delegate = delegate;
+ if (delegate==null)
+ {
+ throw new IllegalArgumentException("null UserTransaction");
+ }
+ }
+
+ public void begin() throws NotSupportedException, SystemException
+ {
+ log.debug("beginning JTA transaction");
+ delegate.begin();
+ getSynchronizations().afterTransactionBegin();
+ }
+
+ public void commit() throws RollbackException, HeuristicMixedException,
+ HeuristicRollbackException, SecurityException, IllegalStateException, SystemException
+ {
+ log.debug("committing JTA transaction");
+ boolean success = false;
+ Synchronizations synchronizations = getSynchronizations();
+ synchronizations.beforeTransactionCommit();
+ try
+ {
+ delegate.commit();
+ success = true;
+ }
+ finally
+ {
+ synchronizations.afterTransactionCommit(success);
+ }
+ }
+
+ public void rollback() throws IllegalStateException, SecurityException, SystemException
+ {
+ log.debug("rolling back JTA transaction");
+ try
+ {
+ delegate.rollback();
+ }
+ finally
+ {
+ getSynchronizations().afterTransactionRollback();
+ }
+ }
+
+ public int getStatus() throws SystemException
+ {
+ return delegate.getStatus();
+ }
+
+ public void setRollbackOnly() throws IllegalStateException, SystemException
+ {
+ delegate.setRollbackOnly();
+ }
+
+ public void setTransactionTimeout(int timeout) throws SystemException
+ {
+ delegate.setTransactionTimeout(timeout);
+ }
+
+ @Override
+ public void registerSynchronization(Synchronization sync)
+ {
+ getSynchronizations().registerSynchronization(sync);
+ }
+
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/UserTransaction.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/UserTransaction.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/UserTransaction.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,29 @@
+package org.jboss.seam.transaction;
+
+import javax.persistence.EntityManager;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+
+/**
+ * Extends the standard UserTransaction interface with a couple
+ * of helpful methods.
+ *
+ * @author Gavin King
+ *
+ */
+public interface UserTransaction extends javax.transaction.UserTransaction
+{
+
+ public boolean isActive() throws SystemException;
+ public boolean isActiveOrMarkedRollback() throws SystemException;
+ public boolean isRolledBackOrMarkedRollback() throws SystemException;
+ public boolean isMarkedRollback() throws SystemException;
+ public boolean isNoTransaction() throws SystemException;
+ public boolean isRolledBack() throws SystemException;
+ public boolean isCommitted() throws SystemException;
+
+ public boolean isConversationContextRequired();
+ public abstract void registerSynchronization(Synchronization sync);
+
+ public void enlist(EntityManager entityManager) throws SystemException;
+}
Added: modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/package-info.java
===================================================================
--- modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/package-info.java (rev 0)
+++ modules/trunk/transaction/src/main/java/org/jboss/seam/transaction/package-info.java 2009-04-27 12:50:30 UTC (rev 10652)
@@ -0,0 +1,20 @@
+/**
+ * Abstracts all possible transaction management APIs behind a
+ * JTA-compatible interface. Unfortunately, many
+ * otherwise-perfectly-intelligent-looking Java developers like
+ * to invent their own transaction management APIs when they get
+ * bored, even though JTA is well-known to be more than good
+ * enough. For example, one of the co-authors of this class was
+ * present at the creation of not one but two "alternative"
+ * transaction APIs (org.hibernate.Transaction and
+ * javax.persistence.EntityTransaction), and is more
+ * embarrassed by this than by any other of his many professional
+ * blunders.
+ *
+ * @see org.jboss.seam.transaction.Transaction
+ * @see org.jboss.seam.transaction.UserTransaction
+ */
+ at Namespace(value="http://jboss.com/products/seam/transaction", prefix="org.jboss.seam.transaction")
+package org.jboss.seam.transaction;
+
+import org.jboss.seam.annotations.Namespace;
More information about the seam-commits
mailing list