You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by gp...@apache.org on 2010/10/14 12:05:50 UTC

svn commit: r1022451 - in /myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl: EntityManagerEntry.java PersistenceContextMetaEntry.java TransactionalInterceptor.java

Author: gpetracek
Date: Thu Oct 14 10:05:49 2010
New Revision: 1022451

URL: http://svn.apache.org/viewvc?rev=1022451&view=rev
Log:
EXTCDI-4 support for extended persistence contexts (in combination with add-ons)

Added:
    myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/EntityManagerEntry.java
    myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/PersistenceContextMetaEntry.java
Modified:
    myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/TransactionalInterceptor.java

Added: myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/EntityManagerEntry.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/EntityManagerEntry.java?rev=1022451&view=auto
==============================================================================
--- myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/EntityManagerEntry.java (added)
+++ myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/EntityManagerEntry.java Thu Oct 14 10:05:49 2010
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.extensions.cdi.jpa.impl;
+
+import javax.persistence.EntityManager;
+
+/**
+ * separated from {@link PersistenceContextMetaEntry}
+ * to allow the usage of {@link PersistenceContextMetaEntry} in the cache
+ * (without a reference to the entity manager)
+ * 
+ * @author Gerhard Petracek
+ */
+class EntityManagerEntry
+{
+    private EntityManager entityManager;
+    private PersistenceContextMetaEntry persistenceContextEntry;
+
+    EntityManagerEntry(EntityManager entityManager, PersistenceContextMetaEntry persistenceContextEntry)
+    {
+        this.entityManager = entityManager;
+        this.persistenceContextEntry = persistenceContextEntry;
+    }
+
+    EntityManager getEntityManager()
+    {
+        return entityManager;
+    }
+
+    PersistenceContextMetaEntry getPersistenceContextEntry()
+    {
+        return persistenceContextEntry;
+    }
+}

Added: myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/PersistenceContextMetaEntry.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/PersistenceContextMetaEntry.java?rev=1022451&view=auto
==============================================================================
--- myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/PersistenceContextMetaEntry.java (added)
+++ myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/PersistenceContextMetaEntry.java Thu Oct 14 10:05:49 2010
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.extensions.cdi.jpa.impl;
+
+/**
+ * @author Gerhard Petracek
+ */
+class PersistenceContextMetaEntry
+{
+    private String fieldName;
+
+    private boolean extended;
+
+    PersistenceContextMetaEntry(String fieldName, boolean extended)
+    {
+        this.fieldName = fieldName;
+        this.extended = extended;
+    }
+
+    String getFieldName()
+    {
+        return fieldName;
+    }
+
+    boolean isExtended()
+    {
+        return extended;
+    }
+}

Modified: myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/TransactionalInterceptor.java
URL: http://svn.apache.org/viewvc/myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/TransactionalInterceptor.java?rev=1022451&r1=1022450&r2=1022451&view=diff
==============================================================================
--- myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/TransactionalInterceptor.java (original)
+++ myfaces/extensions/cdi/trunk/jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/TransactionalInterceptor.java Thu Oct 14 10:05:49 2010
@@ -33,6 +33,7 @@ import javax.interceptor.InvocationConte
 import javax.persistence.EntityManager;
 import javax.persistence.EntityTransaction;
 import javax.persistence.PersistenceContext;
+import javax.persistence.PersistenceContextType;
 import java.io.Serializable;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
@@ -53,6 +54,8 @@ import java.util.logging.Logger;
 @Transactional
 public class TransactionalInterceptor implements Serializable
 {
+    private static final long serialVersionUID = -812054233068559930L;
+
     //don't use final in interceptors
     private static String noFieldMarker = TransactionalInterceptor.class.getName() + ":DEFAULT_FIELD";
 
@@ -65,8 +68,8 @@ public class TransactionalInterceptor im
     private static transient ThreadLocal<HashMap<String, EntityManager>> ems =
             new ThreadLocal<HashMap<String, EntityManager>>();
 
-    private static transient Map<ClassLoader, Map<String, String>> entityManagerFields =
-            new ConcurrentHashMap<ClassLoader, Map<String, String>>();
+    private static transient Map<ClassLoader, Map<String, PersistenceContextMetaEntry>> entityManagerFields =
+            new ConcurrentHashMap<ClassLoader, Map<String, PersistenceContextMetaEntry>>();
 
     public class AnyLiteral extends AnnotationLiteral<Any> implements Any
     {
@@ -113,11 +116,13 @@ public class TransactionalInterceptor im
             }
         }
 
