Author: scottbw
Date: Mon Aug 23 05:54:06 2010
New Revision: 987998

URL: http://svn.apache.org/viewvc?rev=987998&view=rev
Log:
Applied a patch to fix concurrency issue when using JPA for persistence (see 
WOOKIE-145) - when errors occur due to possible race conditions/locking 
transactions are retried. Thanks to Randy Watler for the patch.

Added:
    
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/PersistenceCommitException.java
Modified:
    
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/jcr/JCRPersistenceManager.java
    
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/jpa/JPAPersistenceManager.java
    
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/IPersistenceManager.java
    
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/PersistenceManagerFactory.java
    
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/feature/FeatureLoader.java
    
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/server/MainFilter.java

Modified: 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/jcr/JCRPersistenceManager.java
URL: 
http://svn.apache.org/viewvc/incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/jcr/JCRPersistenceManager.java?rev=987998&r1=987997&r2=987998&view=diff
==============================================================================
--- 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/jcr/JCRPersistenceManager.java
 (original)
+++ 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/jcr/JCRPersistenceManager.java
 Mon Aug 23 05:54:06 2010
@@ -96,6 +96,7 @@ import org.apache.wookie.beans.jcr.impl.
 import org.apache.wookie.beans.jcr.impl.WidgetServiceImpl;
 import org.apache.wookie.beans.jcr.impl.WidgetTypeImpl;
 import org.apache.wookie.beans.util.IPersistenceManager;
+import org.apache.wookie.beans.util.PersistenceCommitException;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -440,7 +441,7 @@ public class JCRPersistenceManager imple
     /* (non-Javadoc)
      * @see org.apache.wookie.beans.util.IPersistenceManager#commit()
      */
-    public void commit()
+    public void commit() throws PersistenceCommitException
     {
         // validate object content manager transaction
         if (ocm == null)
@@ -457,7 +458,7 @@ public class JCRPersistenceManager imple
         }
         catch (Exception e)
         {
-            throw new RuntimeException("Unexpected exception: "+e, e);
+            throw new PersistenceCommitException("Object content manager write 
exception: "+e, e);
         }
     }
 

Modified: 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/jpa/JPAPersistenceManager.java
URL: 
http://svn.apache.org/viewvc/incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/jpa/JPAPersistenceManager.java?rev=987998&r1=987997&r2=987998&view=diff
==============================================================================
--- 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/jpa/JPAPersistenceManager.java
 (original)
+++ 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/jpa/JPAPersistenceManager.java
 Mon Aug 23 05:54:06 2010
@@ -30,8 +30,10 @@ import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
 import javax.persistence.EntityTransaction;
 import javax.persistence.NoResultException;
+import javax.persistence.OptimisticLockException;
 import javax.persistence.Persistence;
 import javax.persistence.Query;
+import javax.persistence.RollbackException;
 import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Predicate;
@@ -91,6 +93,7 @@ import org.apache.wookie.beans.jpa.impl.
 import org.apache.wookie.beans.jpa.impl.WidgetServiceImpl;
 import org.apache.wookie.beans.jpa.impl.WidgetTypeImpl;
 import org.apache.wookie.beans.util.IPersistenceManager;
+import org.apache.wookie.beans.util.PersistenceCommitException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -346,7 +349,7 @@ public class JPAPersistenceManager imple
     /* (non-Javadoc)
      * @see org.apache.wookie.beans.util.IPersistenceManager#commit()
      */
