Se has a similar use cases to this one, when an event should be published when 
the user wanted to remove the domain object.

We can publish the event (eventBus.post(...)) on the "removing" lifecycle 
method.

As it's executed in the context of the same transaction where we change the 
references in all other objects, DN hasn't dispatched the delete command, no 
references to deleted objects are kept on the database.

Shouldn't it be enough for this case? Perhaps I'm missing something.



Disculpa que sea breve. 
Enviado desde mi móvil

> El 30/06/2014, a las 08:41, Dan Haywood <[email protected]> 
> escribió:
> 
> Hi folks (but probably mostly Oscar)...
> 
> 
> Jeroen and I were looking to use the new EventBus support for feature,
> specifically annotating an action using @PostsActionInvokedEvent with a
> custom event...
> 
> public class CommunicationChannel {
> 
>    public class RemovedEvent extends ActionInokedEvent {
>        ...
>       public CommunicationChannel getSource() { ... }
>       public CommunicationChannel getReplacedBy() { ... }
>       ...
>    }
> 
>    @PostsActionInvokedEvent(CommunicationChannel.RemovedEvent.class)
>    public void remove(@Named("Replace with") @Optional
> CommunicationChannel replaceWith) {
>        getContainer().remove(this);
>    }
>    ...
> }
> 
> and then in the subscriber:
> 
> public class AgreementRoleCommunicationChannels {
> 
>    @Subscribe
>    public void on(CommunicationChannel.RemovedEvent ev) {
>        CommunicationChannel removed = ev.getSource();
>        CommunicationChannel replacementIfAny = ev.getReplacedBy()
> 
>        List<AgreementRoleCommunicationChannel> impacted = ... query to
> find those referencing "removed" ...
> 
>        if(impacted.isEmpty()) {
>           return;
>        }
>        if(replacementIfAny == null) {
>            // veto
>            throw new RecoverableException("Provide a replacement");
>        }
>        for(AgreementRoleCommunicationChannel arcc: impacted) {
>            arcc.setCommunicationChannel(replacementIfAny);
>        }
>    }
>    ...
> }
> 
> The algorithm in the subscriber is to update the impacted ARCC objects so
> that they use the replacement.  If no replacement was provided, then the
> action is vetoed.
> 
> As its stands this code fails because the query to find those referencing
> the "removed" triggers a flush, which then causes a JDO referential
> integrity exception; not what we wanted.
> 
> Still with me?
> 
> We thought of making the auto-flush behaviour configurable (and we might
> still), however it seems that this use case highlights the fact that right
> now our event bus only supports propagation of an event during the action
> invocation, and there isn't yet a mechanism to propagate a validation event.
> 
> Put another way: really the veto logic ought to be done prior to executing
> the action; analogous to how our "validateXxx" methods fire.
> 
> For that matter, it ought to be possible for a subscriber to disable (grey
> out) or even hide an action on the object it subscribes to.
> 
> Haven't figured out what the syntax is for this.  I don't really want the
> developer to have to define multiple event types.  One option is to
> introduce a "mode" in the event, eg:
> 
> package org.apache.isis.applib.events;
> public enum Mode
>    Hide, Disable, Validate, Execute;
> }
> 
> and then have this as a member of ActionInvokedEvent.  In the subscriber,
> could then have:
> 
> public class AgreementRoleCommunicationChannels {
> 
>    @Subscribe
>    public void on(CommunicationChannel.RemovedEvent ev) {
>        CommunicationChannel removed = ev.getSource();
>        CommunicationChannel replacementIfAny = ev.getReplacedBy()
>        Mode mode = ev.getMode();
>        switch(mode) {
>            case Validate:
>               List<AgreementRoleCommunicationChannel> impacted = ... query
> to find those referencing "removed" ...
>               if(impacted.isEmpty()) {
>                  return;
>               }
>               if(replacementIfAny == null) {
>                  // veto
>                 throw new RecoverableException("Provide a replacement");
>               }
>               ev.put("impacted", impacted);
>               break;
>            case Execute:
>               List<AgreementRoleCommunicationChannel> impacted =
> ev.get("impacted");
>               for(AgreementRoleCommunicationChannel arcc: impacted) {
>                  arcc.setCommunicationChannel(replacementIfAny);
>               }
>        }
>    }
> }
> 
> Interested in opinions on this.
> 
> Cheers
> Dan

Reply via email to