You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by cs...@apache.org on 2014/09/26 17:49:55 UTC

svn commit: r1627814 - in /aries/trunk/jpa/jpa-container-context: ./ src/main/java/org/apache/aries/jpa/container/context/impl/ src/main/java/org/apache/aries/jpa/container/context/transaction/impl/

Author: cschneider
Date: Fri Sep 26 15:49:55 2014
New Revision: 1627814

URL: http://svn.apache.org/r1627814
Log:
ARIES-1251 Support jpa2.0 and 2.1 with same code base

Added:
    aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManagerHandler.java
Removed:
    aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManager.java
Modified:
    aries/trunk/jpa/jpa-container-context/pom.xml
    aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java

Modified: aries/trunk/jpa/jpa-container-context/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container-context/pom.xml?rev=1627814&r1=1627813&r2=1627814&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container-context/pom.xml (original)
+++ aries/trunk/jpa/jpa-container-context/pom.xml Fri Sep 26 15:49:55 2014
@@ -71,7 +71,7 @@
         </dependency>
         <dependency>
             <groupId>org.hibernate.javax.persistence</groupId>
-            <artifactId>hibernate-jpa-2.1-api</artifactId>
+            <artifactId>hibernate-jpa-2.0-api</artifactId>
             <version>1.0.0.Final</version>
             <scope>provided</scope>
         </dependency>

Modified: aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java?rev=1627814&r1=1627813&r2=1627814&view=diff
==============================================================================
--- aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java (original)
+++ aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/impl/ManagedPersistenceContextFactory.java Fri Sep 26 15:49:55 2014
@@ -18,6 +18,7 @@
  */
 package org.apache.aries.jpa.container.context.impl;
 
+import java.lang.reflect.Proxy;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.HashMap;
@@ -25,17 +26,21 @@ import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 
-import javax.persistence.*;
+import javax.persistence.Cache;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceContextType;
+import javax.persistence.PersistenceUnitUtil;
+import javax.persistence.Query;
 import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.metamodel.Metamodel;
 
 import org.apache.aries.jpa.container.context.PersistenceContextProvider;
-import org.apache.aries.jpa.container.sync.Synchronization;
 import org.apache.aries.jpa.container.context.impl.PersistenceContextManager.QuiesceTidyUp;
 import org.apache.aries.jpa.container.context.transaction.impl.DestroyCallback;
-import org.apache.aries.jpa.container.context.transaction.impl.JTAEntityManager;
+import org.apache.aries.jpa.container.context.transaction.impl.JTAEntityManagerHandler;
 import org.apache.aries.jpa.container.context.transaction.impl.JTAPersistenceContextRegistry;
-import org.osgi.framework.Bundle;
+import org.apache.aries.jpa.container.sync.Synchronization;
 import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -48,6 +53,7 @@ import org.slf4j.LoggerFactory;
  * <p/>
  * Also this class receives a callback on cleanup
  */
