[jboss-svn-commits] JBL Code SVN: r28146 - in labs/jbosstm/workspace/whitingjr/trunk/MVCCSampleSTM/src/main/java/uk/ac/ncl/sdia/a8905943: spec/entitymanager and 1 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Fri Jul 17 10:21:59 EDT 2009


Author: whitingjr
Date: 2009-07-17 10:21:59 -0400 (Fri, 17 Jul 2009)
New Revision: 28146

Modified:
   labs/jbosstm/workspace/whitingjr/trunk/MVCCSampleSTM/src/main/java/uk/ac/ncl/sdia/a8905943/entitymanager/STMEntityManagerFactoryImpl.java
   labs/jbosstm/workspace/whitingjr/trunk/MVCCSampleSTM/src/main/java/uk/ac/ncl/sdia/a8905943/spec/entitymanager/STMEntityManagerFactory.java
   labs/jbosstm/workspace/whitingjr/trunk/MVCCSampleSTM/src/main/java/uk/ac/ncl/sdia/a8905943/stm/persistence/STMPersistenceProviderImpl.java
Log:
Updated factory and provider classes.
Made the factory thread safe.

Modified: labs/jbosstm/workspace/whitingjr/trunk/MVCCSampleSTM/src/main/java/uk/ac/ncl/sdia/a8905943/entitymanager/STMEntityManagerFactoryImpl.java
===================================================================
--- labs/jbosstm/workspace/whitingjr/trunk/MVCCSampleSTM/src/main/java/uk/ac/ncl/sdia/a8905943/entitymanager/STMEntityManagerFactoryImpl.java	2009-07-17 14:21:19 UTC (rev 28145)
+++ labs/jbosstm/workspace/whitingjr/trunk/MVCCSampleSTM/src/main/java/uk/ac/ncl/sdia/a8905943/entitymanager/STMEntityManagerFactoryImpl.java	2009-07-17 14:21:59 UTC (rev 28146)
@@ -10,7 +10,6 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.naming.InitialContext;
-import javax.naming.NameAlreadyBoundException;
 import javax.naming.NameNotFoundException;
 import javax.naming.NamingException;
 import javax.persistence.EntityManager;
@@ -25,7 +24,7 @@
 import uk.ac.ncl.sdia.a8905943.stm.persistence.STMPersistenceProviderImpl;
 
 /** 
- * This object is responsible for choosing the transactional type, creating a persistence contxt, entity manager
+ * This object is responsible for validating the transactional type, creating a persistence context, entity manager
  * and providing the entity manager with the persistence context.
  * This implemenation creates a new instance of EntityManager for each request.
  * This factory will bind an object to the JNDI tree and remove it when asked to close.
@@ -43,13 +42,17 @@
     * EntityManager is created. Use it and treat it as read only.*/
    private volatile Map properties ;
    private static final Logger logger = Logger.getLogger(STMEntityManagerFactoryImpl.class);
-   // this field is an enum field
+   // enum field to indicate the type.
    private volatile PersistenceUnitTransactionType transactionType ;
    // immutable field
+   //TODO this field cannot be static, refactor necessary
    private volatile static IsolationLevel isolationLevel ;
    private volatile boolean isOpen = true;
-   private volatile STMPersistenceContext persistenceContext;
-   private volatile String persistenceContextName;
+   /* The peristence context is shared amongst threads so the instance here still 
+    * requires concurrent access controll.*/
+   private ThreadLocal<STMPersistenceContext> persistenceContext = new ThreadLocal<STMPersistenceContext>();
+   private ThreadLocal<String> persistenceContextName = new  ThreadLocal<String>(); 
+   
    private AtomicBoolean isPCnotBoundToJNDI = new AtomicBoolean(false);
    
    private static final String ERROR_MISSING_ISOLATION_LEVEL_PROPERTY = "Problem occured when creating an EntityManager. ISOLATION_LEVEL not configured.";
@@ -59,7 +62,6 @@
    private static final String ERROR_EMPTY_ISOLATION_LEVEL_VALUE = "Empty isolation value.";
    private static final String ERROR_NULL_PERSISTENCE_CONTEXT = "Persistence Context object is null and will cause a problem.";
    private static final String ERROR_NULL_PERSISTENCE_CONTEXT_NAME = "Persistence name is and will cause a problem.";
-   private static final String ERROR_FAILED_TO_BIND = "Failed to bind the persistence context to JNDI";
    private static final String ERROR_FAILED_TO_UNBIND = "Failed to unbind the persistence context from JNDI";
    private static final String WARN_PC_NOT_FOUND = "EntityManagerFactory attempted to unbind the Persistence Context and it could not be found.";
    private static final String WARN_ALREADY_CLOSED = "EntityManagerFactory is already closed and is being closed again.";
