:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.


== Usage by the Framework

The primary user of the service is the framework itself, which automatically emit events for xref:refguide:applib:index/annotation/Action.adoc#domainEvent[actions], xref:refguide:applib:index/annotation/Property.adoc#domainEvent[properties] and xref:refguide:applib:index/annotation/Collection.adoc#domainEvent[collections].
Multiple events are generated:

* when an object member is to be viewed, an event is fired; subscribers can veto (meaning that the member is hidden)
* when an object member is to be enabled, the same event instance is fired; subscribers can veto (meaning that the member is disabled, ie cannot be edited/invoked)
* when an object member is being validated, then a new event instance is fired; subscribers can veto (meaning that the candidate values/action arguments are rejected)
* when an object member is about to be changed, then the same event instance is fired; subscribers can perform pre-execution operations
* when an object member has been changed, then the same event instance is fired; subscribers can perform post-execution operations

If a subscriber throws an exception in the first three steps, then the interaction is vetoed.
If a subscriber throws an exception in the last two steps, then the transaction is aborted.
For more on this topic, see xref:refguide:applib:index/annotation/Action.adoc#domainEvent[@Action#domainEvent()], xref:refguide:applib:index/annotation/Property.adoc#domainEvent[@Property#domainEvent()] and xref:refguide:applib:index/annotation/Collection.adoc#domainEvent[@Collection#domainEvent()].

It is also possible for domain objects to programmatically generate domain events.
However the events are published, the primary use case is to decoupling interactions from one module/package/namespace and another.

== Default Event Classes

The framework will automatically emit domain events for all of the object members (actions, properties or collections) of an object whenever that object is rendered or (more generally) interacted with.

For example:

[source,java]
----
public class Customer {
    @Action()
    public Customer placeOrder( Product product, int quantity) {
        ...
    }
    ...
}
----

will propagate an instance of the default `o.a.i.applib.services.eventbus.ActionDomainEvent.Default` class, which can then be subscribed to:

[source,java]
----
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

@Service
public class MySubscribingDomainService {
    @EventListener(ActionDomainEvent.class)
    public void on(ActionDomainEvent ev) {
        ...
    }
    ...
}
----

== Custom Event Classes

More commonly though you will probably want to emit domain events of a specific subtype.
As a slightly more interesting example, suppose in a library domain that a `LibraryMember` wants to leave the library.
A letter should be sent out detailing any books that they still have out on loan:

In the `LibraryMember` class, we publish the event by way of an annotation:

[source,java]
----
public class LibraryMember {
    @Action(domainEvent=LibraryMemberLeaveEvent.class)  // <1>
    public void leave() {
        ...
    }
    ...
}
----
<1> `LibraryMemberLeaveEvent` is a subclass of `o.a.i.applib.eventbus.ActionDomainEvent`.The topic of subclassing is discussed in more detail xref:refguide:applib:index/services/eventbus/EventBusService.adoc#event-hierarchy[below].

Meanwhile, in the `BookRepository` domain service, we subscribe to the event and act upon it.
For example:

[source,java]
----
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

@Service
public class BookRepository {

    @EventListener(LibraryMemberLeaveEvent.class)
    public void onLibraryMemberLeaving(LibraryMemberLeaveEvent e) {
        LibraryMember lm = e.getLibraryMember();
        List<Book> lentBooks = findBooksOnLoanFor(lm);
        if(!lentBooks.isEmpty()) {
            sendLetter(lm, lentBooks);
        }
    }

}
----

This design allows the `libraryMember` module to be decoupled from the `book` module.

