[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