Author: swd847
Date: 2010-07-16 18:31:47 -0400 (Fri, 16 Jul 2010)
New Revision: 13415
Added:
modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/EntityTransaction.java
Modified:
modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/Transaction.java
modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/TransactionExtension.java
modules/persistence/trunk/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
modules/persistence/trunk/src/test/java/org/jboss/seam/transactions/test/TransactionInterceptorTest.java
modules/persistence/trunk/src/test/java/org/jboss/seam/transactions/test/UserTransactionTest.java
Log:
make default UserTransaction registered via portable extension
Added:
modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/EntityTransaction.java
===================================================================
---
modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/EntityTransaction.java
(rev 0)
+++
modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/EntityTransaction.java 2010-07-16
22:31:47 UTC (rev 13415)
@@ -0,0 +1,160 @@
+package org.jboss.seam.transaction;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+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.weld.extensions.core.Veto;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 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
+ *
+ */
+@RequestScoped
+@Veto
+public class EntityTransaction extends AbstractUserTransaction
+{
+ private static final Logger log = LoggerFactory.getLogger(EntityTransaction.class);
+
+ @Inject
+ private EntityManager entityManager;
+
+
+ @Inject
+ public EntityTransaction(Synchronizations sync)
+ {
+ super(sync);
+ }
+
+ private javax.persistence.EntityTransaction getDelegate()
+ {
+ return entityManager.getTransaction();
+ }
+
+ public void begin() throws NotSupportedException, SystemException
+ {
+ log.debug("beginning JPA resource-local transaction");
+ //TODO: translate exceptions that occur into the correct JTA exception
+ try
+ {
+ getDelegate().begin();
+ getSynchronizations().afterTransactionBegin();
+ }
+ catch (RuntimeException re)
+ {
+ throw re;
+ }
+ }
+
+ public void commit() throws RollbackException, HeuristicMixedException,
+ HeuristicRollbackException, SecurityException, IllegalStateException,
SystemException
+ {
+ log.debug("committing JPA resource-local transaction");
+ javax.persistence.EntityTransaction delegate = getDelegate();
+ 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
+ javax.persistence.EntityTransaction delegate = getDelegate();
+ try
+ {
+ delegate.rollback();
+ }
+ finally
+ {
+ getSynchronizations().afterTransactionRollback();
+ }
+ }
+
+ public void setRollbackOnly() throws IllegalStateException, SystemException
+ {
+ log.debug("marking JPA resource-local transaction for rollback");
+ getDelegate().setRollbackOnly();
+ }
+
+ public int getStatus() throws SystemException
+ {
+ if (getDelegate().getRollbackOnly())
+ {
+ return Status.STATUS_MARKED_ROLLBACK;
+ }
+ else if (getDelegate().isActive())
+ {
+ return Status.STATUS_ACTIVE;
+ }
+ else
+ {
+ return Status.STATUS_NO_TRANSACTION;
+ }
+ }
+
+ public void setTransactionTimeout(int timeout) throws SystemException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void registerSynchronization(Synchronization sync)
+ {
+ if ( log.isDebugEnabled() )
+ {
+ log.debug("registering synchronization: " + sync);
+ }
+ //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;
+ }
+
+ @Override
+ public void enlist(EntityManager entityManager)
+ {
+ //no-op
+ }
+
+}
Modified:
modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/Transaction.java
===================================================================
---
modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/Transaction.java 2010-07-16
21:51:51 UTC (rev 13414)
+++
modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/Transaction.java 2010-07-16
22:31:47 UTC (rev 13415)
@@ -1,7 +1,6 @@
package org.jboss.seam.transaction;
import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;
@@ -22,7 +21,6 @@
@Inject
Synchronizations synchronizations;
- @Produces
public UserTransaction getTransaction() throws NamingException
{
try
Modified:
modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/TransactionExtension.java
===================================================================
---
modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/TransactionExtension.java 2010-07-16
21:51:51 UTC (rev 13414)
+++
modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/TransactionExtension.java 2010-07-16
22:31:47 UTC (rev 13415)
@@ -1,12 +1,162 @@
package org.jboss.seam.transaction;
+import java.lang.annotation.Annotation;
+import java.util.Collections;
+import java.util.Set;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Default;
+import javax.enterprise.inject.spi.AfterBeanDiscovery;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.enterprise.inject.spi.Extension;
+import javax.enterprise.inject.spi.InjectionPoint;
+import javax.enterprise.inject.spi.InjectionTarget;
+import javax.enterprise.inject.spi.ProcessBean;
+import javax.naming.NamingException;
+
+import org.jboss.weld.extensions.annotated.AnnotatedTypeBuilder;
+import org.jboss.weld.extensions.bean.BeanBuilder;
+import org.jboss.weld.extensions.bean.BeanImpl;
+import org.jboss.weld.extensions.bean.BeanLifecycle;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
- * Extension than provides a {@link UserTransaction}
+ * Extension than provides a {@link UserTransaction} if no other UserTransaction
+ * has been registered.
*
- * @author stuart
+ * This allows the user to register a transaction via seam XML and have it
+ * automatically replace the default UserTransaction implementation
*
+ * This is not done with alternatives, because that would require specifying the
+ * transaction manager on a per module basis, and some of the UserTransaction
+ * implementations need to be configured via seam xml anyway, so they would have
+ * to be configured twice
+ *
+ * @author Stuart Douglas
+ *
*/
-public class TransactionExtension
+public class TransactionExtension implements Extension
{
+ private boolean transactionRegistered = false;
+ private static final Logger log =
LoggerFactory.getLogger(TransactionExtension.class);
+
+ public void processBean(@Observes ProcessBean<?> event)
+ {
+ Bean<?> bean = event.getBean();
+ if (bean.getTypes().contains(UserTransaction.class))
+ {
+ if (bean.getQualifiers().isEmpty()) // not sure about this
+ {
+ transactionRegistered = true;
+ }
+ else
+ {
+ for (Annotation a : event.getBean().getQualifiers())
+ {
+ if (a.annotationType() == Default.class)
+ {
+ transactionRegistered = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ public void afterBeanDiscovery(@Observes AfterBeanDiscovery event, BeanManager
manager)
+ {
+ if (!transactionRegistered)
+ {
+ AnnotatedTypeBuilder<UserTransaction> utbuilder =
AnnotatedTypeBuilder.newInstance(UserTransaction.class);
+ BeanBuilder<UserTransaction> builder = new
BeanBuilder<UserTransaction>(utbuilder.create(), manager);
+ builder.defineBeanFromAnnotatedType();
+
+ Set<Bean<?>> beans = manager.getBeans(Transaction.class);
+ if (beans.isEmpty())
+ {
+ log.error("No bean with type " + Transaction.class.getName() +
" registered, SEAM TRANSACTIONS ARE DISABLED");
+ }
+ else if (beans.size() > 1)
+ {
+ log.error("More than 1 bean with type " +
Transaction.class.getName() + " registered, SEAM TRANSACTIONS ARE DISABLED");
+ }
+ Bean<?> bean = beans.iterator().next();
+ builder.setBeanLifecycle(new TransactionLifecycle(manager, (Bean) bean));
+ builder.setInjectionTarget(new NoOpInjectionTarget());
+ event.addBean(builder.create());
+ }
+ }
+
+ private static class TransactionLifecycle implements
BeanLifecycle<UserTransaction>
+ {
+
+ private final BeanManager manager;
+
+ private final Bean<Transaction> transactionBean;
+
+ public TransactionLifecycle(BeanManager manager, Bean<Transaction>
transactionBean)
+ {
+ this.manager = manager;
+ this.transactionBean = transactionBean;
+
+ }
+
+ public UserTransaction create(BeanImpl<UserTransaction> bean,
CreationalContext<UserTransaction> ctx)
+ {
+ Transaction t = (Transaction) manager.getReference(transactionBean,
Transaction.class, ctx);
+ try
+ {
+ return t.getTransaction();
+ }
+ catch (NamingException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void destroy(BeanImpl<UserTransaction> bean, UserTransaction arg0,
CreationalContext<UserTransaction> arg1)
+ {
+ arg1.release();
+ }
+
+ }
+
+ private static class NoOpInjectionTarget implements
InjectionTarget<UserTransaction>
+ {
+
+ public UserTransaction produce(CreationalContext<UserTransaction> ctx)
+ {
+ return null;
+ }
+
+ public Set<InjectionPoint> getInjectionPoints()
+ {
+ return Collections.EMPTY_SET;
+ }
+
+ public void dispose(UserTransaction instance)
+ {
+
+ }
+
+ public void preDestroy(UserTransaction instance)
+ {
+
+ }
+
+ public void postConstruct(UserTransaction instance)
+ {
+
+ }
+
+ public void inject(UserTransaction instance,
CreationalContext<UserTransaction> ctx)
+ {
+
+ }
+
+ }
}
Modified:
modules/persistence/trunk/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension
===================================================================
---
modules/persistence/trunk/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension 2010-07-16
21:51:51 UTC (rev 13414)
+++
modules/persistence/trunk/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension 2010-07-16
22:31:47 UTC (rev 13415)
@@ -1 +1,2 @@
org.jboss.seam.persistence.PersistenceContextExtension
+org.jboss.seam.transaction.TransactionExtension
\ No newline at end of file
Modified:
modules/persistence/trunk/src/test/java/org/jboss/seam/transactions/test/TransactionInterceptorTest.java
===================================================================
---
modules/persistence/trunk/src/test/java/org/jboss/seam/transactions/test/TransactionInterceptorTest.java 2010-07-16
21:51:51 UTC (rev 13414)
+++
modules/persistence/trunk/src/test/java/org/jboss/seam/transactions/test/TransactionInterceptorTest.java 2010-07-16
22:31:47 UTC (rev 13415)
@@ -42,7 +42,7 @@
war.addClasses(TransactionInterceptorTest.class, TransactionManagedBean.class,
Hotel.class, EntityManagerProvider.class, DontRollBackException.class,
TransactionObserver.class);
war.addWebResource("META-INF/persistence.xml",
"classes/META-INF/persistence.xml");
war.addWebResource(new
ByteArrayAsset(("<beans><interceptors><class>" +
TransactionInterceptor.class.getName() +
"</class></interceptors></beans>").getBytes()),
"beans.xml");
-
+
war.addWebResource("META-INF/services/javax.enterprise.inject.spi.Extension",
"classes/META-INF/services/javax.enterprise.inject.spi.Extension");
return war;
}
Modified:
modules/persistence/trunk/src/test/java/org/jboss/seam/transactions/test/UserTransactionTest.java
===================================================================
---
modules/persistence/trunk/src/test/java/org/jboss/seam/transactions/test/UserTransactionTest.java 2010-07-16
21:51:51 UTC (rev 13414)
+++
modules/persistence/trunk/src/test/java/org/jboss/seam/transactions/test/UserTransactionTest.java 2010-07-16
22:31:47 UTC (rev 13415)
@@ -39,7 +39,7 @@
war.addPackage(Transaction.class.getPackage()).addClasses(UserTransactionTest.class,
Hotel.class);
war.addWebResource("META-INF/persistence.xml",
"classes/META-INF/persistence.xml");
war.addWebResource(new ByteArrayAsset(new byte[0]), "beans.xml");
-
+
war.addWebResource("META-INF/services/javax.enterprise.inject.spi.Extension",
"classes/META-INF/services/javax.enterprise.inject.spi.Extension");
return war;
}