[#event-hierarchy]
== Event hierarchy

By creating domain event subtypes we can be more semantically precise and in turn providesmore flexibility for subscribers: they can choose whether to be broadly applicable (by subscribing to a superclass) or to be tightly focussed (by subscribing to a subclass).

We recommend that you define event classes at (up to) four scopes:

* at the top "global" scope is the Apache Isis-defined `o.a.i.applib.event.ActionDomainEvent`
* for the "module" scope, create a static class to represent the module itself, and creating nested classes within
* for each "class" scope, create a nested static event class in the domain object's class for all of the domain object's actions
* for each "action" scope, create a nested static event class for that action, inheriting from the "domain object" class.

To put all that into code; at the module level we can define:

[source,java]
----
package com.mycompany.modules.libmem;
...
public static class LibMemModule {
    private LibMemModule() {}
    public abstract static class ActionDomainEvent<S>
                extends org.apache.isis.applib.event.ActionDomainEvent<S> {}
    ...                                                                             // <.>
    public abstract static class PropertyDomainEvent<S,T>
                extends org.apache.isis.applib.event.PropertyDomainEvent<S,T> {}
    public abstract static class CollectionDomainEvent<S,E>
                extends org.apache.isis.applib.event.CollectionDomainEvent<S,E> {}
}
----
<.> similar events for properties and collections should also be defined

For the class-level we can define:

[source,java]
----
public static class LibraryMember {
    public abstract static class ActionDomainEvent
            extends LibMemModule.ActionDomainEvent<LibraryMember> { }
    ...                                                                             // <.>
}
----
<.> similar events for properties and collections should also be defined

and finally at the action level we can define:

[source,java]
----
public class LibraryMember {
    public static class LeaveEvent extends LibraryMember.ActionDomainEvent { }
    @Action(domainEvent=LeaveEvent.class)
    public void leave() {
        //...
    }
    ...
}
----

The subscriber can subscribe either to the general superclass (as before), or to any of the classes in the hierarchy.


=== Variation (for contributing services)

A slight variation on this is to not fix the generic parameter at the class level, ie:

[source,java]
----
public static class LibraryMember {
    public abstract static class ActionDomainEvent<S>
            extends LibMemModule.ActionDomainEvent<S> { }
    ...
}
----

and instead parameterize down at the action level:

[source,java]
----
public class LibraryMember {
    public static class LeaveEvent
            extends LibraryMember.ActionDomainEvent<LibraryMember> { }

    @Action(domainEvent=LeaveEvent.class)
    public void leave() {
        ...
    }

    ...
}
----

This then allows for other classes - in particular domain services contributing members - to also inherit from the class-level domain events.

== Programmatic posting

To programmatically post an event, simply call xref:refguide:applib:index/services/eventbus/EventBusService.adoc#post_Object[EventBusService#post].

The `LibraryMember` example described above could for example be rewritten into:

[source,java]
----
public class LibraryMember {
    @Action()
    public void leave() {
        ...
        eventBusService.post(new LibraryMember.LeaveEvent(/*...*/));    // <.>
    }
    ...
}
----
<.> `LibraryMember.LeaveEvent` could be _any_ class, not just a subclass of `o.a.i.applib.event.ActionDomainEvent`.

In practice we suspect there will be few cases where the programmatic approach is required rather than the declarative approach afforded by xref:refguide:applib:index/annotation/Action.adoc#domainEvent[@Action#domainEvent()] et al.


== Using `WrapperFactory`

Using the declarative approach does require that the method to emit the event is an action called directly by the framework (rather than a helper method programmatically called by that action).
However by using the xref:refguide:applib:index/services/wrapper/WrapperFactory.adoc[WrapperFactory] we can invoke that helper method "through" the framework, thereby allowing the framework to emit events.
(It can also optionally perform validation checks and other concerns associated with the UI).

Another use case for the `WrapperFactory` is when you wish to enforce a (lack-of-) trust boundary between the caller and the callee.

For example, suppose that `Customer#placeOrder(...)` emits a `PlaceOrderEvent`, which is subscribed to by a `ReserveStockSubscriber`.
This subscriber in turn calls `StockManagementService#reserveStock(...)`.
Any business rules on `#reserveStock(...)` should be enforced.

In the `ReserveStockSubscriber`, we therefore use the `WrapperFactory`:

[source,java]
----
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

@Service
public class ReserveStockSubscriber {

    @EventListener(Customer.PlaceOrderEvent.class)
    public void on(Customer.PlaceOrderEvent ev) {
        wrapperFactory.wrap(stockManagementService)
                      .reserveStock(ev.getProduct(), ev.getQuantity());
    }

    @Inject
    StockManagementService stockManagementService;
    @Inject
    WrapperFactory wrapperFactory;
}
----

== Related Services

The `EventBusService` is intended for fine-grained publish/subscribe for object-to-object interactions within an Apache Isis domain object model.
The event propagation is strictly in-memory, and there are no restrictions on the object acting as the event (it need not be serializable, for example).

There are several mechanisms to suport coarse-grained publish/subscribe for system-to-system interactions, from Apache Isis to some other system:

* Command publishing, representing the _intention_ to invoke an action or edit a property.
+
These events apply to actions annotated with xref:refguide:applib:index/annotation/Action.adoc#commandPublishing[@Action#commandPublishing()]) and to properties properties annotated with xref:refguide:applib:index/annotation/Property.adoc#commandPublishing[@Property#commandPublishing]).
+
The events are received by any/all xref:refguide:applib:index/services/publishing/spi/CommandSubscriber.adoc[CommandSubscriber]s.

* Execution publishing, representing the _completion_ of an action invocation or property edit.
+
These events apply to actions annotated with xref:refguide:applib:index/annotation/Action.adoc#executionPublishing[@Action#executionPublishing()]) and properties annotated with xref:refguide:applib:index/annotation/Property.adoc#executionPublishing[@Property#executionPublishing]).
+
The events are received by any/all xref:refguide:applib:index/services/publishing/spi/ExecutionSubscriber.adoc[ExecutionSubscriber]s

* Entity change publishing, representing an entity that has changed its state.
+
These events apply to objects annotated with xref:refguide:applib:index/annotation/DomainObject.adoc#entityChangePublishing[@DomainObject#entityChangePublishing()]).
+
The events are received by any/all xref:refguide:applib:index/services/publishing/spi/EntityChangesSubscriber.adoc[EntityChangesSubscriber]s