+        EntityManagerEntry entityManagerEntry = null;
         EntityManager entityManager;
 
         if (bean == null)
         {
-            entityManager = tryToFindEntityManagerOfTarget(context.getTarget());
+            entityManagerEntry = tryToFindEntityManagerEntryInTarget(context.getTarget());
+            entityManager = entityManagerEntry.getEntityManager();
 
             //might happen due to special add-ons - don't change it!
             if(entityManager == null)
@@ -144,166 +149,175 @@ public class TransactionalInterceptor im
             refCount.set(new AtomicInteger(0));
         }
 
-        EntityTransaction transaction = entityManager.getTransaction();
+        synchronized (entityManager)
+        {
+            EntityTransaction transaction = entityManager.getTransaction();
 
-        // used to store any exception we get from the services
-        Exception firstException = null;
+            // used to store any exception we get from the services
+            Exception firstException = null;
 
-        try
-        {
-            if(!transaction.isActive())
+            try
             {
-                transaction.begin();
-            }
-            refCount.get().incrementAndGet();
-
-            return context.proceed();
+                if(!transaction.isActive())
+                {
+                    transaction.begin();
+                }
+                refCount.get().incrementAndGet();
 
-        }
-        catch(Exception e)
-        {
-            firstException = e;
+                return context.proceed();
 
-            // we only cleanup and rollback all open transactions in the outermost interceptor!
-            // this way, we allow inner functions to catch and handle exceptions properly.
-            if (refCount.get().intValue() == 1)
+            }
+            catch(Exception e)
             {
-                for (EntityManager em: ems.get().values())
+                firstException = e;
+
+                // we only cleanup and rollback all open transactions in the outermost interceptor!
+                // this way, we allow inner functions to catch and handle exceptions properly.
+                if (refCount.get().intValue() == 1)
                 {
-                    transaction = em.getTransaction();
-                    if (transaction != null && transaction.isActive())
+                    for (EntityManager em: ems.get().values())
                     {
-                        try
-                        {
-                            transaction.rollback();
-                        }
-                        catch (Exception eRollback)
+                        transaction = em.getTransaction();
+                        if (transaction != null && transaction.isActive())
                         {
-                            logger.log(Level.SEVERE, "Got additional Exception while subsequently " +
-                                       "rolling back other SQL transactions", eRollback);
-                        }
+                            try
+                            {
+                                transaction.rollback();
+                            }
+                            catch (Exception eRollback)
+                            {
+                                logger.log(Level.SEVERE, "Got additional Exception while subsequently " +
+                                        "rolling back other SQL transactions", eRollback);
+                            }
 
+                        }
                     }
-                }
 
-                refCount.remove();
+                    refCount.remove();
 
-                // drop all EntityManagers from the ThreadLocal
-                ems.remove();
-            }
+                    // drop all EntityManagers from the ThreadLocal
+                    ems.remove();
+                }
 
-            // rethrow the exception
-            throw e;
+                // rethrow the exception
+                throw e;
 
-        }
-        finally
-        {
-            if (refCount.get() != null)
+            }
+            finally
             {
-                refCount.get().decrementAndGet();
-
+                if (refCount.get() != null)
+                {
+                    refCount.get().decrementAndGet();
 
-                // will get set if we got an Exception while committing
-                // in this case, we rollback all later transactions too.
-                boolean commitFailed = false;
 
-                // commit all open transactions in the outermost interceptor!
-                // this is a 'JTA for poor men' only, and will not guaranty
-                // commit stability over various databases!
-                if (refCount.get().intValue() == 0)
-                {
+                    // will get set if we got an Exception while committing
+                    // in this case, we rollback all later transactions too.
+                    boolean commitFailed = false;
 
-                    // only commit all transactions if we didn't rollback
-                    // them already
-                    if (firstException == null)
+                    // commit all open transactions in the outermost interceptor!
+                    // this is a 'JTA for poor men' only, and will not guaranty
+                    // commit stability over various databases!
+                    if (refCount.get().intValue() == 0)
                     {
-                        for (EntityManager em: ems.get().values())
+
+                        // only commit all transactions if we didn't rollback
+                        // them already
+                        if (firstException == null)
                         {
-                            transaction = em.getTransaction();
-                            if(transaction != null && transaction.isActive())
+                            for (EntityManager em: ems.get().values())
                             {
-                                try
+                                transaction = em.getTransaction();
+                                if(transaction != null && transaction.isActive())
                                 {
-                                    if (!commitFailed)
+                                    try
                                     {
-                                        transaction.commit();
+                                        if (!commitFailed)
+                                        {
+                                            transaction.commit();
+                                        }
+                                        else
+                                        {
+                                            transaction.rollback();
+                                        }
                                     }
-                                    else
+                                    catch (Exception e)
                                     {
-                                        transaction.rollback();
+                                        firstException = e;
+                                        commitFailed = true;
                                     }
                                 }
-                                catch (Exception e)
-                                {
-                                    firstException = e;
-                                    commitFailed = true;
-                                }
                             }
                         }
-                    }
 
-                    // finally remove all ThreadLocals
-                    refCount.remove();
-                    ems.remove();
-                    if (commitFailed)
-                    {
-                        throw firstException;
+                        // finally remove all ThreadLocals
+                        refCount.remove();
+                        ems.remove();
+                        if (commitFailed)
+                        {
+                            throw firstException;
+                        }
+                        else
+                        {
+                            //commit was successful and entity manager of bean was used
+                            //(and not an entity manager of a producer) which isn't of type extended
+                            if(entityManagerEntry != null && entityManager != null && entityManager.isOpen() &&
+                                    !entityManagerEntry.getPersistenceContextEntry().isExtended())
+                            {
+                                entityManager.clear();
+                            }
+                        }
                     }
                 }
-
             }
         }
