[seam-commits] Seam SVN: r12350 - in modules/persistence/trunk: src/main/java/org/jboss/seam and 4 other directories.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Thu Apr 1 02:13:38 EDT 2010


Author: dan.j.allen
Date: 2010-04-01 02:13:37 -0400 (Thu, 01 Apr 2010)
New Revision: 12350

Added:
   modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/
   modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/JtaTxInterceptor.java
   modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/TransactionPropagation.java
   modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/Transactional.java
   modules/persistence/trunk/src/main/resources/META-INF/beans.xml
Modified:
   modules/persistence/trunk/pom.xml
   modules/persistence/trunk/src/main/java/org/jboss/seam/persistence/PersistenceContextExtension.java
   modules/persistence/trunk/src/test/java/org/jboss/seam/persistence/PersistenceContextExtensionTest.java
Log:
commit incremental changes; nothing guarnateed to work yet


Modified: modules/persistence/trunk/pom.xml
===================================================================
--- modules/persistence/trunk/pom.xml	2010-04-01 05:46:09 UTC (rev 12349)
+++ modules/persistence/trunk/pom.xml	2010-04-01 06:13:37 UTC (rev 12350)
@@ -56,9 +56,17 @@
       </dependency>
 
       <dependency>
+         <groupId>org.slf4j</groupId>
+         <artifactId>slf4j-api</artifactId>
+         <scope>provided</scope>
+      </dependency>
+
+      <dependency>
          <groupId>org.jboss.weld</groupId>
          <artifactId>weld-core-test</artifactId>
+         <scope>test</scope>
       </dependency>
+
    </dependencies>
 
    

Modified: modules/persistence/trunk/src/main/java/org/jboss/seam/persistence/PersistenceContextExtension.java
===================================================================
--- modules/persistence/trunk/src/main/java/org/jboss/seam/persistence/PersistenceContextExtension.java	2010-04-01 05:46:09 UTC (rev 12349)
+++ modules/persistence/trunk/src/main/java/org/jboss/seam/persistence/PersistenceContextExtension.java	2010-04-01 06:13:37 UTC (rev 12350)
@@ -3,7 +3,9 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 import javax.enterprise.context.ApplicationScoped;
@@ -26,17 +28,28 @@
 import javax.persistence.EntityManagerFactory;
 import javax.persistence.Persistence;
 import javax.persistence.PersistenceContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * Support for managed persistence contexts in Java SE environment.
+ * Support for managed persistence contexts in a Java SE environment or Servlet container.
+ *
+ * <p>Unlike with standard Java EE, the unitName attribute on {@link PersistenceContext} must
+ * be provided if the persistence unit is assigned a name in persistence.xml. This
+ * class supports multiple persistence units, but it does not permit multiple
+ * producers for the same persistence unit (naturally).</p>
  * 
  * @author Gavin King
