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/15 16:45:16 UTC
git commit: ISIS-536: thread local as a means of temporarily
disabling concurrency checking.
Updated Branches:
refs/heads/master 3aacb262a -> 4bdc6adb4
ISIS-536: thread local as a means of temporarily disabling concurrency checking.
Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/4bdc6adb
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/4bdc6adb
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/4bdc6adb
Branch: refs/heads/master
Commit: 4bdc6adb4988adbb64010aa2e5c03b44134f6f9c
Parents: 3aacb26
Author: Dan Haywood <da...@apache.org>
Authored: Sun Sep 15 15:45:03 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Sun Sep 15 15:45:03 2013 +0100
----------------------------------------------------------------------
.../persistence/FrameworkSynchronizer.java | 72 +++++++++-----------
.../scimpi/dispatcher/action/ActionAction.java | 4 +-
.../metamodel/adapter/mgr/AdapterManager.java | 3 +
.../core/metamodel/adapter/oid/RootOid.java | 2 -
.../metamodel/adapter/oid/RootOidDefault.java | 14 ----
.../adapter/version/ConcurrencyException.java | 21 ++++++
.../persistence/adapter/PojoAdapter.java | 21 ++++--
.../adaptermanager/AdapterManagerDefault.java | 27 ++++++--
8 files changed, 99 insertions(+), 65 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/isis/blob/4bdc6adb/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 8046643..edbeec0 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
@@ -19,19 +19,15 @@
package org.apache.isis.objectstore.jdo.datanucleus.persistence;
import java.text.MessageFormat;
-import java.util.Arrays;
-import java.util.List;
import java.util.concurrent.Callable;
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.spi.PersistenceCapable;
-import org.datanucleus.api.jdo.NucleusJDOHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.apache.isis.applib.filter.Filter;
import org.apache.isis.core.commons.authentication.AuthenticationSession;
import org.apache.isis.core.commons.exceptions.IsisException;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
@@ -45,7 +41,6 @@ import org.apache.isis.core.metamodel.facets.object.callbacks.CallbackFacet;
import org.apache.isis.core.metamodel.facets.object.callbacks.CallbackUtils;
import org.apache.isis.core.metamodel.facets.object.callbacks.PersistedCallbackFacet;
import org.apache.isis.core.metamodel.facets.object.callbacks.UpdatedCallbackFacet;
-import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
import org.apache.isis.core.runtime.persistence.PersistorUtil;
import org.apache.isis.core.runtime.system.context.IsisContext;
import org.apache.isis.core.runtime.system.persistence.OidGenerator;
@@ -75,43 +70,57 @@ public class FrameworkSynchronizer {
public void run() {
final Version datastoreVersion = getVersionIfAny(pojo);
- final RootOid oid ;
- ObjectAdapter adapter = getAdapterManager().getAdapterFor(pojo);
- if(adapter != null) {
+ final RootOid originalOid ;
+ ObjectAdapter originalAdapter = getAdapterManager().getAdapterFor(pojo);
+ if(originalAdapter != null) {
ensureRootObject(pojo);
- oid = (RootOid) adapter.getOid();
+ originalOid = (RootOid) originalAdapter.getOid();
- final Version previousVersion = adapter.getVersion();
+ final Version originalVersion = originalAdapter.getVersion();
// sync the pojo held by the adapter with that just loaded
- getPersistenceSession().remapRecreatedPojo(adapter, pojo);
-
+ getPersistenceSession().remapRecreatedPojo(originalAdapter, pojo);
+
// since there was already an adapter, do concurrency check
- if(previousVersion != null && datastoreVersion != null) {
- if(previousVersion.different(datastoreVersion)) {
- getCurrentTransaction().setAbortCause(new ConcurrencyException(getAuthenticationSession().getUserName(), oid, previousVersion, datastoreVersion));
+ // (but don't set abort cause if checking is suppressed through thread-local)
+ final RootOid thisOid = originalOid;
+ final Version thisVersion = originalVersion;
+ final Version otherVersion = datastoreVersion;
+
+ if(thisVersion != null &&
+ otherVersion != null &&
+ thisVersion.different(otherVersion)) {
+
+ if(ConcurrencyException.concurrencyChecking.get().isChecking()) {
+ LOG.info("concurrency conflict detected on " + thisOid + " (" + otherVersion + ")");
+ final String currentUser = getAuthenticationSession().getUserName();
+ final ConcurrencyException abortCause = new ConcurrencyException(currentUser, thisOid, thisVersion, otherVersion);
+ getCurrentTransaction().setAbortCause(abortCause);
+
+ } else {
+ LOG.warn("concurrency conflict detected but suppressed, on " + thisOid + " (" + otherVersion + ")");
}
}
} else {
final OidGenerator oidGenerator = getOidGenerator();
- oid = oidGenerator.createPersistent(pojo, null);
+ originalOid = oidGenerator.createPersistent(pojo, null);
// it appears to be possible that there is already an adapter for this Oid,
// ie from ObjectStore#resolveImmediately()
- adapter = getAdapterManager().getAdapterFor(oid);
- if(adapter != null) {
- getPersistenceSession().remapRecreatedPojo(adapter, pojo);
+ originalAdapter = getAdapterManager().getAdapterFor(originalOid);
+ if(originalAdapter != null) {
+ getPersistenceSession().remapRecreatedPojo(originalAdapter, pojo);
} else {
- adapter = getPersistenceSession().mapRecreatedPojo(oid, pojo);
+ originalAdapter = getPersistenceSession().mapRecreatedPojo(originalOid, pojo);
}
}
- if(!adapter.isResolved()) {
- PersistorUtil.startResolving(adapter);
- PersistorUtil.toEndState(adapter);
+ if(!originalAdapter.isResolved()) {
+ PersistorUtil.startResolving(originalAdapter);
+ PersistorUtil.toEndState(originalAdapter);
}
- adapter.setVersion(datastoreVersion);
+ originalAdapter.setVersion(datastoreVersion);
if(pojo.jdoIsDeleted()) {
- adapter.changeState(ResolveState.DESTROYED);
+ originalAdapter.changeState(ResolveState.DESTROYED);
}
ensureFrameworksInAgreement(pojo);
@@ -347,19 +356,6 @@ public class FrameworkSynchronizer {
}
@SuppressWarnings("unused")
- private static Filter<ObjectAssociation> dirtyFieldFilterFor(final PersistenceCapable pojo) {
- String[] dirtyFields = NucleusJDOHelper.getDirtyFields(pojo, JDOHelper.getPersistenceManager(pojo));
- final List<String> dirtyFieldList = Arrays.asList(dirtyFields);
- Filter<ObjectAssociation> dirtyFieldsFilter = new Filter<ObjectAssociation>() {
- @Override
- public boolean accept(final ObjectAssociation t) {
- String id = t.getId();
- return dirtyFieldList.contains(id);
- }};
- return dirtyFieldsFilter;
- }
-
- @SuppressWarnings("unused")
private void ensureObjectNotLoaded(final PersistenceCapable pojo) {
final ObjectAdapter adapter = getAdapterManager().getAdapterFor(pojo);
if(adapter != null) {
http://git-wip-us.apache.org/repos/asf/isis/blob/4bdc6adb/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/action/ActionAction.java
----------------------------------------------------------------------
diff --git a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/action/ActionAction.java b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/action/ActionAction.java
index 9ef481d..f181cc9 100644
--- a/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/action/ActionAction.java
+++ b/component/viewer/scimpi/dispatcher/src/main/java/org/apache/isis/viewer/scimpi/dispatcher/action/ActionAction.java
@@ -30,6 +30,7 @@ import org.apache.isis.core.commons.debug.DebugBuilder;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
+import org.apache.isis.core.metamodel.adapter.version.Version;
import org.apache.isis.core.metamodel.consent.Consent;
import org.apache.isis.core.metamodel.consent.Veto;
import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
@@ -91,7 +92,8 @@ public class ActionAction implements Action {
session = new AnonymousSession();
}
- object.checkLock(context.getVersion(version));
+ final Version originalVersion = context.getVersion(version);
+ object.checkLock(originalVersion);
if (entryState.isValid()) {
final boolean hasResult = invokeMethod(context, resultName, object, action, entryState);
String view = context.getParameter(hasResult ? "_" + VIEW : "_" + VOID);
http://git-wip-us.apache.org/repos/asf/isis/blob/4bdc6adb/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 d3978aa..0ff8a82 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
@@ -79,6 +79,9 @@ public interface AdapterManager extends Injectable {
: ConcurrencyChecking.CHECK;
}
+ public boolean isChecking() {
+ return this == CHECK;
+ }
}
/**
http://git-wip-us.apache.org/repos/asf/isis/blob/4bdc6adb/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java
index a112f3e..a701b22 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java
@@ -50,8 +50,6 @@ public interface RootOid extends TypedOid {
void setVersion(Version version);
- void checkLock(String currentUser, RootOid oid);
-
/**
* Returns a new RootOid for the same {@link #getObjectSpecId()}, but persistent and with the specified {@link #getIdentifier() identifier}.
http://git-wip-us.apache.org/repos/asf/isis/blob/4bdc6adb/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOidDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOidDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOidDefault.java
index 2f1b4b7..9aa4533 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOidDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOidDefault.java
@@ -249,20 +249,6 @@ public final class RootOidDefault implements Serializable, RootOid {
: Comparison.EQUIVALENT_BUT_CHANGED;
}
- @Override
- public void checkLock(String currentUser, RootOid otherOid) {
- Version otherVersion = otherOid.getVersion();
- if(version == null || otherVersion == null) {
- return;
- }
- if (version.different(otherVersion)) {
- LOG.info("concurrency conflict on " + this + " (" + otherVersion + ")");
- // reset this Oid to latest
- throw new ConcurrencyException(currentUser, this, version, otherVersion);
- }
- }
-
-
// ////////////////////////////////////////////
// bookmark
// ////////////////////////////////////////////
http://git-wip-us.apache.org/repos/asf/isis/blob/4bdc6adb/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 2197550..af3fdfc 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,6 +20,7 @@
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;
@@ -27,6 +28,26 @@ 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/4bdc6adb/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 b3da0cb..5128cb8 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
@@ -331,14 +331,25 @@ public class PojoAdapter extends InstanceAbstract implements ObjectAdapter {
getAggregateRoot().checkLock(otherVersion);
return;
}
- final Version version = getOid().getVersion();
- if (otherVersion != null && version != null && version.different(otherVersion)) {
- LOG.info("concurrency conflict on " + this + " (" + otherVersion + ")");
- throw new ConcurrencyException(getAuthenticationSession().getUserName(), getOid(), version, otherVersion);
+
+ Oid thisOid = getOid();
+ final Version thisVersion = thisOid.getVersion();
+
+ // check for exception, but don't throw if suppressed through thread-local
+ if(thisVersion != null &&
+ otherVersion != null &&
+ thisVersion.different(otherVersion)) {
+
+ if(ConcurrencyException.concurrencyChecking.get().isChecking()) {
+ LOG.info("concurrency conflict detected on " + thisOid + " (" + otherVersion + ")");
+ final String currentUser = getAuthenticationSession().getUserName();
+ throw new ConcurrencyException(currentUser, thisOid, thisVersion, otherVersion);
+ } else {
+ LOG.warn("concurrency conflict detected but suppressed, on " + thisOid + " (" + otherVersion + ")");
+ }
}
}
-
@Override
public void setVersion(final Version version) {
if(isParented()) {
http://git-wip-us.apache.org/repos/asf/isis/blob/4bdc6adb/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 644ca16..0e561b1 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
@@ -45,6 +45,7 @@ import org.apache.isis.core.metamodel.adapter.oid.Oid;
import org.apache.isis.core.metamodel.adapter.oid.OidMarshaller;
import org.apache.isis.core.metamodel.adapter.oid.RootOid;
import org.apache.isis.core.metamodel.adapter.oid.TypedOid;
+import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
import org.apache.isis.core.metamodel.adapter.version.Version;
import org.apache.isis.core.metamodel.facets.accessor.PropertyOrCollectionAccessorFacet;
import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
@@ -61,6 +62,7 @@ import org.apache.isis.core.metamodel.spec.feature.Contributed;
import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
import org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
+import org.apache.isis.core.runtime.persistence.adapter.PojoAdapter;
import org.apache.isis.core.runtime.system.context.IsisContext;
import org.apache.isis.core.runtime.system.persistence.AdapterManagerSpi;
import org.apache.isis.core.runtime.system.persistence.OidGenerator;
@@ -312,20 +314,35 @@ public class AdapterManagerDefault implements AdapterManagerSpi {
if(adapterOid instanceof RootOid) {
final RootOid recreatedOid = (RootOid) adapterOid;
final RootOid originalOid = (RootOid) typedOid;
+
try {
- if(concurrencyChecking == ConcurrencyChecking.CHECK) {
- recreatedOid.checkLock(getAuthenticationSession().getUserName(), originalOid);
+ if(concurrencyChecking.isChecking()) {
+
+ // check for exception, but don't throw if suppressed through thread-local
+ final Version otherVersion = originalOid.getVersion();
+ final Version thisVersion = recreatedOid.getVersion();
+ if(thisVersion != null &&
+ otherVersion != null &&
+ thisVersion.different(otherVersion)) {
+
+ if(ConcurrencyException.concurrencyChecking.get().isChecking()) {
+ LOG.info("concurrency conflict detected on " + recreatedOid + " (" + otherVersion + ")");
+ final String currentUser = getAuthenticationSession().getUserName();
+ throw new ConcurrencyException(currentUser, recreatedOid, thisVersion, otherVersion);
+ } else {
+ LOG.warn("concurrency conflict detected but suppressed, on " + recreatedOid + " (" + otherVersion + ")");
+ }
+ }
}
} finally {
- originalOid.setVersion(recreatedOid.getVersion());
+ final Version recreatedVersion = recreatedOid.getVersion();
+ originalOid.setVersion(recreatedVersion);
}
}
return adapter;
}
-
-
@Override
public void remapRecreatedPojo(ObjectAdapter adapter, final Object pojo) {
removeAdapter(adapter);