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 {