HI Oscar, Just coming back to you on this pull request for providing an alternate Axon event bus.
I know previously (offline) I said I'd look to do the work to bring this change in for 1.8.0, but I've changed my mind, for a couple of reasons: * it's a fairly deep change to bring in at quite a late stage * if we did bring it in, it would make the Axon framework a new dependency of Isis. * we could in any case instead make the code available as a new Isis addon. Thus, for those that want to use it, it should just be a matter of updating the pom.xml and registering in isis.properties (anything registered there takes precedence over the default @DomainServices). This isn't to rule out moving to an Axon-based implementation in the future - I know you have a lot of experience with Axon and rate it highly - but I think starting off with an Isisaddon is a lower-risk approach. It also allows you to iterate and refine the implementation if required without the overhead of doing a full ASF release. ~~~ If you're happy with that, I'll create a new Isis addon module and put the code there. Let me know, Dan On 8 February 2015 at 21:59, GESCONSULTOR - Óscar Bou < [email protected]> wrote: > Hi, Dan. > > I've updated the pull request. > > It still has an unexpected behavior when using the refactored > EventBusServiceJdo, being that when an Exception is thrown during action > processing (ie, on EXECUTING) the transaction is marked to be aborted but > the execution flow continues (and seems not to abort). > > Perhaps an Exception might be thrown when detected or something similar? > I had tests expecting an Exception that were previously passing and > currently not. > But not sure when the exception might be thrown. > > > Thanks, > > Oscar > > > > > El 8/2/2015, a las 13:04, GESCONSULTOR - Óscar Bou < > [email protected]> escribió: > > > > Hi, Dan. > > > > I've just sent a pull request [1] containing an initial implementation > of an Axon-based EventBusService. > > > > I've refactored some classes in order to reuse Isis logic as much as > possible. > > > > > > Please, can you review it? > > > > Thanks, > > > > Oscar > > > > > > [1] https://github.com/apache/isis/pull/23 < > https://github.com/apache/isis/pull/23> > > > > > >> El 6/2/2015, a las 19:47, Dan Haywood <[email protected] > <mailto:[email protected]>> escribió: > >> > >> Hi Oscar, > >> sorry not to reply on this post... just getting around to it. > >> > >> Yes, your email makes sense to me; I hadn't known that Guava buffered > events, but I can see why the fact that it does could cause this > multi-level cascade issue. > >> > >> I had a poke around its Javadoc but couldn't see any way to turn it off. > >> > >> It ought to be possible to swap in an Axion-based event bus instead > though. Write a service implementing Isis' EventBusService API, and make > sure that the subscribers use Axion's own subscription API, obviously. > >> > >> With the Guava implementation I had to install a special exception > handler [8] so that a subscriber could veto or abort an transaction; an > Axion implementation would need to do something similar. > >> > >> If you do write an implementation, then it can be registered (and take > precedence over the built-in guava impl) just by explicitly registering in > isis.properties, like we used to do. > >> > >> ~~~ > >> As for CQRS.... Jeroen and I joke about my antipathy for it as a > pattern. But actually, it's not really true... I can, truth be told, see > benefits from applying some of its ideas, if only to help decouple the app > (different rates of change of behaviour = commands vs structure = query). > >> > >> So, in Isis a CQRS app one would have dumb entities, and all behaviour > would be either contributed actions or event bus subscribers. Indeed, we > are gradually refactoring Estatio into this structure, so that we can (a) > focus on its core domain - an invoice calculation engine - and (b) > potentially reuse some of its building block modules in other apps. > >> > >> Cheers > >> Dan > >> > >> > >> [8] > https://github.com/apache/isis/blob/b5f73ec3dcae8015d11004915c15dd81c2945238/core/runtime/src/main/java/org/apache/isis/core/runtime/services/eventbus/EventBusServiceDefault.java#L91 > < > https://github.com/apache/isis/blob/b5f73ec3dcae8015d11004915c15dd81c2945238/core/runtime/src/main/java/org/apache/isis/core/runtime/services/eventbus/EventBusServiceDefault.java#L91 > > > >> > >> > >> On 17 January 2015 at 16:17, GESCONSULTOR - Óscar Bou < > [email protected] <mailto:[email protected]>> wrote: > >> Hi all. > >> > >> I'm "fighting" against current Event Bus implementation, as it's > currently based on Guava Event Bus. > >> > >> It has one characteristic that is not allowing me to implement, for > example, cascade deleting of Domain Entities, nested in 3 levels (Entity2 > references Entity1, and Entity3 references Entity2. When deleting an > Entity1 instance I want to delete - or set to null, etc. - Entity2 and > Entity3 also). > >> > >> This is due to Guava EventBus current implementation, that enqueues > Events posted instead of dispatching them at the very moment [1] as a > programmer would expect with a sequential execution flow. > >> > >> That originates limitations on "nested" behaviors when you post an > Event once you're processing an Event (ie, you're entered a @Subscriber). > >> For example, Events dispatched from actions that act on the EXECUTING > phase: > >> - if invoked by the user from the UI the @Subscriber's code will be > executed PRIOR to the action's code. > >> - but if invoked as part of a previous Event handler (ie, when still > executing a previous Event @Subscriber's code) it will be queued and will > be executed AFTER the action's code. > >> > >> In [1] the problem is explained quite clearly, and also the solution if > this one is not the desired behavior (to "delete" 3 lines, as currently > it's not configurable...). > >> > >> > >> > >> I'm trying to explain this over Estatio. > >> > >> On [2], the Party entity declares a "remove" action that posts an Event. > >> > >> On 3], the AgreementRoles service is subscribed to the Event. > >> But imagine that we want to delete all "AgreementRole" instances > instead of setting the reference to null or to another Party. > >> For that, we would declare and invoke a similar "remove" action to the > one defined for Party ([2]), with an @ActionInteraction for posting an > Event, and invoking it inside a "wrap" for the Event to be published. > >> > >> If I only have Party and AgreementRole, when Party.RemoveEvent is > processed on the EXECUTING phase I can delete (or set to null) the > AgreementRole instances referencing it. > >> So by now, all is ok. > >> > >> > >> But now imagine that there's another Entity that holds a reference to > the "AgreementRole" we are removing. > >> For that, I subscribe to AgreementRole.Remove Events hoping that > @Subscriber to be called BEFORE an "AgreementRole" is removed, in order to > "clear" (set to null) the reference to it, avoiding a referential integrity > Exception. > >> > >> In fact, I can define a test that asserts that, when an AgreementRole > is removed, the Event is posted and the reference is set to null. > >> > >> But what happens if the "AgreementRole.remove()" action is invoked > WHILE still processing the Party.RemoveEvent on the "AgreementRoles" > @Subscriber? > >> > >> That the Event will be queued, instead of being processed when posted > (and the AgreementRole @Subscriber being invoke then) !!! > >> > >> > >> As the execution flow will return to the "Party.RemoveEvent", where the > container().remove(...) method will be invoked, a JDO exception will be > thrown, similar to this one: > >> > >> javax.jdo.JDODataStoreException: Ha tirado una excepci�n al hacer > flush() a la base de datos > >> at > org.datanucleus.api.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:451) > >> at > org.datanucleus.api.jdo.JDOPersistenceManager.flush(JDOPersistenceManager.java:2029) > >> at > org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.executeCommands(DataNucleusObjectStore.java:361) > >> at > org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.execute(DataNucleusObjectStore.java:353) > >> at > org.apache.isis.core.runtime.system.transaction.IsisTransaction.doFlush(IsisTransaction.java:502) > >> at > org.apache.isis.core.runtime.system.transaction.IsisTransaction.flush(IsisTransaction.java:451) > >> at > org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.flushTransaction(IsisTransactionManager.java:392) > >> at > org.apache.isis.core.runtime.persistence.internal.RuntimeContextFromSession$7.flush(RuntimeContextFromSession.java:238) > >> at > org.apache.isis.core.metamodel.services.container.DomainObjectContainerDefault.flush(DomainObjectContainerDefault.java:247) > >> at > com.xms.framework.api.domain.model.isis.AbstractIsisDomainRepositoryAndFactory.doRemove(AbstractIsisDomainRepositoryAndFactory.java:353) > >> at > com.xms.framework.api.domain.model.isis.AbstractIsisDomainRepositoryAndFactory$3.execute(AbstractIsisDomainRepositoryAndFactory.java:346) > >> at > org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:160) > >> at > com.xms.framework.api.domain.model.isis.AbstractIsisDomainRepositoryAndFactory.remove(AbstractIsisDomainRepositoryAndFactory.java:342) > >> at > com.xms.framework.api.domain.model.isis.DomainRepositoryService.deleteEntity(DomainRepositoryService.java:221) > >> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) > >> at > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) > >> at > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) > >> at java.lang.reflect.Method.invoke(Method.java:606) > >> at > org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.internalInvoke(ActionInvocationFacetForInteractionAbstract.java:314) > >> at > org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.invoke(ActionInvocationFacetForInteractionAbstract.java:188) > >> at > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:57) > >> at > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:1) > >> at > org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:205) > >> at > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction.invoke(ActionInvocationFacetWrapTransaction.java:54) > >> at > org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionImpl.execute(ObjectActionImpl.java:367) > >> at > org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.handleActionMethod(DomainObjectInvocationHandler.java:563) > >> at > org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.invoke(DomainObjectInvocationHandler.java:229) > >> at > org.apache.isis.core.wrapper.proxy.ProxyInstantiatorForJavassist$1.invoke(ProxyInstantiatorForJavassist.java:52) > >> at > com.xms.framework.api.domain.model.isis.DomainRepositoryService_$$_jvst9b5_6.deleteEntity(DomainRepositoryService_$$_jvst9b5_6.java) > >> at > com.xms.framework.api.integration.tests.isis.AbstractIsisDomainRepositoryAndFactoryTests.deleteDomainObjectWithAnnotation_referenced_isDeleted_ifEventHandlerDeletesTheReference_nested(AbstractIsisDomainRepositoryAndFactoryTests.java:108) > >> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) > >> at > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) > >> at > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) > >> at java.lang.reflect.Method.invoke(Method.java:606) > >> at > org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) > >> at > org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) > >> at > org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) > >> at > org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) > >> at > org.apache.isis.core.integtestsupport.IntegrationTestAbstract$IsisTransactionRule$1.evaluate(IntegrationTestAbstract.java:199) > >> at > org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2$1.evaluate(JUnitRuleMockery2.java:146) > >> at > org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:168) > >> at org.junit.rules.RunRules.evaluate(RunRules.java:20) > >> at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) > >> at > org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) > >> at > org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) > >> at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) > >> at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) > >> at > org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) > >> at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) > >> at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) > >> at > org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) > >> at org.junit.runners.ParentRunner.run(ParentRunner.java:309) > >> at > org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) > >> at > org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) > >> at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) > >> at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) > >> at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) > >> at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) > >> NestedThrowablesStackTrace: > >> java.sql.BatchUpdateException: violación del restricción de integridad: > sin acción para la clave foránea; AGREEMENTROLE_FK1 table: AGREEMENTROLE > >> at org.hsqldb.jdbc.JDBCPreparedStatement.executeBatch(Unknown > Source) > >> at > org.datanucleus.store.rdbms.datasource.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297) > >> at > org.datanucleus.store.rdbms.datasource.dbcp.DelegatingStatement.executeBatch(DelegatingStatement.java:297) > >> at > org.datanucleus.store.rdbms.ParamLoggingPreparedStatement.executeBatch(ParamLoggingPreparedStatement.java:372) > >> at > org.datanucleus.store.rdbms.SQLController.processConnectionStatement(SQLController.java:628) > >> at > org.datanucleus.store.rdbms.SQLController.processStatementsForConnection(SQLController.java:596) > >> at > org.datanucleus.store.rdbms.SQLController$1.transactionFlushed(SQLController.java:683) > >> at > org.datanucleus.store.connection.AbstractManagedConnection.transactionFlushed(AbstractManagedConnection.java:86) > >> at > org.datanucleus.store.connection.ConnectionManagerImpl$2.transactionFlushed(ConnectionManagerImpl.java:454) > >> at org.datanucleus.TransactionImpl.flush(TransactionImpl.java:203) > >> at > org.datanucleus.ExecutionContextImpl.flushInternal(ExecutionContextImpl.java:4125) > >> at > org.datanucleus.ExecutionContextImpl.flush(ExecutionContextImpl.java:4070) > >> at > org.datanucleus.api.jdo.JDOPersistenceManager.flush(JDOPersistenceManager.java:2010) > >> at > org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.executeCommands(DataNucleusObjectStore.java:361) > >> at > org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore.execute(DataNucleusObjectStore.java:353) > >> at > org.apache.isis.core.runtime.system.transaction.IsisTransaction.doFlush(IsisTransaction.java:502) > >> at > org.apache.isis.core.runtime.system.transaction.IsisTransaction.flush(IsisTransaction.java:451) > >> at > org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.flushTransaction(IsisTransactionManager.java:392) > >> at > org.apache.isis.core.runtime.persistence.internal.RuntimeContextFromSession$7.flush(RuntimeContextFromSession.java:238) > >> at > org.apache.isis.core.metamodel.services.container.DomainObjectContainerDefault.flush(DomainObjectContainerDefault.java:247) > >> at > com.xms.framework.api.domain.model.isis.AbstractIsisDomainRepositoryAndFactory.doRemove(AbstractIsisDomainRepositoryAndFactory.java:353) > >> at > com.xms.framework.api.domain.model.isis.AbstractIsisDomainRepositoryAndFactory$3.execute(AbstractIsisDomainRepositoryAndFactory.java:346) > >> at > org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:160) > >> at > com.xms.framework.api.domain.model.isis.AbstractIsisDomainRepositoryAndFactory.remove(AbstractIsisDomainRepositoryAndFactory.java:342) > >> at > com.xms.framework.api.domain.model.isis.DomainRepositoryService.deleteEntity(DomainRepositoryService.java:221) > >> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) > >> at > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) > >> at > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) > >> at java.lang.reflect.Method.invoke(Method.java:606) > >> at > org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.internalInvoke(ActionInvocationFacetForInteractionAbstract.java:314) > >> at > org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.invoke(ActionInvocationFacetForInteractionAbstract.java:188) > >> at > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:57) > >> at > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:1) > >> at > org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:205) > >> at > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction.invoke(ActionInvocationFacetWrapTransaction.java:54) > >> at > org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionImpl.execute(ObjectActionImpl.java:367) > >> at > org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.handleActionMethod(DomainObjectInvocationHandler.java:563) > >> at > org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.invoke(DomainObjectInvocationHandler.java:229) > >> at > org.apache.isis.core.wrapper.proxy.ProxyInstantiatorForJavassist$1.invoke(ProxyInstantiatorForJavassist.java:52) > >> at > com.xms.framework.api.domain.model.isis.DomainRepositoryService_$$_jvst9b5_6.deleteEntity(DomainRepositoryService_$$_jvst9b5_6.java) > >> at > com.xms.framework.api.integration.tests.isis.AbstractIsisDomainRepositoryAndFactoryTests.deleteDomainObjectWithAnnotation_referenced_isDeleted_ifEventHandlerDeletesTheReference_nested(AbstractIsisDomainRepositoryAndFactoryTests.java:108) > >> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) > >> at > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) > >> at > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) > >> at java.lang.reflect.Method.invoke(Method.java:606) > >> at > org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) > >> at > org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) > >> at > org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) > >> at > org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) > >> at > org.apache.isis.core.integtestsupport.IntegrationTestAbstract$IsisTransactionRule$1.evaluate(IntegrationTestAbstract.java:199) > >> at > org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2$1.evaluate(JUnitRuleMockery2.java:146) > >> at > org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:168) > >> at org.junit.rules.RunRules.evaluate(RunRules.java:20) > >> at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) > >> at > org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) > >> at > org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) > >> at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) > >> at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) > >> at > org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) > >> at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) > >> at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) > >> at > org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) > >> at org.junit.runners.ParentRunner.run(ParentRunner.java:309) > >> at > org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) > >> at > org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) > >> at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) > >> at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) > >> at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) > >> at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) > >> > >> > >> > >> > >> Am I missing something here? Perhaps a better way to solve this? > >> > >> > >> > >> > >> If not, for this to be avoided, possible solutions that come to my mind > are: > >> 1. To modify the current Guava's EventBus implementation to not queue > Event calls. > >> 2. To change current EventBus implementation to another one that will > not affect the business logic execution flow. > >> > >> > >> I've being a long-time user of the Axon framework's EventBus, and I'm > going to try it to resolve this use case. > >> > >> They have really amazing Event Bus implementations for "simple" > scenarios as mostly ours regarding one virtual machine (see SimpleEventBus > [4]) and for really advance scenarios involving Domain Events in clusters > (see ClusteredEventBus [5]). > >> > >> So using the SimpleEventBus seems the best way here ... > >> > >> Also, I think it would be interesting for Apache Isis to integrate it, > as it could be the initial alignment of Apache Isis DDD implementation with > CQRS, which quite people on the DDD community consider are closely related > (see references on the "Implementing DDD" book, and some links like [7], . > >> > >> > >> > >> > >> Excuse me for this long email. Events are hard to explain ... :-)) > >> > >> Many thanks in advance, > >> > >> Oscar > >> > >> > >> > >> > >> > >> [1] > https://github.com/estatio/estatio/blob/master/estatioapp/dom/src/main/java/org/estatio/dom/party/Party.java#L177 > < > https://github.com/estatio/estatio/blob/master/estatioapp/dom/src/main/java/org/estatio/dom/party/Party.java#L177 > > > >> > >> [2] > https://github.com/estatio/estatio/blob/master/estatioapp/dom/src/main/java/org/estatio/dom/agreement/AgreementRoles.java#L143 > < > https://github.com/estatio/estatio/blob/master/estatioapp/dom/src/main/java/org/estatio/dom/agreement/AgreementRoles.java#L143 > > > >> > >> [3] > http://stackoverflow.com/questions/21947936/guava-eventbus-dispatching < > http://stackoverflow.com/questions/21947936/guava-eventbus-dispatching> > >> > >> [4] http://www.axonframework.org <http://www.axonframework.org/> > >> > >> [5] > https://github.com/AxonFramework/AxonFramework/blob/master/core/src/main/java/org/axonframework/eventhandling/SimpleEventBus.java > < > https://github.com/AxonFramework/AxonFramework/blob/master/core/src/main/java/org/axonframework/eventhandling/SimpleEventBus.java > > > >> > >> [6] > https://github.com/AxonFramework/AxonFramework/blob/master/core/src/main/java/org/axonframework/eventhandling/ClusteringEventBus.java > < > https://github.com/AxonFramework/AxonFramework/blob/master/core/src/main/java/org/axonframework/eventhandling/ClusteringEventBus.java > > > >> > >> [7] > http://www.kenneth-truyers.net/2013/12/05/introduction-to-domain-driven-design-cqrs-and-event-sourcing/ > < > http://www.kenneth-truyers.net/2013/12/05/introduction-to-domain-driven-design-cqrs-and-event-sourcing/ > > > >> > >> > >> > >> > >>> El 14/1/2015, a las 10:07, GESCONSULTOR - Óscar Bou < > [email protected] <mailto:[email protected]>> escribió: > >>> > >>> Just to notice. > >>> > >>> As I was simply trying that, when removing an Entity (Relationship), > declared on a "core" module, it would automatically remove a dependent > object (RelationshipBCMInformation) declared on another module without > creating a direct dependency on the "core" module, I also tried to use > foreign keys declaration through JDO. > >>> > >>> So I annotated the RelationshipBCMInformation with @Element as this: > >>> > >>> > >>> public class RelationshipBCMInformation extends > AbstractMultiTenantUnnamedEntity { > >>> > >>> > >>> // {{ Relationship (property) > >>> private Relationship relationship; > >>> > >>> @Hidden > >>> @XMSField(locales = { @XMSLocale(locale = "es", caption = > "Relación") }) > >>> @Column(allowsNull = "false") > >>> @MemberOrder(sequence = "010") > >>> @Element(deleteAction = ForeignKeyAction.CASCADE) > >>> public Relationship getRelationship() { > >>> return this.relationship; > >>> } > >>> > >>> public void setRelationship(final Relationship relationship) { > >>> this.relationship = relationship; > >>> } > >>> > >>> .... > >>> > >>> } > >>> > >>> Seems that HSQLDB does not properly support DELETE CASCADE, but over > PostgreSQL it declares de Foreign Key and deletes de object. > >>> > >>> But seems that Isis does not get notified about it and the following > exception is thrown when ending the Isis transaction: > >>> > >>> Rerun > com.xms.framework.risk.integration.tests.continuity.RelationshipsBCMInformationTests.testDeleteColletionWithRelationshipAlsoDeletesRelationshipBCMInformation > >>> > testDeleteColletionWithRelationshipAlsoDeletesRelationshipBCMInformation(com.xms.framework.risk.integration.tests.continuity.RelationshipsBCMInformationTests) > >>> javax.jdo.JDOUserException: No es posible leer campos de un objeto > borrado > >>> > FailedObject:1[OID]com.xms.framework.architecture.domain.model.Relationship > >>> at > org.datanucleus.api.jdo.state.PersistentNewDeleted.transitionReadField(PersistentNewDeleted.java:106) > >>> at > org.datanucleus.state.AbstractStateManager.transitionReadField(AbstractStateManager.java:650) > >>> at > org.datanucleus.state.JDOStateManager.isLoaded(JDOStateManager.java:3194) > >>> at > com.xms.framework.api.domain.model.isis.AbstractMultiTenantObject.getTenantId(AbstractMultiTenantObject.java) > >>> at > com.xms.framework.api.domain.model.isis.AbstractMultiTenantObject.toString(AbstractMultiTenantObject.java:72) > >>> at > org.apache.isis.core.runtime.system.transaction.IsisTransaction.asString(IsisTransaction.java:703) > >>> at > org.apache.isis.core.runtime.system.transaction.IsisTransaction.access$0(IsisTransaction.java:702) > >>> at > org.apache.isis.core.runtime.system.transaction.IsisTransaction$PreAndPostValues.setPost(IsisTransaction.java:1197) > >>> at > org.apache.isis.core.runtime.system.transaction.IsisTransaction.updatePostValues(IsisTransaction.java:1325) > >>> at > org.apache.isis.core.runtime.system.transaction.IsisTransaction.getChangedObjectProperties(IsisTransaction.java:1310) > >>> at > org.apache.isis.core.runtime.system.transaction.IsisTransaction.preCommit(IsisTransaction.java:733) > >>> at > org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.endTransaction(IsisTransactionManager.java:481) > >>> at > org.apache.isis.core.integtestsupport.IsisSystemForTest.endTran(IsisSystemForTest.java:667) > >>> at > org.apache.isis.core.integtestsupport.IntegrationTestAbstract$IsisTransactionRule$1.evaluate(IntegrationTestAbstract.java:200) > >>> at > org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2$1.evaluate(JUnitRuleMockery2.java:146) > >>> at > org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:168) > >>> at org.junit.rules.RunRules.evaluate(RunRules.java:20) > >>> at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) > >>> at > org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) > >>> at > org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) > >>> at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) > >>> at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) > >>> at > org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) > >>> at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) > >>> at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) > >>> at > org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) > >>> at org.junit.runners.ParentRunner.run(ParentRunner.java:309) > >>> at > org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) > >>> at > org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) > >>> at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) > >>> at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) > >>> at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) > >>> at > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) > >>> > >>> > >>> > >>> I will try to reimplement it using Events, but perhaps this is > relevant for other use cases. > >>> > >>> HTH, > >>> > >>> Oscar > >>> > >>> > >>> > >>> > >>> > >>>> El 13/1/2015, a las 19:25, GESCONSULTOR - Óscar Bou < > [email protected] <mailto:[email protected]>> escribió: > >>>> > >>>> Hi Dan. > >>>> > >>>> I’ve just updated the issue description. > >>>> > >>>> Just an “idiomatic issue”. > >>>> > >>>> I understand that an object can be saved when initially created, and > after updating an existing object. > >>>> > >>>> So for me domainEventOnSave would be triggered both when saving newly > created objects, and when updating previously created objects. > >>>> > >>>> Would it be better naming it something like “domainEventOnCreate” ? > >>>> > >>>> Seems JDO lifecycle callbacks are named something similar [1]. > >>>> > >>>> Regards, > >>>> > >>>> Oscar > >>>> > >>>> > >>>> [1] > http://www.datanucleus.org/products/datanucleus/jdo/lifecycle_callbacks.html > < > http://www.datanucleus.org/products/datanucleus/jdo/lifecycle_callbacks.html > > > >>>> > >>>> > >>>>> El 13/1/2015, a las 18:39, Dan Haywood <[email protected] > <mailto:[email protected]>> escribió: > >>>>> > >>>>> > >>>>> > >>>>> On 13 January 2015 at 17:19, GESCONSULTOR - Óscar Bou < > [email protected] <mailto:[email protected]>> wrote: > >>>>> ok, Dan. > >>>>> > >>>>> But that would include something like @DomainObjectInteraction, in > order to customize the event (and the event handler) ? > >>>>> > >>>>> > >>>>> > >>>>> Yeah, though into @DomainObject rather than a new annotation. > >>>>> > >>>>> Why? because in ISIS-970 the existing annotations @ActionInteraction > / @PropertyInteraction / @CollectionInteraction are being deprecated to be > replaced by into @Action / @Property / @Collection, > >>>>> > >>>>> eg: > >>>>> @ActionInteraction(SomethingChangedEvent.class) > >>>>> > >>>>> will become > >>>>> > >>>>> @Action(domainEvent=SomethingChangedEvent.class) > >>>>> > >>>>> > >>>>> ~~~ > >>>>> > >>>>> Therefore I suggest > >>>>> > >>>>> @DomainObject( > >>>>> domainEventOnLoad = ..., > >>>>> domainEventOnSave = ..., > >>>>> domainEventOnUpdate = ..., > >>>>> domainEventOnDelete = ..., > >>>>> ) > >>>>> > >>>>> I don't think there's any need to have a pairs of hooks (eg > domainEventOnSaving / domainEventOnSaved), because the domainEvent itself > has "phases", ie EXECUTING and EXECUTED. So we can reuse that. > >>>>> > >>>>> I'm not sure at this stage if the other "vetoing" phases > (HIDE/DISABLE/VALIDATE) all makes sense, though possibly the OnLoad event > could honour HIDE and DISABLE (providing a way by which a subscriber could > prevent an object from being either viewed or being edited). > >>>>> > >>>>> If the above sounds ok, can you do me a favour and copy/paste some > of the above into the ISIS-803 ticket? > >>>>> > >>>>> > >>>>> Cheers > >>>>> Dan > >>>>> > >>>>> > >>>>> > >>>>> > >>>>>> El 13/1/2015, a las 15:21, Dan Haywood < > [email protected] <mailto:[email protected]>> > escribió: > >>>>>> > >>>>>> Hi Oscar > >>>>>> > >>>>>> Although we probably won't use this in Estatio, it is (I think) a > valid use case. > >>>>>> > >>>>>> We do in fact have a ticket for it already, ISIS-803 [1]. And the > original ticket that introduced the event bus, ISIS-550 [2], although it > didn't implement the feature, did mention it. > >>>>>> > >>>>>> In a similar vein, if we implement ISIS-803 then I think the > recently raised ISIS-1005 [3] is probably redundant (or at least, is part > of ISIS-803). > >>>>>> > >>>>>> In terms of priorities, I want to get my @Action / @Property / > @Collection stuff finished off. Then I'll take a look at this and see how > much work it is to squeeze in for 1.8.0 or not. > >>>>>> > >>>>>> HTH > >>>>>> Dan > >>>>>> > >>>>>> > >>>>>> [1] https://issues.apache.org/jira/browse/ISIS-803 < > https://issues.apache.org/jira/browse/ISIS-803> > >>>>>> [2] https://issues.apache.org/jira/browse/ISIS-550 < > https://issues.apache.org/jira/browse/ISIS-550> > >>>>>> [3] https://issues.apache.org/jira/browse/ISIS-1005 < > https://issues.apache.org/jira/browse/ISIS-1005> > >>>>>> > >>>>>> > >>>>>> ~~~~~~~~~~~~~ > >>>>>> > >>>>>> > >>>>>> On 13 January 2015 at 14:06, GESCONSULTOR - Óscar Bou < > [email protected] <mailto:[email protected]>> wrote: > >>>>>> Hi, Dan and Jeroen for your pointing me towards those examples. > >>>>>> > >>>>>> As I'm seeing on Estatio, event publishing is made through an > @ActionInteraction annotation, which requires to always delete entities by > means of that action. > >>>>>> > >>>>>> I attached the event post to the "removing" framework method for > publishing the event every time an object is going to be delete, > independently it's made through a custom action or through > "container().remove()". > >>>>>> That way, I can be sure the business logic is going to be executed > ALWAYS despite how the other developers implement this. > >>>>>> > >>>>>> We can re-implement all this event logic for assuring that we > always delete this kind of domain objects through that action, but I > thought previous solution would work better, as it's directly attached to > the object's lifecycle. > >>>>>> > >>>>>> In previous threads we talked about the option of being notified of > framework's events. > >>>>>> > >>>>>> Perhaps implementing a @DomainObjectInteraction annotation in a > similar way to @ActionInteraction could have sense. > >>>>>> > >>>>>> What do you think? > >>>>>> > >>>>>> Thanks, > >>>>>> > >>>>>> Oscar > >>>>>> > >>>>>> > >>>>>> > >>>>>> > >>>>>> > >>>>>> > >>>>>> > >>>>>> > >>>>>>> El 12/1/2015, a las 20:38, Jeroen van der Wal <[email protected] > <mailto:[email protected]>> escribió: > >>>>>>> > >>>>>>> > >>>>>>> Here's a sample of invalidating the removal of a Party in case it > plays > >>>>>>> role in an agreement: > >>>>>>> > https://github.com/estatio/estatio/blob/master/estatioapp/dom/src/main/java/org/estatio/dom/agreement/AgreementRoles.java#L143 > < > https://github.com/estatio/estatio/blob/master/estatioapp/dom/src/main/java/org/estatio/dom/agreement/AgreementRoles.java#L143 > > > >>>>>>> > >>>>>>> HTH > >>>>>>> > >>>>>>> On 12 January 2015 at 19:38, Dan Haywood < > [email protected] <mailto:[email protected]>> > >>>>>>> wrote: > >>>>>>> > >>>>>>>> Hi Oscar, > >>>>>>>> > >>>>>>>> I think we can support this use case, but admittedly it isn't - > yet - well > >>>>>>>> documented. > >>>>>>>> > >>>>>>>> First thing to say is that the "removing" lifecycle code hook > method that > >>>>>>>> you quote isn't actually part of your stacktrace. As it happens, > that's > >>>>>>>> probably a good thing... support for them is a little bit patchy > (there > >>>>>>>> might be bugs). > >>>>>>>> > >>>>>>>> So, when I look at your stack trace, what's actually happening is > that: > >>>>>>>> * BusinessEntity.deleteFromAssignedToBusinessProcesses(...) is > performing a > >>>>>>>> "removeElement" on a wrapped collection, which fires an event via: > >>>>>>>> * CollectionRemoveFromFacetForInteractionAbstract, which is > handled by > >>>>>>>> * RelationshipsBCMInformationEventHandler.on > >>>>>>>> > >>>>>>>> So, what you should do in the handler is to look at the event's > "phase". > >>>>>>>> In fact, you really must pay attention to the phase because it is > called > >>>>>>>> multiple times: > >>>>>>>> > >>>>>>>> switch(ev,getPhase()) { > >>>>>>>> case HIDE: > >>>>>>>> ... > >>>>>>>> case DISABLE: > >>>>>>>> ... > >>>>>>>> case VALIDATE: > >>>>>>>> ... > >>>>>>>> case EXECUTING: > >>>>>>>> ... > >>>>>>>> case EXECUTED: > >>>>>>>> ... > >>>>>>>> } > >>>>>>>> > >>>>>>>> As you have probably guessed, your code wants to go into the > "EXECUTING" > >>>>>>>> bit, which is the pre-execute callback. I imagine at the moment > it is > >>>>>>>> firing for all the cases, including the EXECUTED bit, and that's > most > >>>>>>>> likely why JDO then complains at you when you try to access that > deleted > >>>>>>>> object. > >>>>>>>> > >>>>>>>> Hope that makes sense / works... if not, then we can go round the > loop. > >>>>>>>> > >>>>>>>> Cheers > >>>>>>>> Dan > >>>>>>>> > >>>>>>>> > >>>>>>>> > >>>>>>>> > >>>>>>>> > >>>>>>>> > >>>>>>>> > >>>>>>>> Two things about > >>>>>>>> Rather than do this on the removing() callback, I suggest you > emit an event > >>>>>>>> on the action that The event that > >>>>>>>> > >>>>>>>> On 12 January 2015 at 18:24, GESCONSULTOR - Óscar Bou < > >>>>>>>> [email protected] <mailto:[email protected]>> wrote: > >>>>>>>> > >>>>>>>>> Hi all. > >>>>>>>>> > >>>>>>>>> I want to get notified when a domain object is going to be > removed. > >>>>>>>>> > >>>>>>>>> I have defined it as this: > >>>>>>>>> > >>>>>>>>> public class Relationship { > >>>>>>>>> > >>>>>>>>> … > >>>>>>>>> > >>>>>>>>> public void removing() { > >>>>>>>>> this.eventBusService.post(new > RelationshipRemovingEvent(this)); > >>>>>>>>> } > >>>>>>>>> ... > >>>>>>>>> > >>>>>>>>> } > >>>>>>>>> > >>>>>>>>> And an Event Handler like this: > >>>>>>>>> > >>>>>>>>> public class RelationshipsBCMInformationEventHandler extends > >>>>>>>>> AbstractXMSService { > >>>>>>>>> > >>>>>>>>> // {{ RELATIONSHIPS EVENTS HANDLER > >>>>>>>>> > >>>>>>>>> @Subscribe > >>>>>>>>> @Programmatic > >>>>>>>>> public void on(final RelationshipRemovingEvent event) { > >>>>>>>>> try { > >>>>>>>>> final RelationshipBCMInformation > relationshipBCMInformation = > >>>>>>>>> > >>>>>>>> > this.wrap(this.relationshipsBCMInformation).businessContinuityInformation(event.getRelationship()); > >>>>>>>>> > this.getContainer().remove(relationshipBCMInformation); > >>>>>>>>> this.getContainer().flush(); > >>>>>>>>> } catch (final Exception e) { > >>>>>>>>> e.printStackTrace(); > >>>>>>>>> throw new ApplicationException(e); > >>>>>>>>> } > >>>>>>>>> } > >>>>>>>>> > >>>>>>>>> // }} > >>>>>>>>> > >>>>>>>>> // {{ injected: RelationshipsBCMInformation > >>>>>>>>> @Inject > >>>>>>>>> private RelationshipsBCMInformation > relationshipsBCMInformation; > >>>>>>>>> > >>>>>>>>> // }} > >>>>>>>>> > >>>>>>>>> // {{ injected: EventBusService > >>>>>>>>> @Programmatic > >>>>>>>>> @PostConstruct > >>>>>>>>> public void postConstruct() { > >>>>>>>>> this.eventBusService.register(this); > >>>>>>>>> } > >>>>>>>>> > >>>>>>>>> @Programmatic > >>>>>>>>> @PreDestroy > >>>>>>>>> public void preDestroy() { > >>>>>>>>> this.eventBusService.unregister(this); > >>>>>>>>> } > >>>>>>>>> > >>>>>>>>> @javax.inject.Inject > >>>>>>>>> private EventBusService eventBusService; > >>>>>>>>> // }} > >>>>>>>>> > >>>>>>>>> } > >>>>>>>>> > >>>>>>>>> > >>>>>>>>> > >>>>>>>>> Problem is that when the code enters the “on” event handler, the > >>>>>>>> reference > >>>>>>>>> to the relationship accessed on "event.getRelationship()” is > already > >>>>>>>> marked > >>>>>>>>> as deleted: > >>>>>>>>> > >>>>>>>>> > >>>>>>>>> javax.jdo.JDOUserException: No es posible leer campos de un > objeto > >>>>>>>> borrado > >>>>>>>>> > >>>>>>>> > FailedObject:0[OID]com.xms.framework.architecture.domain.model.Relationship > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.datanucleus.api.jdo.state.PersistentNewDeleted.transitionReadField(PersistentNewDeleted.java:106) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.datanucleus.state.AbstractStateManager.transitionReadField(AbstractStateManager.java:650) > >>>>>>>>> at > >>>>>>>>> > org.datanucleus.state.JDOStateManager.isLoaded(JDOStateManager.java:3194) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.api.domain.model.isis.AbstractXMSDomainObject.getId(AbstractXMSDomainObject.java) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.api.domain.model.isis.AbstractXMSDomainObject.hashCode(AbstractXMSDomainObject.java:431) > >>>>>>>>> at java.util.Objects.hashCode(Objects.java:96) > >>>>>>>>> at java.util.HashMap$Entry.hashCode(HashMap.java:847) > >>>>>>>>> at java.util.AbstractMap.hashCode(AbstractMap.java:494) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.datanucleus.query.QueryUtils.getKeyForQueryResultsCache(QueryUtils.java:1306) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.datanucleus.store.query.QueryManager.getDatastoreQueryResult(QueryManager.java:470) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.datanucleus.store.rdbms.query.JDOQLQuery.performExecute(JDOQLQuery.java:605) > >>>>>>>>> at > >>>>>>>> org.datanucleus.store.query.Query.executeQuery(Query.java:1786) > >>>>>>>>> at > >>>>>>>>> org.datanucleus.store.query.Query.executeWithMap(Query.java:1690) > >>>>>>>>> at > >>>>>>>>> > org.datanucleus.api.jdo.JDOQuery.executeWithMap(JDOQuery.java:334) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.api.domain.model.isis.AbstractXMSDomainObjectRepositoryAndFactory.doFindByPropMultiTenant(AbstractXMSDomainObjectRepositoryAndFactory.java:759) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.api.domain.model.isis.AbstractXMSDomainObjectRepositoryAndFactory.findByPropMultiTenant(AbstractXMSDomainObjectRepositoryAndFactory.java:776) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.api.domain.model.isis.AbstractXMSDomainObjectRepositoryAndFactory.findByProp(AbstractXMSDomainObjectRepositoryAndFactory.java:769) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.api.domain.model.isis.AbstractSingletonMultiTenantObjectRepositoryAndFactory.singletonInstance(AbstractSingletonMultiTenantObjectRepositoryAndFactory.java:16) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.risk.domain.model.continuity.RelationshipsBCMInformation.businessContinuityInformation(RelationshipsBCMInformation.java:47) > >>>>>>>>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native > Method) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) > >>>>>>>>> at java.lang.reflect.Method.invoke(Method.java:606) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.internalInvoke(ActionInvocationFacetForInteractionAbstract.java:314) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.invoke(ActionInvocationFacetForInteractionAbstract.java:188) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:57) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:1) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:205) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction.invoke(ActionInvocationFacetWrapTransaction.java:54) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionImpl.execute(ObjectActionImpl.java:367) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.handleActionMethod(DomainObjectInvocationHandler.java:563) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.invoke(DomainObjectInvocationHandler.java:229) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.wrapper.proxy.ProxyInstantiatorForJavassist$1.invoke(ProxyInstantiatorForJavassist.java:52) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.risk.domain.model.continuity.RelationshipsBCMInformation_$$_jvstb07_2b.businessContinuityInformation(RelationshipsBCMInformation_$$_jvstb07_2b.java) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.risk.domain.model.continuity.RelationshipsBCMInformationEventHandler.on(RelationshipsBCMInformationEventHandler.java:23) > >>>>>>>>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native > Method) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) > >>>>>>>>> at java.lang.reflect.Method.invoke(Method.java:606) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.google.common.eventbus.EventSubscriber.handleEvent(EventSubscriber.java:74) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.google.common.eventbus.SynchronizedEventSubscriber.handleEvent(SynchronizedEventSubscriber.java:47) > >>>>>>>>> at > >>>>>>>> com.google.common.eventbus.EventBus.dispatch(EventBus.java:322) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:304) > >>>>>>>>> at > com.google.common.eventbus.EventBus.post(EventBus.java:275) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.applib.services.eventbus.EventBusService.post(EventBusService.java:202) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.metamodel.facets.InteractionHelper.postEventForCollection(InteractionHelper.java:202) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.metamodel.facets.collections.interaction.CollectionRemoveFromFacetForInteractionAbstract.remove(CollectionRemoveFromFacetForInteractionAbstract.java:103) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.transaction.facets.CollectionRemoveFromFacetWrapTransaction$1.execute(CollectionRemoveFromFacetWrapTransaction.java:55) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:160) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.transaction.facets.CollectionRemoveFromFacetWrapTransaction.remove(CollectionRemoveFromFacetWrapTransaction.java:52) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.metamodel.specloader.specimpl.OneToManyAssociationImpl.removeElement(OneToManyAssociationImpl.java:190) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.handleCollectionRemoveFromMethod(DomainObjectInvocationHandler.java:526) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.invoke(DomainObjectInvocationHandler.java:218) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.wrapper.proxy.ProxyInstantiatorForJavassist$1.invoke(ProxyInstantiatorForJavassist.java:52) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.architecture.domain.model.business.extensions.businessactor.Person_$$_jvstb07_28.removeFromAssignedToBusinessProcesses(Person_$$_jvstb07_28.java) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.architecture.domain.model.business.BusinessEntity.deleteFromAssignedToBusinessProcesses(BusinessEntity.java:93) > >>>>>>>>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native > Method) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) > >>>>>>>>> at java.lang.reflect.Method.invoke(Method.java:606) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.internalInvoke(ActionInvocationFacetForInteractionAbstract.java:314) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.invoke(ActionInvocationFacetForInteractionAbstract.java:188) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:57) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:1) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:205) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction.invoke(ActionInvocationFacetWrapTransaction.java:54) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionImpl.execute(ObjectActionImpl.java:367) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.handleActionMethod(DomainObjectInvocationHandler.java:563) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.invoke(DomainObjectInvocationHandler.java:229) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.wrapper.proxy.ProxyInstantiatorForJavassist$1.invoke(ProxyInstantiatorForJavassist.java:52) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.architecture.domain.model.business.extensions.businessactor.Person_$$_jvstb07_28.deleteFromAssignedToBusinessProcesses(Person_$$_jvstb07_28.java) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.architecture.domain.model.business.BusinessProcess.deleteFromRequiredBusinessEntities(BusinessProcess.java:476) > >>>>>>>>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native > Method) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) > >>>>>>>>> at java.lang.reflect.Method.invoke(Method.java:606) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.internalInvoke(ActionInvocationFacetForInteractionAbstract.java:314) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.metamodel.facets.actions.interaction.ActionInvocationFacetForInteractionAbstract.invoke(ActionInvocationFacetForInteractionAbstract.java:188) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:57) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction$1.execute(ActionInvocationFacetWrapTransaction.java:1) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.system.transaction.IsisTransactionManager.executeWithinTransaction(IsisTransactionManager.java:205) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.runtime.transaction.facets.ActionInvocationFacetWrapTransaction.invoke(ActionInvocationFacetWrapTransaction.java:54) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionImpl.execute(ObjectActionImpl.java:367) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.handleActionMethod(DomainObjectInvocationHandler.java:563) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.wrapper.handlers.DomainObjectInvocationHandler.invoke(DomainObjectInvocationHandler.java:229) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.wrapper.proxy.ProxyInstantiatorForJavassist$1.invoke(ProxyInstantiatorForJavassist.java:52) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.architecture.domain.model.business.BusinessProcess_$$_jvstb07_27.deleteFromRequiredBusinessEntities(BusinessProcess_$$_jvstb07_27.java) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > com.xms.framework.risk.integration.tests.continuity.RelationshipsBCMInformationTests.testDeleteColletionWithRelationshipAlsoDeletesRelationshipBCMInformation(RelationshipsBCMInformationTests.java:72) > >>>>>>>>> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native > Method) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) > >>>>>>>>> at java.lang.reflect.Method.invoke(Method.java:606) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.integtestsupport.IntegrationTestAbstract$IsisTransactionRule$1.evaluate(IntegrationTestAbstract.java:199) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2$1.evaluate(JUnitRuleMockery2.java:146) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:168) > >>>>>>>>> at org.junit.rules.RunRules.evaluate(RunRules.java:20) > >>>>>>>>> at > org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) > >>>>>>>>> at > org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) > >>>>>>>>> at > >>>>>>>> org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) > >>>>>>>>> at > >>>>>>>>> org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) > >>>>>>>>> at > >>>>>>>> org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) > >>>>>>>>> at > >>>>>>>> org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) > >>>>>>>>> at > org.junit.runners.ParentRunner.run(ParentRunner.java:309) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) > >>>>>>>>> at > >>>>>>>>> > >>>>>>>> > org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) > >>>>>>>>> > >>>>>>>>> > >>>>>>>>> So, as it could be a quite “common” events-related use case > (referencing > >>>>>>>>> the same entity “before” deleting it), could the event be > dispatched > >>>>>>>> BEFORE > >>>>>>>>> sending the object to DN to mark it as deleted? > >>>>>>>>> > >>>>>>>>> Or, is there any other way to detect when an object is going to > be > >>>>>>>> deleted > >>>>>>>>> (previously to being deleted, obviously) ? > >>>>>>>>> > >>>>>>>>> > >>>>>>>>> Thanks in advance, > >>>>>>>>> > >>>>>>>>> Oscar > >>>>>>>>> > >>>>>>>>> > >>>>>>>>> > >>>>>>>>> > >>>>>>>> > >>>>> > >>>> > >>> > >> > > > > > > >