+@SuppressWarnings({"rawtypes", "unchecked"})
 public class ManagedPersistenceContextFactory implements Synchronization, EntityManagerFactory, DestroyCallback {
     /**
      * Logger
@@ -60,7 +66,7 @@ public class ManagedPersistenceContextFa
     private final PersistenceContextType type;
     private final AtomicLong activeCount = new AtomicLong(0);
     private final String unitName;
-    private final JTAEntityManager em;
+    private final EntityManager em;
 
     private final AtomicReference<QuiesceTidyUp> tidyUp = new AtomicReference<QuiesceTidyUp>();
 
@@ -81,9 +87,12 @@ public class ManagedPersistenceContextFa
                         return (EntityManagerFactory) emf.getBundle().getBundleContext().getService(emf);
                     }
                 });
-        em = new JTAEntityManager(factory, properties, registry, activeCount, this);
+        JTAEntityManagerHandler invocationHandler = new JTAEntityManagerHandler(factory, properties, registry, activeCount, this);
+        ClassLoader cl = this.getClass().getClassLoader();
+        Class<?>[] ifAr = new Class[] { Synchronization.class, EntityManager.class }; 
+        em = (EntityManager)Proxy.newProxyInstance(cl, ifAr, invocationHandler);
     }
-
+    
     public EntityManager createEntityManager() {
         if (_logger.isDebugEnabled()) {
             _logger.debug("Creating a container managed entity manager for the perstence unit {} with the following properties {}",
@@ -101,12 +110,12 @@ public class ManagedPersistenceContextFa
 
     @Override
     public void preCall() {
-        em.preCall();
+        ((Synchronization)em).preCall();
     }
 
     @Override
     public void postCall() {
-        em.postCall();
+        ((Synchronization)em).postCall();
     }
 
     public void close() {
@@ -162,22 +171,10 @@ public class ManagedPersistenceContextFa
         }
     }
 
-    public <T> void addNamedEntityGraph(String arg0, EntityGraph<T> arg1) {
-        throw new UnsupportedOperationException();
-    }
-
     public void addNamedQuery(String arg0, Query arg1) {
         throw new UnsupportedOperationException();
     }
 
-    public EntityManager createEntityManager(SynchronizationType arg0) {
-        throw new UnsupportedOperationException();
-    }
-
-    public EntityManager createEntityManager(SynchronizationType arg0, Map arg1) {
-        throw new UnsupportedOperationException();
-    }
-
     public <T> T unwrap(Class<T> arg0) {
         throw new UnsupportedOperationException();
     }

Added: aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManagerHandler.java
URL: http://svn.apache.org/viewvc/aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManagerHandler.java?rev=1627814&view=auto
==============================================================================
--- aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManagerHandler.java (added)
+++ aries/trunk/jpa/jpa-container-context/src/main/java/org/apache/aries/jpa/container/context/transaction/impl/JTAEntityManagerHandler.java Fri Sep 26 15:49:55 2014
@@ -0,0 +1,167 @@
+package org.apache.aries.jpa.container.context.transaction.impl;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.LockModeType;
+import javax.persistence.TransactionRequiredException;
+
+import org.apache.aries.jpa.container.context.impl.NLS;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JTAEntityManagerHandler implements InvocationHandler {
+    private static final String[] TRANSACTED_METHODS = {"flush", "lock", "merge", "isJoinedToTransaction", "persist", "remove", "getLockMode", "lock", "refresh"};
+    
+    /**
+     * Logger
+     */
+    private static final Logger _logger = LoggerFactory.getLogger("org.apache.aries.jpa.container.context");
+    
+    private Set<String> transactedMethods = new HashSet<String>(Arrays.asList(TRANSACTED_METHODS));
+
+    /**
+     * The {@link EntityManagerFactory} that can create new {@link EntityManager} instances
+     */
+    private final EntityManagerFactory emf;
+    /**
+     * The map of properties to pass when creating EntityManagers
+     */
+    private final Map<String, Object> props;
+    /**
+     * A registry for creating new persistence contexts
+     */
+    private final JTAPersistenceContextRegistry reg;
+    /**
+     * The number of EntityManager instances that are open
+     */
+    private final AtomicLong instanceCount;
+    /**
+     * A callback for when we're quiescing
+     */
+    private final DestroyCallback callback;
+
+
+    private final ThreadLocal<AtomicInteger> activeCalls = new ThreadLocal<AtomicInteger>() {
+        @Override
+        protected AtomicInteger initialValue() {
+            return new AtomicInteger(0);
+        }
+    };
+
+    private final ThreadLocal<EntityManager> activeManager = new ThreadLocal<EntityManager>();
+
+    private final ConcurrentLinkedQueue<EntityManager> pool = new ConcurrentLinkedQueue<EntityManager>();
+    
+    public JTAEntityManagerHandler(EntityManagerFactory factory,
+                            Map<String, Object> properties, JTAPersistenceContextRegistry registry, AtomicLong activeCount,
+                            DestroyCallback onDestroy) {
+        emf = factory;
+        props = properties;
+        reg = registry;
+        instanceCount = activeCount;
+        callback = onDestroy;
+    }
+
+    public void preCall() {
+        activeCalls.get().incrementAndGet();
+    }
+
+    public void postCall() {
+        if (activeCalls.get().decrementAndGet() == 0) {
+            EntityManager manager = activeManager.get();
+            if (manager != null) {
+                activeManager.set(null);
+                manager.clear();
+                pool.add(manager);
+            }
+        }
+    }
+    
+    /**
+     * Get the target persistence context
+     *
+     * @param forceTransaction Whether the returned entity manager needs to be bound to a transaction
+     * @return
+     * @throws TransactionRequiredException if forceTransaction is true and no transaction is available
+     */
+    private EntityManager getPersistenceContext(boolean forceTransaction) {
+        if (forceTransaction) {
+            EntityManager manager = activeManager.get();
+            if (manager != null) {
+                manager.clear();
+            }
+            return reg.getCurrentPersistenceContext(emf, props, instanceCount, callback);
+        } else {
+            if (reg.isTransactionActive()) {
+                EntityManager manager = activeManager.get();
+                if (manager != null) {
+                    manager.clear();
+                }
+                return reg.getCurrentPersistenceContext(emf, props, instanceCount, callback);
+            } else {
+                if (!!!reg.jtaIntegrationAvailable() && _logger.isDebugEnabled())
+                    _logger.debug("No integration with JTA transactions is available. No transaction context is active.");
+
+                EntityManager manager = activeManager.get();
+                if (manager == null) {
+                    manager = pool.poll();
+                    if (manager == null) {
+                        manager = emf.createEntityManager(props);
+                    }
+                    activeManager.set(manager);
+                }
+                return manager;
+            }
+        }
+    }
+
+    /**
+     * Called reflectively by blueprint
+     */
+    public void internalClose() {
+        EntityManager temp;
+        while ((temp = pool.poll()) != null) {
+            temp.close();
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        if ("close".equals(method.getName())) {
+            throw new IllegalStateException(NLS.MESSAGES.getMessage("close.called.on.container.manged.em"));
+        }
+        if ("getTransaction".equals(method.getName())) {
+            throw new IllegalStateException(NLS.MESSAGES.getMessage("getTransaction.called.on.container.managed.em"));
+        }
+        if ("isOpen".equals(method.getName())) {
+            return true;
+        }
+        if ("joinTransaction".equals(method.getName())) {
+            // This should be a no-op for a JTA entity manager
+            return null;
+        }
+        
+        boolean forceTransaction = transactedMethods.contains(method.getName());
+        
+        if ("joinTransaction".equals(method.getName())) {
+            forceTransaction = args[2] != LockModeType.NONE;
+        }
+        
+        EntityManager delegate = getPersistenceContext(forceTransaction); 
+        Object res = method.invoke(delegate, args);
+        return res;
+
+    }
+
+}