Repository: zest-java Updated Branches: refs/heads/develop b9e71e7b4 -> d85a93fe8
Adding more information in Exceptions dealing with concurrent modifications. Project: http://git-wip-us.apache.org/repos/asf/zest-java/repo Commit: http://git-wip-us.apache.org/repos/asf/zest-java/commit/80284fb2 Tree: http://git-wip-us.apache.org/repos/asf/zest-java/tree/80284fb2 Diff: http://git-wip-us.apache.org/repos/asf/zest-java/diff/80284fb2 Branch: refs/heads/develop Commit: 80284fb254e2498ba8c7589314e904ebad305f5f Parents: b9e71e7 Author: Niclas Hedhman <[email protected]> Authored: Sat Nov 14 08:49:06 2015 +0800 Committer: Niclas Hedhman <[email protected]> Committed: Sat Nov 14 08:49:06 2015 +0800 ---------------------------------------------------------------------- .../ConcurrentEntityModificationException.java | 7 +++- .../unitofwork/concern/UnitOfWorkConcern.java | 39 +++++++++++++++++--- .../zest/runtime/entity/EntityInstance.java | 15 +++++++- .../runtime/entity/EntityStateInstance.java | 13 ++++++- .../runtime/unitofwork/UnitOfWorkInstance.java | 2 +- ...currentEntityStateModificationException.java | 20 +++++++++- .../ConcurrentModificationCheckConcern.java | 11 +++--- .../ConcurrentUoWFileModificationException.java | 5 ++- .../uowfile/internal/UoWFileFactory.java | 2 +- 9 files changed, 94 insertions(+), 20 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/zest-java/blob/80284fb2/core/api/src/main/java/org/apache/zest/api/unitofwork/ConcurrentEntityModificationException.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/ConcurrentEntityModificationException.java b/core/api/src/main/java/org/apache/zest/api/unitofwork/ConcurrentEntityModificationException.java index 5d02845..e494f82 100644 --- a/core/api/src/main/java/org/apache/zest/api/unitofwork/ConcurrentEntityModificationException.java +++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/ConcurrentEntityModificationException.java @@ -15,6 +15,7 @@ package org.apache.zest.api.unitofwork; import org.apache.zest.api.entity.EntityComposite; +import org.apache.zest.api.usecase.Usecase; /** * This exception is thrown by UnitOfWork.complete() if any entities that are being committed @@ -27,9 +28,11 @@ public class ConcurrentEntityModificationException private final Iterable<EntityComposite> concurrentlyModifiedEntities; - public ConcurrentEntityModificationException( Iterable<EntityComposite> concurrentlyModifiedEntities ) + public ConcurrentEntityModificationException( Iterable<EntityComposite> concurrentlyModifiedEntities, + Usecase usecase + ) { - super("Entities changed concurrently :" + concurrentlyModifiedEntities); + super( "Entities changed concurrently, and detected in usecase '" + usecase + "'\nModified entities : " + concurrentlyModifiedEntities ); this.concurrentlyModifiedEntities = concurrentlyModifiedEntities; } http://git-wip-us.apache.org/repos/asf/zest-java/blob/80284fb2/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkConcern.java ---------------------------------------------------------------------- diff --git a/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkConcern.java b/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkConcern.java index 5791398..c79db85 100644 --- a/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkConcern.java +++ b/core/api/src/main/java/org/apache/zest/api/unitofwork/concern/UnitOfWorkConcern.java @@ -18,6 +18,7 @@ package org.apache.zest.api.unitofwork.concern; import java.lang.reflect.Method; +import java.lang.reflect.UndeclaredThrowableException; import org.apache.zest.api.common.AppliesTo; import org.apache.zest.api.concern.GenericConcern; import org.apache.zest.api.injection.scope.Invocation; @@ -66,6 +67,7 @@ public class UnitOfWorkConcern { if( module.isUnitOfWorkActive() ) { + //noinspection ConstantConditions return next.invoke( proxy, method, args ); } else @@ -86,6 +88,7 @@ public class UnitOfWorkConcern Usecase usecase = usecase(); return invokeWithCommit( proxy, method, args, module.newUnitOfWork( usecase ) ); } + //noinspection ConstantConditions return next.invoke( proxy, method, args ); } @@ -122,22 +125,31 @@ public class UnitOfWorkConcern int retry = 0; while( true ) { + //noinspection ConstantConditions Object result = next.invoke( proxy, method, args ); try { currentUnitOfWork.complete(); return result; } - catch( ConcurrentEntityModificationException e ) + catch( UndeclaredThrowableException e) { - if( retry >= maxTries ) + Throwable undeclared = e.getUndeclaredThrowable(); + if( undeclared instanceof ConcurrentEntityModificationException ) + { + ConcurrentEntityModificationException ceme = (ConcurrentEntityModificationException) undeclared; + currentUnitOfWork = checkRetry( maxTries, delayFactor, initialDelay, retry, ceme ); + retry++; + } + else { throw e; } - module.currentUnitOfWork().discard(); - Thread.sleep( initialDelay + retry * delayFactor ); + } + catch( ConcurrentEntityModificationException e ) + { + currentUnitOfWork = checkRetry( maxTries, delayFactor, initialDelay, retry, e ); retry++; - currentUnitOfWork = module.newUnitOfWork( usecase() ); } } } @@ -149,6 +161,23 @@ public class UnitOfWorkConcern } } + private UnitOfWork checkRetry( int maxTries, + long delayFactor, + long initialDelay, + int retry, + ConcurrentEntityModificationException e + ) + throws ConcurrentEntityModificationException, InterruptedException + { + if( retry >= maxTries ) + { + throw e; + } + module.currentUnitOfWork().discard(); + Thread.sleep( initialDelay + retry * delayFactor ); + return module.newUnitOfWork( usecase() ); + } + /** * Discard unit of work if the discard policy match. * http://git-wip-us.apache.org/repos/asf/zest-java/blob/80284fb2/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityInstance.java index d30ff3f..3f55ba5 100755 --- a/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityInstance.java +++ b/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityInstance.java @@ -231,7 +231,14 @@ public final class EntityInstance @Override public String toString() { - return identity.toString(); + if( Boolean.getBoolean( "zest.entity.print.state" ) ) + { + return state.toString(); + } + else + { + return identity.toString(); + } } public void remove( UnitOfWork unitOfWork ) @@ -301,7 +308,11 @@ public final class EntityInstance catch( ConstraintViolationException e ) { List<Class<?>> entityModelList = entityModel.types().collect( toList() ); - throw new ConstraintViolationException( identity.identity(), entityModelList, e.mixinTypeName(), e.methodName(), e.constraintViolations() ); + throw new ConstraintViolationException( identity.identity(), + entityModelList, + e.mixinTypeName(), + e.methodName(), + e.constraintViolations() ); } } } http://git-wip-us.apache.org/repos/asf/zest-java/blob/80284fb2/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityStateInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityStateInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityStateInstance.java index 9ab2326..0028c5a 100644 --- a/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityStateInstance.java +++ b/core/runtime/src/main/java/org/apache/zest/runtime/entity/EntityStateInstance.java @@ -20,10 +20,12 @@ package org.apache.zest.runtime.entity; import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; import java.util.function.BiFunction; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.zest.api.association.Association; import org.apache.zest.api.association.AssociationStateHolder; @@ -39,7 +41,6 @@ import org.apache.zest.runtime.association.ManyAssociationInstance; import org.apache.zest.runtime.association.ManyAssociationModel; import org.apache.zest.runtime.association.NamedAssociationInstance; import org.apache.zest.runtime.association.NamedAssociationModel; -import org.apache.zest.runtime.composite.ConstraintsCheck; import org.apache.zest.runtime.property.PropertyModel; import org.apache.zest.runtime.unitofwork.BuilderEntityState; import org.apache.zest.spi.entity.EntityState; @@ -225,4 +226,14 @@ public final class EntityStateInstance return state; } + + @Override + public String toString() + { + return "EntityState[" + state.entrySet().stream() + .map( entry -> ((Method) entry.getKey()).getName() + "=" + entry.getValue()) + .collect( Collectors.joining("\n ", " ", "\n") ) + + "]" + ; + } } http://git-wip-us.apache.org/repos/asf/zest-java/blob/80284fb2/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/UnitOfWorkInstance.java ---------------------------------------------------------------------- diff --git a/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/UnitOfWorkInstance.java b/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/UnitOfWorkInstance.java index 6f404e7..e9ea72c 100755 --- a/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/UnitOfWorkInstance.java +++ b/core/runtime/src/main/java/org/apache/zest/runtime/unitofwork/UnitOfWorkInstance.java @@ -371,7 +371,7 @@ public final class UnitOfWorkInstance .filter( instance -> instance.identity().equals( modifiedEntityIdentity ) ) .forEach( instance -> modifiedEntities.add( instance.<EntityComposite>proxy() ) ); } - throw new ConcurrentEntityModificationException( modifiedEntities ); + throw new ConcurrentEntityModificationException( modifiedEntities, ( (ConcurrentEntityStateModificationException) e ).getUsecase() ); } else { http://git-wip-us.apache.org/repos/asf/zest-java/blob/80284fb2/core/spi/src/main/java/org/apache/zest/spi/entitystore/ConcurrentEntityStateModificationException.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/zest/spi/entitystore/ConcurrentEntityStateModificationException.java b/core/spi/src/main/java/org/apache/zest/spi/entitystore/ConcurrentEntityStateModificationException.java index fe86c78..b6716ed 100644 --- a/core/spi/src/main/java/org/apache/zest/spi/entitystore/ConcurrentEntityStateModificationException.java +++ b/core/spi/src/main/java/org/apache/zest/spi/entitystore/ConcurrentEntityStateModificationException.java @@ -18,6 +18,7 @@ package org.apache.zest.spi.entitystore; import java.util.Collection; import org.apache.zest.api.entity.EntityReference; +import org.apache.zest.api.usecase.Usecase; /** * This exception should be thrown if the EntityStore detects that the entities being saved have been changed @@ -27,10 +28,11 @@ public class ConcurrentEntityStateModificationException extends EntityStoreException { private Collection<EntityReference> modifiedEntities; + private Usecase usecase; public ConcurrentEntityStateModificationException( Collection<EntityReference> modifiedEntities ) { - super("Entities changed concurrently:" + modifiedEntities); + super(); this.modifiedEntities = modifiedEntities; } @@ -38,4 +40,20 @@ public class ConcurrentEntityStateModificationException { return modifiedEntities; } + + @Override + public String getMessage() + { + return "Entities changed concurrently. Changes detected in usecase '" + usecase + "\nModified entities are;\n" + modifiedEntities; + } + + public Usecase getUsecase() + { + return usecase; + } + + public void setUsecase( Usecase usecase ) + { + this.usecase = usecase; + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zest-java/blob/80284fb2/core/spi/src/main/java/org/apache/zest/spi/entitystore/ConcurrentModificationCheckConcern.java ---------------------------------------------------------------------- diff --git a/core/spi/src/main/java/org/apache/zest/spi/entitystore/ConcurrentModificationCheckConcern.java b/core/spi/src/main/java/org/apache/zest/spi/entitystore/ConcurrentModificationCheckConcern.java index 5ae7b56..5ed5f91 100755 --- a/core/spi/src/main/java/org/apache/zest/spi/entitystore/ConcurrentModificationCheckConcern.java +++ b/core/spi/src/main/java/org/apache/zest/spi/entitystore/ConcurrentModificationCheckConcern.java @@ -14,8 +14,7 @@ package org.apache.zest.spi.entitystore; -import java.util.ArrayList; -import java.util.List; +import java.util.HashSet; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.zest.api.ZestAPI; import org.apache.zest.api.concern.ConcernOf; @@ -59,10 +58,9 @@ public abstract class ConcurrentModificationCheckConcern { private final EntityStoreUnitOfWork uow; private EntityStateVersions versions; - private ModuleSpi module; private long currentTime; - private List<EntityState> loaded = new ArrayList<>(); + private HashSet<EntityState> loaded = new HashSet<>(); private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); @@ -73,7 +71,6 @@ public abstract class ConcurrentModificationCheckConcern { this.uow = uow; this.versions = versions; - this.module = module; this.currentTime = currentTime; } @@ -134,6 +131,10 @@ public abstract class ConcurrentModificationCheckConcern catch( EntityStoreException e ) { lock.writeLock().unlock(); + if( e instanceof ConcurrentEntityStateModificationException ) + { + ((ConcurrentEntityStateModificationException) e).setUsecase( usecase() ); + } throw e; } } http://git-wip-us.apache.org/repos/asf/zest-java/blob/80284fb2/libraries/uowfile/src/main/java/org/apache/zest/library/uowfile/internal/ConcurrentUoWFileModificationException.java ---------------------------------------------------------------------- diff --git a/libraries/uowfile/src/main/java/org/apache/zest/library/uowfile/internal/ConcurrentUoWFileModificationException.java b/libraries/uowfile/src/main/java/org/apache/zest/library/uowfile/internal/ConcurrentUoWFileModificationException.java index 0d8be4e..c1d8fe6 100644 --- a/libraries/uowfile/src/main/java/org/apache/zest/library/uowfile/internal/ConcurrentUoWFileModificationException.java +++ b/libraries/uowfile/src/main/java/org/apache/zest/library/uowfile/internal/ConcurrentUoWFileModificationException.java @@ -20,15 +20,16 @@ package org.apache.zest.library.uowfile.internal; import java.util.Collections; import org.apache.zest.api.entity.EntityComposite; import org.apache.zest.api.unitofwork.ConcurrentEntityModificationException; +import org.apache.zest.api.usecase.Usecase; public class ConcurrentUoWFileModificationException extends ConcurrentEntityModificationException { private final Iterable<UoWFile> concurrentlyModifiedFiles; - ConcurrentUoWFileModificationException( Iterable<UoWFile> concurrentlyModifiedFiles ) + ConcurrentUoWFileModificationException( Iterable<UoWFile> concurrentlyModifiedFiles, Usecase usecase ) { - super( Collections.<EntityComposite>emptyList() ); + super( Collections.<EntityComposite>emptyList(), usecase ); this.concurrentlyModifiedFiles = concurrentlyModifiedFiles; } http://git-wip-us.apache.org/repos/asf/zest-java/blob/80284fb2/libraries/uowfile/src/main/java/org/apache/zest/library/uowfile/internal/UoWFileFactory.java ---------------------------------------------------------------------- diff --git a/libraries/uowfile/src/main/java/org/apache/zest/library/uowfile/internal/UoWFileFactory.java b/libraries/uowfile/src/main/java/org/apache/zest/library/uowfile/internal/UoWFileFactory.java index f17e83a..3dcb80a 100644 --- a/libraries/uowfile/src/main/java/org/apache/zest/library/uowfile/internal/UoWFileFactory.java +++ b/libraries/uowfile/src/main/java/org/apache/zest/library/uowfile/internal/UoWFileFactory.java @@ -155,7 +155,7 @@ public interface UoWFileFactory } if( !concurrentlyModified.isEmpty() ) { - throw new ConcurrentUoWFileModificationException( concurrentlyModified ); + throw new ConcurrentUoWFileModificationException( concurrentlyModified, uow.usecase() ); } } }
