OK, this ticket (ISIS-831) has now been implemented and will be in 1.6.0.

Notable points:

- every interaction with action, property and collection generates events
onto the event bus.
- if the action/property/collection is annotated (using @ActionInteraction,
@PropertyInteraction, @CollectionInteraction) then the event type specified
will be posted.
- If there is no annotation, then an instance of
"XxxInteractionEvent.Default" is posted instead
- each event is sent to subscribers (up to) 5 times: hide, disable,
validate, executing and executed; the ev.getPhase() can be used to
distinguish
- the same event is passed from the validate -> executing phases, meaning
that the subscriber can use the event as a means to transfer state from one
phase to another.

~~~

The use case that started all this was a requirement in Estatio app [1] to
implement a cascade update when deleting a CommunicationChannel; any
references to that CC in the AgreementRoleCommunicationChannel entity must
be updated with a replacement CC.

This is now implemented as follows.  In the entity

public abstract class CommunicationChannel ... {
   ...

   public static class RemoveEvent extends
ActionInteractionEvent<CommunicationChannel> { ... }

  @ActionInteraction(CommunicationChannel.RemoveEvent.class)
    public void remove(@Named("Replace with") @Optional
CommunicationChannel replacement) {
        getContainer().remove(this);
    }
}

and in the subscriber:

@DomainService
public class AgreementRoleCommunicationChannels ... {