- * 
+ * @author Dan Allen
  */
 public class PersistenceContextExtension implements Extension
 {
-   private Bean<EntityManagerFactory> emfBean;
+   private static final Logger log = LoggerFactory.getLogger(PersistenceContextExtension.class);
 
+   private Map<String, Bean<EntityManagerFactory>> emfBeans = new HashMap<String, Bean<EntityManagerFactory>>();
+
+   private Boolean bootstrapRequired;
+
    /**
     * For @PersistenceContext producer fields, make a bean for the EMF, then
     * wrap the producer CDI creates, to get the EM from the EMF bean we made
@@ -44,12 +57,31 @@
     */
    void processProducer(@Observes ProcessProducer<?, EntityManager> pp, final BeanManager bm)
    {
+      if (Boolean.FALSE.equals(bootstrapRequired))
+      {
+         return;
+      }
+      else if (bootstrapRequired == null)
+      {
+         if (isPersistenceContainerManaged())
+         {
+            bootstrapRequired = false;
+            return;
+         }
+         else
+         {
+            bootstrapRequired = true;
+            log.info("Java SE persistence bootstrap required");
+         }
+      }
+
       if (pp.getAnnotatedMember().isAnnotationPresent(PersistenceContext.class))
       {
-         if (emfBean == null)
+         AnnotatedField<?> field = (AnnotatedField<?>) pp.getAnnotatedMember();
+         final String unitName = field.getAnnotation(PersistenceContext.class).unitName();
+         if (!emfBeans.containsKey(unitName))
          {
-            AnnotatedField<?> field = (AnnotatedField<?>) pp.getAnnotatedMember();
-            final String unitName = field.getAnnotation(PersistenceContext.class).unitName();
+            log.info("Found persistence context producer for persistence unit: " + unitName);
             final Class<?> module = field.getJavaMember().getDeclaringClass();
             final Set<Annotation> qualifiers = new HashSet<Annotation>();
             for (Annotation ann : field.getAnnotations())
@@ -65,14 +97,12 @@
             {
                qualifiers.add(new AnnotationLiteral<Default>()
                {
-
                   /** default value. Added only to suppress compiler warnings. */
                   private static final long serialVersionUID = 1L;
                });
             }
             qualifiers.add(new AnnotationLiteral<Any>()
             {
-
                /** default value. Added only to suppress compiler warnings. */
                private static final long serialVersionUID = 1L;
             });
@@ -81,15 +111,14 @@
             {
                /** default value. Added only to suppress compiler warnings. */
                private static final long serialVersionUID = 1L;
-
                {
                   add(EntityManagerFactory.class);
                   add(Object.class);
                }
             };
 
-            // create a bean for the EMF
-            emfBean = new Bean<EntityManagerFactory>()
+            // create and register a bean for the EMF
+            emfBeans.put(unitName, new Bean<EntityManagerFactory>()
             {
                public Set<Type> getTypes()
                {
@@ -119,7 +148,6 @@
 
                public Set<InjectionPoint> getInjectionPoints()
                {
-                  // return Collections.EMPTY_SET;
                   return Collections.emptySet();
                }
 
@@ -135,7 +163,6 @@
 
                public Set<Class<? extends Annotation>> getStereotypes()
                {
-                  // return Collections.EMPTY_SET;
                   return Collections.emptySet();
 
                }
@@ -149,22 +176,19 @@
                {
                   return false;
                }
-            };
+            });
 
          }
          else
          {
-            throw new RuntimeException("Only one EMF per application is supported");
+            throw new RuntimeException("There can only be one producer per persistence unit");
          }
 
          Producer<EntityManager> producer = new Producer<EntityManager>()
          {
-
             public Set<InjectionPoint> getInjectionPoints()
             {
-               // return Collections.EMPTY_SET;
                return Collections.emptySet();
-
             }
 
             public EntityManager produce(CreationalContext<EntityManager> ctx)
@@ -174,13 +198,15 @@
 
             private EntityManagerFactory getFactory(CreationalContext<EntityManager> ctx)
             {
-               return (EntityManagerFactory) bm.getReference(emfBean, EntityManagerFactory.class, ctx);
+               return (EntityManagerFactory) bm.getReference(emfBeans.get(unitName), EntityManagerFactory.class, ctx);
             }
 
             public void dispose(EntityManager em)
             {
                if (em.isOpen()) // work around what I suspect is a bug in Weld
+               {
                   em.close();
+               }
             }
          };
          pp.setProducer(producer);
@@ -192,6 +218,39 @@
     */
    void afterBeanDiscovery(@Observes AfterBeanDiscovery abd)
    {
-      abd.addBean(emfBean);
+      for (Bean<EntityManagerFactory> emfBean : emfBeans.values())
+      {
+         abd.addBean(emfBean);
+      }
    }
+
+   /**
+    * Check whether persistence is container managed. For now, this simply
+    * checks for the presence of the EJB API. If it's present, we assume
+    * this is an EE environment and that persistence is container managed.
+    */
+   boolean isPersistenceContainerManaged() {
+      boolean eeEnv = true;
+      try
+      {
+         if (Thread.currentThread().getContextClassLoader() != null)
+         {
+            Thread.currentThread().getContextClassLoader().loadClass("javax.ejb.Stateless");
+         }
+         else
+         {
+            Class.forName("javax.ejb.Stateless");
+         }
+      }
+      catch (ClassNotFoundException e)
+      {
+         eeEnv = false;
+      }
+      catch (NoClassDefFoundError e)
+      {
+         eeEnv = false;
+      }
+
+      return eeEnv;
+   }
 }

Added: modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/JtaTxInterceptor.java
===================================================================
--- modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/JtaTxInterceptor.java	                        (rev 0)
+++ modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/JtaTxInterceptor.java	2010-04-01 06:13:37 UTC (rev 12350)
@@ -0,0 +1,123 @@
+package org.jboss.seam.transaction;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import javax.inject.Inject;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+import javax.transaction.Status;
+import javax.transaction.UserTransaction;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A rudimentary transaction interceptor implementation, intended as a proof
+ * of concept.
+ *
+ * @author Matt Corey
+ * @author Dan Allen
+ */
+public @Transactional @Interceptor class JtaTxInterceptor {
+
+   private static final Logger log = LoggerFactory.getLogger(JtaTxInterceptor.class);
+
+   @Inject private UserTransaction utx;
+
+   /**
+    * Super quick impl. Needs to be done correctly.
+    */
+   @AroundInvoke
+   public Object workInTransaction(InvocationContext ic) throws Exception {
+      // TODO cache this information
+      TransactionPropagation type = getTransactionPropagation(ic.getMethod());
+
+      int status = utx.getStatus();
+      boolean transactionActive = (status == Status.STATUS_ACTIVE || status == Status.STATUS_MARKED_ROLLBACK);
+      boolean beginTransaction = isNewTransactionRequired(type, transactionActive);
+
+      if (beginTransaction) {
+         log.debug("Beginning transaction");
+         utx.begin();
+      }
+
+      Object result = null;
+      try {
+         result = ic.proceed();
+
+         if (beginTransaction) {
+            if (utx.getStatus() == Status.STATUS_MARKED_ROLLBACK) {
+               log.debug("Rolling back transaction marked for rollback");
+               utx.rollback();
+            }
+            else {
+               log.debug("Committing transaction");
+               utx.commit();
+            }
+         }
+
+         return result;
+      } catch (Exception e) {
+         if (beginTransaction && utx.getStatus() != Status.STATUS_NO_TRANSACTION) {
+            // FIXME don't rollback if this is an application exception which indicates no rollback
+            log.debug("Rolling back transaction as the result of an exception");
+            utx.rollback();
+         }
+
+         throw e;
+      }
+   }
+
+    /**
+     * Get the TransactionPropagation value
+     * FIXME cache this information
+     */
+    private TransactionPropagation getTransactionPropagation(Method m) {
+       // first look at the explicit method-level annotation
+       if (m.isAnnotationPresent(Transactional.class)) {
+          return m.getAnnotation(Transactional.class).value();
+       }
+        // now look at the method-level meta-annotations
+        for (Annotation a: m.getAnnotations()) {
+            if (a.annotationType().isAnnotationPresent(Transactional.class)) {
+                return a.annotationType().getAnnotation(Transactional.class).value();
+            }
+        }
+        // now try the explicit class-level annotation
+        if (m.getDeclaringClass().isAnnotationPresent(Transactional.class)) {
+           return m.getDeclaringClass().getAnnotation(Transactional.class).value();
+        }
+        // finally, try the class-level meta-annotations
+        for (Annotation a: m.getDeclaringClass().getAnnotations()) {
+            if (a.annotationType().isAnnotationPresent(Transactional.class)) {
+                return a.annotationType().getAnnotation(Transactional.class).value();
+            }
+        }
+        return null;
+    }
+
+   private boolean isNewTransactionRequired(TransactionPropagation type, boolean transactionActive) {
+      switch (type) {
+         case REQUIRED:
+            return !transactionActive;
+         case SUPPORTS:
+            return false;
+         case MANDATORY:
+            if (!transactionActive) {
+               throw new IllegalStateException("No transaction active on call to method that requires a transaction.");
+            }
+            else {
+               return false;
+            }
+         case NEVER:
+            if (transactionActive) {
+               throw new IllegalStateException("Transaction active on call to method that does not support transactions.");
+            }
+            else {
+               return false;
+            }
+         default:
+            throw new IllegalArgumentException("Unknown transaction type " + type);
+      }
+   }
+}
\ No newline at end of file

Added: modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/TransactionPropagation.java
===================================================================
--- modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/TransactionPropagation.java	                        (rev 0)
+++ modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/TransactionPropagation.java	2010-04-01 06:13:37 UTC (rev 12350)
@@ -0,0 +1,8 @@
+package org.jboss.seam.transaction;
+
+/**
+ * @author Dan Allen
+ */
+public enum TransactionPropagation {
+   REQUIRED, SUPPORTS, MANDATORY, NEVER;
+}
\ No newline at end of file

Added: modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/Transactional.java
===================================================================
--- modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/Transactional.java	                        (rev 0)
+++ modules/persistence/trunk/src/main/java/org/jboss/seam/transaction/Transactional.java	2010-04-01 06:13:37 UTC (rev 12350)
@@ -0,0 +1,25 @@
+package org.jboss.seam.transaction;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.enterprise.util.Nonbinding;
+import javax.interceptor.InterceptorBinding;
+
+/**
+ * @author Dan Allen
+ */
+ at Inherited
+ at InterceptorBinding
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.METHOD, ElementType.TYPE})
+public @interface Transactional {
+   /**
+    * The transaction propagation type.
+    *
+    * @return REQUIRED by default
+    */
+   @Nonbinding TransactionPropagation value() default TransactionPropagation.REQUIRED;
+}
\ No newline at end of file