-
     }
 
     /*
      * needed for special add-ons - don't change it!
      */
-    private EntityManager tryToFindEntityManagerOfTarget(Object target)
+    private EntityManagerEntry tryToFindEntityManagerEntryInTarget(Object target)
     {
-        Map<String, String> mapping = entityManagerFields.get(getClassLoader());
+        Map<String, PersistenceContextMetaEntry> mapping = entityManagerFields.get(getClassLoader());
 
         mapping = initMapping(mapping);
 
         String key = target.getClass().getName();
-        String targetFieldName = mapping.get(key);
+        PersistenceContextMetaEntry persistenceContextEntry = mapping.get(key);
 
-        if(noFieldMarker.equals(targetFieldName))
+        if( persistenceContextEntry != null && noFieldMarker.equals(persistenceContextEntry.getFieldName()))
         {
             return null;
         }
 
-        Field entityManagerField = null;
-        if(targetFieldName == null)
+        if(persistenceContextEntry == null)
         {
-            entityManagerField = findEntityManagerField(target.getClass());
+            persistenceContextEntry = findPersistenceContextEntry(target.getClass());
 
-            if(entityManagerField == null)
+            if(persistenceContextEntry == null)
             {
-                mapping.put(key, noFieldMarker);
+                mapping.put(key, new PersistenceContextMetaEntry(noFieldMarker, false));
                 return null;
             }
 
-            mapping.put(key, entityManagerField.getName());
+            mapping.put(key, persistenceContextEntry);
         }
 
-        if(entityManagerField == null)
+        Field entityManagerField;
+        try
         {
-            try
-            {
-                entityManagerField = target.getClass().getDeclaredField(targetFieldName);
-            }
-            catch (NoSuchFieldException e)
-            {
-                //TODO add logging in case of project stage dev.
-                return null;
-            }
+            entityManagerField = target.getClass().getDeclaredField(persistenceContextEntry.getFieldName());
+        }
+        catch (NoSuchFieldException e)
+        {
+            //TODO add logging in case of project stage dev.
+            return null;
         }
 
         entityManagerField.setAccessible(true);
         try
         {
-            return (EntityManager)entityManagerField.get(target);
+            EntityManager entityManager = (EntityManager)entityManagerField.get(target);
+            return new EntityManagerEntry(entityManager, persistenceContextEntry);
         }
         catch (IllegalAccessException e)
         {
@@ -312,27 +326,31 @@ public class TransactionalInterceptor im
         }
     }
 
-    private synchronized Map<String, String> initMapping(Map<String, String> mapping)
+    private synchronized Map<String, PersistenceContextMetaEntry> initMapping(
+            Map<String, PersistenceContextMetaEntry> mapping)
     {
         if(mapping == null)
         {
-            mapping = new ConcurrentHashMap<String, String>();
+            mapping = new ConcurrentHashMap<String, PersistenceContextMetaEntry>();
             entityManagerFields.put(getClassLoader(), mapping);
         }
         return mapping;
     }
 
-    private Field findEntityManagerField(Class target)
+    private PersistenceContextMetaEntry findPersistenceContextEntry(Class target)
     {
         //TODO support other injection types
         Class currentParamClass = target;
+        PersistenceContext persistenceContext;
         while (currentParamClass != null && !Object.class.getName().equals(currentParamClass.getName()))
         {
             for(Field currentField : target.getDeclaredFields())
             {
-                if(currentField.isAnnotationPresent(PersistenceContext.class))
+                persistenceContext = currentField.getAnnotation(PersistenceContext.class);
+                if(persistenceContext != null)
                 {
-                    return currentField;
+                    return new PersistenceContextMetaEntry(
+                            currentField.getName(), PersistenceContextType.EXTENDED.equals(persistenceContext.type()));
                 }
             }
             currentParamClass = currentParamClass.getSuperclass();
@@ -345,4 +363,4 @@ public class TransactionalInterceptor im
     {
         return ClassUtils.getClassLoader(null);
     }
-}
\ No newline at end of file
+}