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
>>>>
>>>
>>>
>>
>