-    public void commit()
+    public void commit() throws PersistenceCommitException
     {
         // validate entity manager transaction
         if (entityManager == null)
@@ -358,7 +361,18 @@ public class JPAPersistenceManager imple
         EntityTransaction transaction = entityManager.getTransaction();
         if (transaction.isActive())
         {
-            transaction.commit();
+            try
+            {
+                transaction.commit();
+            }
+            catch (RollbackException re)
+            {
+                throw new PersistenceCommitException("Transaction commit 
exception: "+re, re);
+            }
+            catch (OptimisticLockException ole)
+            {
+                throw new PersistenceCommitException("Transaction 
locking/version commit exception: "+ole, ole);
+            }
         }
     }
 

Modified: 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/IPersistenceManager.java
URL: 
http://svn.apache.org/viewvc/incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/IPersistenceManager.java?rev=987998&r1=987997&r2=987998&view=diff
==============================================================================
--- 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/IPersistenceManager.java
 (original)
+++ 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/IPersistenceManager.java
 Mon Aug 23 05:54:06 2010
@@ -38,8 +38,10 @@ public interface IPersistenceManager
     
     /**
      * Commit persistence manager transaction.
+     * 
+     * @throws PersistenceCommitException
      */
-    void commit();
+    void commit() throws PersistenceCommitException;
     
     /**
      * Rollback persistence manager transaction

Added: 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/PersistenceCommitException.java
URL: 
http://svn.apache.org/viewvc/incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/PersistenceCommitException.java?rev=987998&view=auto
==============================================================================
--- 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/PersistenceCommitException.java
 (added)
+++ 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/PersistenceCommitException.java
 Mon Aug 23 05:54:06 2010
@@ -0,0 +1,64 @@
+/*
+ *  Licensed 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.wookie.beans.util;
+
+/**
+ * PersistenceCommitException - persistence exception during commit
+ * 
+ * @author <a href="mailto:[email protected]";>Randy Watler</a>
+ * @version $Id$
+ */
+public class PersistenceCommitException extends Exception
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Default constructor.
+     */
+    public PersistenceCommitException()
+    {
+    }
+
+    /**
+     * Message constructor.
+     * 
+     * @param message exception message
+     */
+    public PersistenceCommitException(String message)
+    {
+        super(message);
+    }
+
+    /**
+     * Cause constructor.
+     * 
+     * @param cause exception cause
+     */
+    public PersistenceCommitException(Throwable cause)
+    {
+        super(cause);
+    }
+
+    /**
+     * Message and cause constructor.
+     * 
+     * @param message exception message
+     * @param cause exception cause
+     */
+    public PersistenceCommitException(String message, Throwable cause)
+    {
+        super(message, cause);
+    }
+}

Modified: 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/PersistenceManagerFactory.java
URL: 
http://svn.apache.org/viewvc/incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/PersistenceManagerFactory.java?rev=987998&r1=987997&r2=987998&view=diff
==============================================================================
--- 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/PersistenceManagerFactory.java
 (original)
+++ 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/beans/util/PersistenceManagerFactory.java
 Mon Aug 23 05:54:06 2010
@@ -232,7 +232,14 @@ public class PersistenceManagerFactory
                 }
                 
                 // commit persistence manager transaction
-                persistenceManager.commit();
+                try
+                {
+                    persistenceManager.commit();
+                }
+                catch (PersistenceCommitException pce)
+                {
+                    throw new RuntimeException("Initialization exception: 
"+pce, pce);
+                }
 
                 if (initializing)
                 {

Modified: 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/feature/FeatureLoader.java
URL: 
http://svn.apache.org/viewvc/incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/feature/FeatureLoader.java?rev=987998&r1=987997&r2=987998&view=diff
==============================================================================
--- 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/feature/FeatureLoader.java
 (original)
+++ 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/feature/FeatureLoader.java
 Mon Aug 23 05:54:06 2010
@@ -17,6 +17,7 @@ import org.apache.commons.configuration.
 import org.apache.log4j.Logger;
 import org.apache.wookie.beans.IServerFeature;
 import org.apache.wookie.beans.util.IPersistenceManager;
+import org.apache.wookie.beans.util.PersistenceCommitException;
 import org.apache.wookie.beans.util.PersistenceManagerFactory;
 import org.apache.wookie.w3c.util.IRIValidator;
 
@@ -65,7 +66,14 @@ public class FeatureLoader {
                        }
                }
                
-        persistenceManager.commit();
+        try
+        {
+            persistenceManager.commit();
+        }
+        catch (PersistenceCommitException pce)
+        {
+            throw new RuntimeException("Feature loading exception: "+pce, pce);
+        }
         PersistenceManagerFactory.closePersistenceManager();
        }
 