@@ -75,7 +77,7 @@
       try
       {
          InitialContext context = new InitialContext();
-         context.unbind(getBindingName(persistenceContextName));
+         context.unbind(getBindingName(persistenceContextName.get()));
       }
       catch (NameNotFoundException nnfe)
       {
@@ -162,25 +164,11 @@
          {    
             logger.info(INFO_ATTEMPTING_PC_BIND);
          }
-         try
-         {
-            InitialContext context = new InitialContext();
-            context.bind(this.persistenceContextName, this.persistenceContext);
-         } 
-         catch (NameAlreadyBoundException nabe)
-         {
-            // this is acceptable
-         }
-         catch (NamingException ne)
-         {
-            isPCnotBoundToJNDI.compareAndSet(true, false);
-            logger.error(ERROR_FAILED_TO_BIND, ne);
-            throw new RuntimeException(ERROR_FAILED_TO_BIND);
-         }
+         
       }
       
       // allow the persistence context to escape
-      return new STMEntityManagerImpl(this.persistenceContext);
+      return new STMEntityManagerImpl(this.persistenceContext.get());
    }
 
    @Override
@@ -191,12 +179,29 @@
    
    
    /**
-    * Create a new STMEntityManagerFactoryImpl. Needs initialising
+    * Create a new STMEntityManagerFactoryImpl. The initialization
+    * of this object relies on serialization by the caller. Use the
+    * {@link STMPersistenceProviderImpl} object to protect access.
     *
     */
-   public STMEntityManagerFactoryImpl()
+   public STMEntityManagerFactoryImpl(String persistenceName, STMPersistenceContext persistenceContext)
    {
-      
+      if (StringUtils.isNotBlank( persistenceName))
+      {
+         this.persistenceContextName.set(  persistenceName); 
+      }
+      else
+      {
+         logger.error(ERROR_NULL_PERSISTENCE_CONTEXT_NAME);
+      }
+      if (null != persistenceContext)
+      {
+         this.persistenceContext.set(persistenceContext);
+      }
+      else
+      {
+         logger.error(ERROR_NULL_PERSISTENCE_CONTEXT);
+      }
    }
    
    /**
@@ -238,33 +243,6 @@
       return returnValue;
    }
    
-   /**
-    * Initialise the factory object with persistence context details. 
-    * 
-    * @param persistenceName
-    * @param persistenceContext
-    */
-   public void initialise(String persistenceName, STMPersistenceContext persistenceContext)
-   {
-      //TODO: this method is not thread safe, needs changing to make it safe
-      if (StringUtils.isNotBlank( persistenceName))
-      {
-         this.persistenceContextName = persistenceName; 
-      }
-      else
-      {
-         logger.error(ERROR_NULL_PERSISTENCE_CONTEXT_NAME);
-      }
-      if (null != persistenceContext)
-      {
-         this.persistenceContext = persistenceContext;
-      }
-      else
-      {
-         logger.error(ERROR_NULL_PERSISTENCE_CONTEXT);
-      }
-   }
-   
    private boolean notEmpty(Map map)
    {
       return !map.isEmpty();
@@ -286,4 +264,10 @@
    {
       throw new CloneNotSupportedException("Cloning of this object is not supported.");
    }
+   
+   @Override
+   public STMPersistenceContext getPersistenceContext()
+   {
+      return null;
+   }
 }

Modified: labs/jbosstm/workspace/whitingjr/trunk/MVCCSampleSTM/src/main/java/uk/ac/ncl/sdia/a8905943/spec/entitymanager/STMEntityManagerFactory.java
===================================================================
--- labs/jbosstm/workspace/whitingjr/trunk/MVCCSampleSTM/src/main/java/uk/ac/ncl/sdia/a8905943/spec/entitymanager/STMEntityManagerFactory.java	2009-07-17 14:21:19 UTC (rev 28145)
+++ labs/jbosstm/workspace/whitingjr/trunk/MVCCSampleSTM/src/main/java/uk/ac/ncl/sdia/a8905943/spec/entitymanager/STMEntityManagerFactory.java	2009-07-17 14:21:59 UTC (rev 28146)
@@ -10,7 +10,9 @@
 
 import javax.persistence.EntityManagerFactory;
 
+import uk.ac.ncl.sdia.a8905943.ejb3.persistence.STMPersistenceContext;
+
 public interface STMEntityManagerFactory extends EntityManagerFactory, Serializable
 {
-   
+   public STMPersistenceContext getPersistenceContext();
 }

Modified: labs/jbosstm/workspace/whitingjr/trunk/MVCCSampleSTM/src/main/java/uk/ac/ncl/sdia/a8905943/stm/persistence/STMPersistenceProviderImpl.java
===================================================================
--- labs/jbosstm/workspace/whitingjr/trunk/MVCCSampleSTM/src/main/java/uk/ac/ncl/sdia/a8905943/stm/persistence/STMPersistenceProviderImpl.java	2009-07-17 14:21:19 UTC (rev 28145)
+++ labs/jbosstm/workspace/whitingjr/trunk/MVCCSampleSTM/src/main/java/uk/ac/ncl/sdia/a8905943/stm/persistence/STMPersistenceProviderImpl.java	2009-07-17 14:21:59 UTC (rev 28146)
@@ -7,14 +7,17 @@
 package uk.ac.ncl.sdia.a8905943.stm.persistence;
 
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
+import javax.naming.InitialContext;
+import javax.naming.NameAlreadyBoundException;
+import javax.naming.NamingException;
 import javax.persistence.EntityManagerFactory;
 import javax.persistence.spi.PersistenceProvider;
 import javax.persistence.spi.PersistenceUnitInfo;
 import javax.persistence.spi.PersistenceUnitTransactionType;
 
 import org.apache.log4j.Logger;