Added: modules/persistence/trunk/src/main/resources/META-INF/beans.xml
===================================================================
--- modules/persistence/trunk/src/main/resources/META-INF/beans.xml	                        (rev 0)
+++ modules/persistence/trunk/src/main/resources/META-INF/beans.xml	2010-04-01 06:13:37 UTC (rev 12350)
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   The contents of this file is permitted to be empty.
+   The schema definition is provided for your convenience.
+-->
+<beans xmlns="http://java.sun.com/xml/ns/javaee"
+   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="
+      http://java.sun.com/xml/ns/javaee 
+      http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
+</beans>

Modified: modules/persistence/trunk/src/test/java/org/jboss/seam/persistence/PersistenceContextExtensionTest.java
===================================================================
--- modules/persistence/trunk/src/test/java/org/jboss/seam/persistence/PersistenceContextExtensionTest.java	2010-04-01 05:46:09 UTC (rev 12349)
+++ modules/persistence/trunk/src/test/java/org/jboss/seam/persistence/PersistenceContextExtensionTest.java	2010-04-01 06:13:37 UTC (rev 12350)
@@ -1,12 +1,13 @@
 package org.jboss.seam.persistence;
 
-import org.jboss.weld.test.AbstractWeldTest;
+//import org.jboss.weld.test.AbstractWeldTest;
 import org.testng.annotations.Test;
 /**
  * Presently, this is just a placeholder. 
  */
 @Test
-public class PersistenceContextExtensionTest extends AbstractWeldTest
+public class PersistenceContextExtensionTest
+//extends AbstractWeldTest
 {
    public void helloWorld(){
 //      System.out.println("hello world");



More information about the seam-commits mailing list