Modified: 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/server/MainFilter.java
URL: 
http://svn.apache.org/viewvc/incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/server/MainFilter.java?rev=987998&r1=987997&r2=987998&view=diff
==============================================================================
--- 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/server/MainFilter.java
 (original)
+++ 
incubator/wookie/branches/pluggablepersistence/src/org/apache/wookie/server/MainFilter.java
 Mon Aug 23 05:54:06 2010
@@ -24,6 +24,7 @@ import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 
 import org.apache.wookie.beans.util.IPersistenceManager;
+import org.apache.wookie.beans.util.PersistenceCommitException;
 import org.apache.wookie.beans.util.PersistenceManagerFactory;
 
 /**
@@ -36,21 +37,57 @@ public class MainFilter implements Filte
 
        public void doFilter(final ServletRequest request, final 
ServletResponse response, final FilterChain chain) 
        throws IOException, ServletException {
-               // get persistence manager for this thread
-           IPersistenceManager persistenceManager = 
PersistenceManagerFactory.getPersistenceManager();
-           try {
-               // start and commit transaction around servlet invocation
-                       persistenceManager.begin();
-                       chain.doFilter(request, response);
-                       persistenceManager.commit();
-           } catch (Throwable t) {
-               // rollback transaction on exception
-            persistenceManager.rollback();
-            throw new RuntimeException();
-           } finally {
-            // close thread persistence manager
-               PersistenceManagerFactory.closePersistenceManager();
-           }
+           // Retry filter chain invocation once if persistence commit
+           // exception is caught and response is not committed. This
+           // is intended to help insulate both the server and the
+           // widgets from limited transactional race conditions from
+           // concurrent requests that attempt to side effect the same
+           // server state. Note that this will not protect the widget
+           // or server from more than two concurrent modification
+           // attempts or guarantee sequential operation order. 
+           boolean retryChainInvocation = false;
+           do {
+               // get persistence manager for this thread
+               IPersistenceManager persistenceManager = 
PersistenceManagerFactory.getPersistenceManager();
+               try {
+                   // reset response and pause on retry to help ensure success
+                   if (retryChainInvocation) {
+                       response.reset();
+                       try {
+                           Thread.sleep(50);
+                       } catch (InterruptedException ie) {
+                       }
+                   }
+                   // start and commit transaction around servlet invocation
+                   persistenceManager.begin();
+                   chain.doFilter(request, response);
+                   persistenceManager.commit();
+                   // terminate retry attempts on success
+                   retryChainInvocation = false;
+               } catch (ServletException se) {
+                   // rollback transaction on exception
+                   persistenceManager.rollback();
+                   throw se;
+               } catch (IOException ioe) {
+                   // rollback transaction on exception
+                   persistenceManager.rollback();
+                   throw ioe;
+               } catch (PersistenceCommitException pce) {
+                // rollback and retry on commit exception if response not 
committed                
+                   persistenceManager.rollback();
+                   retryChainInvocation = (!retryChainInvocation && 
!response.isCommitted());
+                   if (!retryChainInvocation) {
+                       throw new RuntimeException("Persistence commit 
exception caught for transaction: "+pce, pce);                   
+                   }
+               } catch (Throwable t) {
+                   // rollback transaction on exception
+                   persistenceManager.rollback();
+                   throw new RuntimeException("Exception caught for 
transaction: "+t, t);
+               } finally {
+                   // close thread persistence manager
+                   PersistenceManagerFactory.closePersistenceManager();
+               }
+           } while (retryChainInvocation);
        }
 
        public void init(FilterConfig arg0) throws ServletException {           


Reply via email to