    ...
    @Subscribe
    public void on(final CommunicationChannel.RemoveEvent ev) {
        CommunicationChannel sourceCommunicationChannel =
(CommunicationChannel) ev.getSource();
        CommunicationChannel replacementCommunicationChannel =
ev.getReplacement();

        switch (ev.getPhase()) {
            case VALIDATE:
                final List<AgreementRoleCommunicationChannel>
communicationChannels =
findByCommunicationChannel(sourceCommunicationChannel);

                if (communicationChannels.size() > 0 &&
replacementCommunicationChannel == null) {
                    ev.invalidate("Communication channel is being used:
provide a replacement");
                }

                ev.setCommunicationChannels(communicationChannels);
                break;
            case EXECUTING:
                for (AgreementRoleCommunicationChannel arcc :
ev.getImpactedCommunicationChannels()) {

arcc.setCommunicationChannel(replacementCommunicationChannel);
                }
                break;
        }
    }
}

I'm pretty excited about this new functionality; reckon it opens up all
sorts of scenarios to help decouple business logic.  For example, one could
have a subscriber whose sole job is to apply cross-cutting business rules.
 That subscriber could even be named after the business rule being
implemented.  In the above example, we could have called our subscriber
class "ReplaceCommunicationChannelWhereverUsed" as a way to describe its
responsibility.  (Now that we have @DomainService to automatically register
these classes, there is no real downside to having such fine-grained
services).


Cheers
Dan



[1] http://github.com/estatio/estatio
[2]
https://github.com/estatio/estatio/blob/bd2b6b932d128def036231fc1d51b58b4fcd8c14/dom/src/main/java/org/estatio/dom/communicationchannel/CommunicationChannel.java#L194
[3]








On 8 July 2014 07:28, Dan Haywood <[email protected]> wrote:

> Slight correction to previous post: the names I have chosen for the new
> annotations are
>
> @InteractionWithAction, @InteractionWithProperty,
> @InteractionWithCollection
>
> rather than
>
> @ActionInteraction, @PropertyInteraction, @CollectionInteraction.
>
> I'm really unsure which to use, keep changing my mind.  The
> "InteractionWith" prefix I like cos it groups these together lexically, and
> is more descriptive, but it's a bit clunky as a name; the second I like cos
> they are snappier.
>
> Opinions, if any?
>
> Dan
>
>
>
>
>
> On 8 July 2014 07:21, Dan Haywood <[email protected]> wrote:
>
>> Have started implementing this story now (ISIS-831), looking for some
>> opinions.  Oscar will chip in I'm sure :-) but I'd like other opinions too,
>> if possible.
>>
>>
>> Right now I'm planning to have an @ActionInteraction,
>> @PropertyInteraction and @CollectionInteraction; these are basically
>> replacements for @PostsActionInvokedEvent, @PostsPropertyChangedEvent and
>> @PostsCollectionAddedToEvent/@PostsCollectionRemovedFromEvent, and support
>> the validation stuff.  The original 4 @PostsXxxEvent annotations will be
>> deprecated.
>>
>> Because they are intended as replacements, if both annotations are
>> present then I intend only to generate one event on the event bus.
>>
>> ~~~
>> You'll note that I've collapsed the two annotations for collections
>> (add/remove) into a single annotation for collections.  I think I prefer
>> this.
>>
>> This does raise the question of whether to preserve two event classes for
>> collections (eg a CollectionAddInteractionEvent and
>> CollectionRemoveInteractionEvent), or whether to collapse into a single
>> event and have a field on the event class so that the subscriber can tell
>> whether an add or remove was performed.
>>
>> ~~~
>> The first design looks results in more boilerplate for the publisher:
>>
>> public static class OrderLinesAdd extends CollectionAddInteractionEvent {
>> ... }
>> public static class OrderLinesRemove extends
>> CollectionRemoveInteractionEvent { ... }
>>
>> @CollectionInteraction(add=OrderLinesAdd.class,
>> remove=OrderLinesRemove.class)
>> public Set<OrderLine> getOrderLines() { ...}
>>
>> but is cleaner for the subscriber:
>>
>> @Subscribe
>> public void on(OrderLinesAdd ev) { ...}
>> @Subscribe
>> public void on(OrderLinesRemove ev) { ...}
>>
>> ~~~
>> The second design is simpler for the publisher:
>>
>> public static class OrderLines extends CollectionRemoveInteractionEvent {
>> ... }
>>
>> @CollectionInteraction(OrderLines.class)
>> public Set<OrderLine> getOrderLines() { ...}
>>
>> but results in more code for the subscriber:
>>
>> @Subscribe
>> public void on(OrderLines ev) {
>>     if (ev.getType == ADD_TO) {
>>       ... add logic ...
>>     } else {
>>        ... remove logic ...
>>     }
>>
>>
>> Of these, I prefer the second design myself - I'd rather keep boilerplate
>> in the publishing entities down to a minimum.  But other opinions welcome.
>>
>> ~~~
>> Also, I've named the annotations @ActionInteraction, @PropertyInteraction
>> and @CollectionInteraction, but it occurred to me that they could be
>> shortened to just @Action, @Property, @Collection.  This might be a bad
>> thing or a good thing:
>> - it might be a bad thing because it would suggest that the only methods
>> that are recognised as actions, properties and collections are those
>> annotated in this way; where as Isis recognises everything that isn't
>> @Ignore'd.
>> - it might be a good thing because we could provide a mode of running
>> Isis whereby all methods are ignored by default unless explicitly
>> annotated.  In that case these annotations would flag the bits of the class
>> that are significant to Isis.
>>
>> I think the bad outweighs the good, meaning I should keep the
>> "Interaction" suffix and keep the current behaviour of recognizing
>> everything unless @Ignore'd .... but thought it raising in case anyone has
>> any opinions on this matter.
>>
>> Thx
>> Dan
>>
>>
>>
>>
>>
>> On 3 July 2014 12:21, Dan Haywood <[email protected]> wrote:
>>
>>>
>>>
>>> On 3 July 2014 12:15, GESCONSULTOR <[email protected]> wrote:
>>>
>>>>
>>>> Agree with you, Dan.
>>>>
>>>> Simply the @ActionInteraction perhaps should have the @PostsXXX prefix
>>>> for coherence.
>>>>
>>>>
>>> I thought about that, but I thought that "PostsXxx" implies an event
>>> being fired after (which used to be the case, of course) whereas in the new
>>> proposed design there are four events fired, three before the execute, one
>>> after.
>>>
>>> Another alternative I had thought of was to fold this into @Command, eg:
>>>
>>> @Command(...., actionInteraction=RemoveActionInteraction.class)
>>>
>>> One issue though is that commands only apply to actions, not to
>>> properties and collections (remember: there is the hide and disable events
>>> as part of this).  So perhaps probably best not too combine just yet, until
>>> things become clearer.
>>>
>>> Other suggestions welcome, of course!
>>>
>>>
>>> Ta
>>> Dan
>>>
>>>
>>>
>>>
>>>> Many thanks!!
>>>>
>>>>
>>>> > El 03/07/2014, a las 12:25, Dan Haywood <[email protected]>
>>>> escribió:
>>>> >
>>>> > @ActionInteraction
>>>>
>>>
>>>
>>
>

Reply via email to