-import org.jgroups.annotations.GuardedBy;
 
 import uk.ac.ncl.sdia.a8905943.ejb3.persistence.STMPersistenceContext;
 import uk.ac.ncl.sdia.a8905943.entitymanager.STMEntityManagerFactoryImpl;
@@ -22,8 +25,12 @@
 /**
  * This object is responsible for creating an EntityManagerFactory for this 
  * provider STM system. This object is used by the container to create a factory
- * which in turn can create an EntityManager. There is the expectation of there
- * only being a single instance of the EMF in the JVM.
+ * which in turn can create an EntityManager. In a single JVM there can be multiple
+ * persistence contexts. A persistence context has only one EntityManagerFactory 
+ * so ensure that concurrent threads access the correct persistence context and
+ * the EMF associated with it.
+ * This implementation relies on an EJB being allocated to a persistence context and
+ * for the full lifecycle of the thread the persistence context not changing.
  * 
  * This implementation supports only:
  * JTA transaction type
@@ -40,11 +47,13 @@
    public static final String PROPERTY_JTA_DATASOURCE = "javax.persistence.jtaDataSource";
    public static final String PROPERTY_PERSISTENCE_PROVIDER = "javax.persistence.provider";
    public static final String PROPERTY_ISOLATION_LEVEL = "ISOLATION_LEVEL";
+   private static final String ERROR_FAILED_TO_BIND = "Failed to bind the persistence context to JNDI";
+   private static final String WARN_ALREADY_BOUND = "The STM persistence provider does not support application managed entity manager factory creation. Only containers can create this.";
+   private static final String PC_NAME= "java/PersistenceContext/";
    
-   //TODO: jrw make factory a singleton 
-   @GuardedBy("this")
-   private static final STMEntityManagerFactoryImpl factory = new STMEntityManagerFactoryImpl();
-   private static final STMPersistenceContext context = new STMPersistenceContext();
+   //shared hashmap of factories, uniquness is based on persistence name
+   private final ConcurrentHashMap<String, STMEntityManagerFactoryImpl> factories = new ConcurrentHashMap<String, STMEntityManagerFactoryImpl>();
+   private final ConcurrentHashMap<String, STMPersistenceContext> contexts = new ConcurrentHashMap<String, STMPersistenceContext>();
    
    @Override
    public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map)
@@ -67,10 +76,34 @@
       {
          throw new UnsupportedOperationException("Attempt to use resource-local persistence provider which is not supported. Only JTA is supported.");
       }
-      factory.initialise(info.getPersistenceUnitName(), this.context);
-      
-      returnValue = factory;
-      
+      synchronized(this)
+      {
+         STMEntityManagerFactoryImpl factory = new STMEntityManagerFactoryImpl(info.getPersistenceUnitName(), new STMPersistenceContext());
+         final STMEntityManagerFactoryImpl concurrentValue = factories.putIfAbsent(info.getPersistenceUnitName(), factory);
+         // using the factory to indicate if this persistence provider has been 'initialised'
+         if (null == concurrentValue)
+         {// bind to jndi the persistence context
+            returnValue = factory;
+            try
+            {
+               InitialContext context = new InitialContext();
+               context.bind( getBindingName(info.getPersistenceUnitName()), factory.getPersistenceContext());
+            }
+            catch (NameAlreadyBoundException nabe)
+            {
+               logger.warn(WARN_ALREADY_BOUND);
+            }
+            catch (NamingException ne)
+            {
+               logger.error(ERROR_FAILED_TO_BIND, ne);
+               throw new RuntimeException(ERROR_FAILED_TO_BIND);
+            }
+         }
+         else
+         {// persistence context is already bound to jndi
+            returnValue = concurrentValue; // the factory instance created earlier in method is discarded
+         }
+      }
       return returnValue;
    }
 
@@ -79,9 +112,17 @@
    {
       if (true)
       {
-         throw new UnsupportedOperationException("The STM persistence provider does not support application managed entity manager factory creation. Only containers can create this.");
+         throw new UnsupportedOperationException();
       }
       return null;
    }
-
+   
+   public STMPersistenceProviderImpl()
+   {
+   }
+   
+   private String getBindingName(String pcName)
+   {
+      return new StringBuffer().append(PC_NAME).append(pcName).toString();
+   }
 }



More information about the jboss-svn-commits mailing list