You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2013/09/24 07:58:05 UTC

[1/2] git commit: ISIS-536: disable concurrency checking in IsisJdoSupport#deleteAll

Updated Branches:
  refs/heads/master 3fd5244e0 -> 9e550a98f


ISIS-536: disable concurrency checking in IsisJdoSupport#deleteAll


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/beb614a9
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/beb614a9
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/beb614a9

Branch: refs/heads/master
Commit: beb614a986669741452132a210a895478abf062f
Parents: 3fd5244
Author: Dan Haywood <da...@apache.org>
Authored: Tue Sep 24 06:55:28 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Tue Sep 24 06:55:28 2013 +0100

----------------------------------------------------------------------
 .../applib/service/support/IsisJdoSupport.java  | 15 ++++++++
 .../persistence/FrameworkSynchronizer.java      |  3 +-
 .../service/support/IsisJdoSupportImpl.java     | 18 ++++++++-
 .../metamodel/adapter/mgr/AdapterManager.java   | 40 +++++++++++++++++++-
 .../adapter/version/ConcurrencyException.java   | 21 ----------
 .../persistence/adapter/PojoAdapter.java        |  3 +-
 .../adaptermanager/AdapterManagerDefault.java   |  2 +-
 7 files changed, 75 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/beb614a9/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/support/IsisJdoSupport.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/support/IsisJdoSupport.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/support/IsisJdoSupport.java
index 4014476..23faeb2 100644
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/support/IsisJdoSupport.java
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/support/IsisJdoSupport.java
@@ -62,6 +62,21 @@ public interface IsisJdoSupport {
     @Programmatic
     Integer executeUpdate(String sql);
 
+    /**
+     * Force the deletion of all instances of the specified class.
+     * 
+     * <p>
+     * Note: this is intended primarily for testing purposes, eg clearing existing data as part of
+     * installing fixtures.  It will generate a <tt>SQL DELETE</tt> for each instance.  To perform
+     * a bulk deletion with a single <tt>SQL DELETE</tt>, use {@link #executeUpdate(String)}.  
+     * 
+     * <p>
+     * Implementation note: It can occasionally be the case that Isis' internal adapter for the domain object is
+     * still in memory.  JDO/DataNucleus seems to bump up the version of the object prior to its deletion, 
+     * which under normal circumstances would cause Isis to throw a concurrency exception.  Therefore
+     * To prevent this from happening (ie to <i>force</i> the deletion of all instances), concurrency checking
+     * is temporarily disabled while this method is performed. 
+     */
     @Programmatic
     void deleteAll(Class<?>... pcClasses);
 

http://git-wip-us.apache.org/repos/asf/isis/blob/beb614a9/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/FrameworkSynchronizer.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/FrameworkSynchronizer.java b/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/FrameworkSynchronizer.java
index edbeec0..b9f9132 100644
--- a/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/FrameworkSynchronizer.java
+++ b/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/persistence/FrameworkSynchronizer.java
@@ -33,6 +33,7 @@ import org.apache.isis.core.commons.exceptions.IsisException;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.ResolveState;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
@@ -91,7 +92,7 @@ public class FrameworkSynchronizer {
                        otherVersion != null && 
                        thisVersion.different(otherVersion)) {
 
-                        if(ConcurrencyException.concurrencyChecking.get().isChecking()) {
+                        if(ConcurrencyChecking.isCurrentlyEnabled()) {
                             LOG.info("concurrency conflict detected on " + thisOid + " (" + otherVersion + ")");
                             final String currentUser = getAuthenticationSession().getUserName();
                             final ConcurrencyException abortCause = new ConcurrencyException(currentUser, thisOid, thisVersion, otherVersion);

http://git-wip-us.apache.org/repos/asf/isis/blob/beb614a9/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/service/support/IsisJdoSupportImpl.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/service/support/IsisJdoSupportImpl.java b/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/service/support/IsisJdoSupportImpl.java
index 2c08b3b..279361f 100644
--- a/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/service/support/IsisJdoSupportImpl.java
+++ b/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/service/support/IsisJdoSupportImpl.java
@@ -26,6 +26,7 @@ import java.sql.Statement;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Callable;
 
 import javax.jdo.Extent;
 import javax.jdo.PersistenceManager;
@@ -34,10 +35,13 @@ import javax.jdo.datastore.JDOConnection;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
+import org.apache.isis.applib.ApplicationException;
 import org.apache.isis.applib.annotation.Hidden;
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
+import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
 import org.apache.isis.core.metamodel.services.ServicesInjectorSpi;
 import org.apache.isis.core.runtime.persistence.ObjectPersistenceException;
 import org.apache.isis.core.runtime.system.context.IsisContext;
@@ -156,7 +160,19 @@ public class IsisJdoSupportImpl implements IsisJdoSupport {
         for (Class<?> pcClass : pcClasses) {
             final Extent<?> extent = getJdoPersistenceManager().getExtent(pcClass);
             final List<Object> instances = Lists.newArrayList(extent.iterator());
-            getJdoPersistenceManager().deletePersistentAll(instances);
+            
+            // temporarily disable concurrency checking while this method is performed
+            try {
+                ConcurrencyChecking.executeWithConcurrencyCheckingDisabled(new Callable<Void>(){
+                    @Override
+                    public Void call() {
+                        getJdoPersistenceManager().deletePersistentAll(instances);
+                        return null;
+                    }
+                });
+            } catch (Exception e) {
+                throw new ApplicationException(e);
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/beb614a9/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/mgr/AdapterManager.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/mgr/AdapterManager.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/mgr/AdapterManager.java
index 0ff8a82..2634a65 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/mgr/AdapterManager.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/mgr/AdapterManager.java
@@ -19,6 +19,8 @@
 
 package org.apache.isis.core.metamodel.adapter.mgr;
 
+import java.util.concurrent.Callable;
+
 import org.apache.isis.applib.annotation.ActionSemantics;
 import org.apache.isis.core.commons.components.Injectable;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
@@ -73,14 +75,48 @@ public interface AdapterManager extends Injectable {
         NO_CHECK,
         CHECK;
         
+        public boolean isChecking() {
+            return this == CHECK;
+        }
+        
         public static ConcurrencyChecking concurrencyCheckingFor(ActionSemantics.Of actionSemantics) {
             return actionSemantics == ActionSemantics.Of.SAFE
                     ? ConcurrencyChecking.NO_CHECK
                     : ConcurrencyChecking.CHECK;
         }
 
-        public boolean isChecking() {
-            return this == CHECK;
+        /**
+         * Provides a mechanism to temporarily disable concurrency checking.
+         * 
+         * <p>
+         * A {@link ThreadLocal} is used because typically there is JDO/DataNucleus code between the Isis code
+         * that wishes to disable the concurrency checking and the code (an Isis callback) that needs to
+         * check if checking has been disabled.
+         */
+        private static ThreadLocal<ConcurrencyChecking> concurrencyChecking = new ThreadLocal<ConcurrencyChecking>(){
+            protected ConcurrencyChecking initialValue() {
+                return CHECK;
+            };
+        };
+        
+        /**
+         * Whether concurrency checking is currently disabled.
+         */
+        public static boolean isCurrentlyEnabled() {
+            return concurrencyChecking.get().isChecking();
+        }
+
+        /**
+         * Allows a caller to temporarily disable concurrency checking for the current thread.
+         */
+        public static <T> T executeWithConcurrencyCheckingDisabled(final Callable<T> callable) throws Exception {
+            final ConcurrencyChecking prior = ConcurrencyChecking.concurrencyChecking.get();
+            try {
+                ConcurrencyChecking.concurrencyChecking.set(ConcurrencyChecking.NO_CHECK);
+                return callable.call();
+            } finally {
+                ConcurrencyChecking.concurrencyChecking.set(prior);
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/beb614a9/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/version/ConcurrencyException.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/version/ConcurrencyException.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/version/ConcurrencyException.java
index af3fdfc..2197550 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/version/ConcurrencyException.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/version/ConcurrencyException.java
@@ -20,7 +20,6 @@
 package org.apache.isis.core.metamodel.adapter.version;
 
 import org.apache.isis.core.commons.exceptions.IsisException;
-import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.OidMarshaller;
 
@@ -28,26 +27,6 @@ public class ConcurrencyException extends IsisException {
     
     private static final long serialVersionUID = 1L;
 
-    /**
-     * Provides a mechanism to temporarily disable concurrency checking.
-     * 
-     * <p>
-     * This thread-local is not used by this class, but is defined here as a central point for other methods
-     * to read/write.  The idea is that if concurrency checking is to be temporarily disabled, then the caller can
-     * set this threadlocal to {@link ConcurrencyChecking#NO_CHECK no-check}, and then the code that would normally
-     * detect the concurrency problem and throw this exception would instead consult this thread local and suppress
-     * the exception being raised.
-
-     * <p>
-     * In this design, it is the responsibility of the caller that is disabling concurrency exception handling to reinstate it
-     * afterwards.  This should normally be done using a try...finally.
-     */
-    public static ThreadLocal<ConcurrencyChecking> concurrencyChecking = new ThreadLocal<ConcurrencyChecking>(){
-        protected ConcurrencyChecking initialValue() {
-            return ConcurrencyChecking.CHECK;
-        };
-    };
-    
     private static String buildMessage(String currentUser, Oid oid, Version staleVersion, Version datastoreVersion) {
         
         final StringBuilder buf = new StringBuilder();

http://git-wip-us.apache.org/repos/asf/isis/blob/beb614a9/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adapter/PojoAdapter.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adapter/PojoAdapter.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adapter/PojoAdapter.java
index 5128cb8..07cf7bb 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adapter/PojoAdapter.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adapter/PojoAdapter.java
@@ -34,6 +34,7 @@ import org.apache.isis.core.commons.util.ToString;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.ResolveState;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
 import org.apache.isis.core.metamodel.adapter.oid.AggregatedOid;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.ParentedOid;
@@ -340,7 +341,7 @@ public class PojoAdapter extends InstanceAbstract implements ObjectAdapter {
            otherVersion != null && 
            thisVersion.different(otherVersion)) {
             
-            if(ConcurrencyException.concurrencyChecking.get().isChecking()) {
+            if(ConcurrencyChecking.isCurrentlyEnabled()) {
                 LOG.info("concurrency conflict detected on " + thisOid + " (" + otherVersion + ")");
                 final String currentUser = getAuthenticationSession().getUserName();
                 throw new ConcurrencyException(currentUser, thisOid, thisVersion, otherVersion);

http://git-wip-us.apache.org/repos/asf/isis/blob/beb614a9/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java
index 0e561b1..fc76dd7 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/adaptermanager/AdapterManagerDefault.java
@@ -325,7 +325,7 @@ public class AdapterManagerDefault implements AdapterManagerSpi {
                        otherVersion != null && 
                        thisVersion.different(otherVersion)) {
                         
-                        if(ConcurrencyException.concurrencyChecking.get().isChecking()) {
+                        if(ConcurrencyChecking.isCurrentlyEnabled()) {
                             LOG.info("concurrency conflict detected on " + recreatedOid + " (" + otherVersion + ")");
                             final String currentUser = getAuthenticationSession().getUserName();
                             throw new ConcurrencyException(currentUser, recreatedOid, thisVersion, otherVersion);


[2/2] git commit: ISIS-540: Exception Recognizer for JDODataStoreException now does *not* recognise...

Posted by da...@apache.org.
ISIS-540: Exception Recognizer for JDODataStoreException now does *not* recognise...

.. certain phrases that would likely constitute an error in the system that should be surfaced to the dev team, ie not swallowed in a friendly error message

* "NOT NULL check constraint" -- eg a mandatory property has most likely not been set.


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/9e550a98
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/9e550a98
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/9e550a98

Branch: refs/heads/master
Commit: 9e550a98f8698259167732466681fb7a8521e5b6
Parents: beb614a
Author: Dan Haywood <da...@apache.org>
Authored: Tue Sep 24 06:57:50 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Tue Sep 24 06:57:50 2013 +0100

----------------------------------------------------------------------
 ...ptionRecognizerForJDODataStoreException.java |  2 +-
 .../exceprecog/ExceptionRecognizerForType.java  | 41 +++++++++++++++++++-
 2 files changed, 40 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/9e550a98/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDODataStoreException.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDODataStoreException.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDODataStoreException.java
index 94d9381..a79e090 100644
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDODataStoreException.java
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDODataStoreException.java
@@ -23,7 +23,7 @@ import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerForType;
 public class ExceptionRecognizerForJDODataStoreException extends ExceptionRecognizerForType {
 
     public ExceptionRecognizerForJDODataStoreException() {
-        super(javax.jdo.JDODataStoreException.class, 
+        super(ofTypeExcluding(javax.jdo.JDODataStoreException.class, "NOT NULL check constraint"), 
             prefix("Unable to save changes.  " +
             	   "Does similar data already exist, or has referenced data been deleted?"));
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/9e550a98/core/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerForType.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerForType.java b/core/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerForType.java
index 7a3e74b..76760a3 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerForType.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerForType.java
@@ -18,8 +18,11 @@
  */
 package org.apache.isis.applib.services.exceprecog;
 
+import java.util.List;
+
 import com.google.common.base.Function;
 import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
 import com.google.common.base.Throwables;
 
 import org.apache.isis.applib.annotation.Hidden;
@@ -37,7 +40,11 @@ import org.apache.isis.applib.annotation.Hidden;
 @Hidden
 public class ExceptionRecognizerForType extends ExceptionRecognizerDelegating {
 
-    private final static Predicate<Throwable> ofType(final Class<? extends Throwable> exceptionType) {
+    protected final static Predicate<Throwable> ofTypeExcluding(final Class<? extends Throwable> exceptionType, final String... messages) {
+        return Predicates.and(ofType(exceptionType), excluding(messages));
+    }
+
+    protected final static Predicate<Throwable> ofType(final Class<? extends Throwable> exceptionType) {
         return new Predicate<Throwable>() {
             @Override
             public boolean apply(Throwable input) {
@@ -45,9 +52,39 @@ public class ExceptionRecognizerForType extends ExceptionRecognizerDelegating {
             }
         };
     }
+    
+    /**
+     * A {@link Predicate} that {@link Predicate#apply(Object) applies} only if the message(s)
+     * supplied do <i>NOT</i> appear in the {@link Throwable} or any of its {@link Throwable#getCause() cause}s
+     * (recursively).
+     * 
+     * <p>
+     * Intended to prevent too eager matching of an overly general exception type.
+     */
+    protected final static Predicate<Throwable> excluding(final String... messages) {
+        return new Predicate<Throwable>() {
+            @Override
+            public boolean apply(Throwable input) {
+                final List<Throwable> causalChain = Throwables.getCausalChain(input);
+                for (String message : messages) {
+                    for (Throwable throwable : causalChain) {
+                        final String throwableMessage = throwable.getMessage();
+                        if(throwableMessage != null && throwableMessage.contains(message)) {
+                            return false;
+                        }
+                    }
+                }
+                return true;
+            }
+        };
+    }
 
     public ExceptionRecognizerForType(final Class<? extends Exception> exceptionType, final Function<String,String> messageParser) {
-        super(new ExceptionRecognizerGeneral(ofType(exceptionType), messageParser));
+        this(ofType(exceptionType), messageParser);
+    }
+    
+    public ExceptionRecognizerForType(final Predicate<Throwable> predicate, final Function<String,String> messageParser) {
+        super(new ExceptionRecognizerGeneral(predicate, messageParser));
     }
     
     public ExceptionRecognizerForType(Class<? extends Exception> exceptionType) {