public interface Hub
Producers fire events through the hub ((cf. fire(Object, String...))), which routes them to all the
observers that have previously subscribed to receive them (subscribe(Object))).
Producers, Observers, and Events
Producers, observers, and events are arbitrary objects. Observers are objects with one or more methods marked with
the Observes annotation and taking events as their only parameter. Observes methods can have any name
and access modifier, and may throw any kind of exception. Any object value may serve as an event. The following
example illustrates:
class Observer {
{@literal @}Observes
void someMethod(int event) {...}
}
Hub hub = ....;
hub.subscribe(new Observer());
hub.fire(10);
In general, events and Observes methods match events when the type of events is a subtype of the
type of the single parameter of the observer methods. Normal java subtyping rule apply, with the following
exceptions:
The type matching algorithm can be refined by qualifying events and event types with one ore more labels that
observers declare in Observes annotations and produce specify when firing events. An example of using
qualifiers is the following:
class Observer {
{@literal @}Observes({"currency","dollars"})
void onDollarPayment(Integer amount) {...}
{@literal @}Observes({"currency","euro"})
void onEuroPayment(Integer amount) {...}
{@literal @}Observes({"currency"})
void onAnyPayment(Integer amount) {...}
}
Hub hub = ....;
hub.subscribe(new Observer());
hub.fire(10, "currency", "dollars");
Here the methods onDollarPayment() and onAnyPayment() receive the event, while the method
onEuroPayment() does not. In general, Observes methods are notified if they specify a subset of
the qualifiers associated with events, including no qualifiers at all.
Event Grouping
Observers that perform costly operations may wish to process rapid bursts of events at once. Observes methods
may then specify the minimal delay in milliseconds between two successive notifications {cf. @link Observes#every()}.
All the events produced within this delay are grouped and delivered in a collection when the delay expires and in the
order in which they were produced. Observers process the collections as they see fit (e.g. consume the most recent,
merge all the events, aggregate data in the events, etc). For example:
{@literal @}Observes(value="change",every=1000)
void onPayments(List<Integer> payments) {...}
Any Collection type can be used for the delivery of the events.
Critical, Safe, and Resilient Consumers
Firing events blocks producers until all matching Observes methods that are marked Observes.Kind.critical have
been executed (cf. Observes.kind()). Critical Observes methods execute sequentially in an
unpredictable order, and any exception they raise is reported to producers. Producers do not block instead for the
execution of Observes methods that are marked Observes.Kind.safe or Observes.Kind.resilient. Safe and resilient
Observes methods execute in parallel and any exception they raise is logged. Finally, the difference between
Observes.Kind.safe and Observes.Kind.resilient handlers is that the former execute if and only if there are no critical
failures, while the latter execute in all cases.
*
Parametric Observers and Events
Parametric observers and events can be still be used in either one of two ways:
Event class, which is provided to capture type information
which is otherwise lost at runtime due to type erasure. This approach is more verbose but also safer.
Consider the following example of event wrapping:
class Observer {
{@literal @}Observes
void someMethod(MyType<Integer> event) {...}
}
Hub hub = ....;
hub.subscribe(new Observer());
MyType<Integer> event = ...
hub.fire(new Event<MyType<Integer>>(event){});
where new Event(event){} instantiates an anonymous Event subclass. The idiom is
hardly palatable, but it does circumvent the limitation of type erasure in Java. Currently, the follow limitations
apply:
? extends ...). Lower bounds are not currently supported.
Observes| Modifier and Type | Method and Description |
|---|---|
void |
fire(Object event,
String... qualifiers)
Fires an event to all observers which have subscribed for them, blocking the client until all the critical
observers have executed.
|
void |
stop()
Signals that this hub is no longer needed and can release its resources.
|
void |
subscribe(Object observer)
Subscribes an observer for notification of events of a given type.
|
boolean |
unsubscribe(Object observer)
Unsubscribes an observer.
|
void |
waitFor(Class<?> eventType)
Blocks the caller until an event of a given type occurs.
|
void |
waitFor(Class<?> eventType,
long duration,
TimeUnit unit)
Blocks the caller until an event of a given type occurs or a given length of time elapses.
|
void subscribe(Object observer)
The single parameter of any method of the observer annotated with Observes identifies the type of the
events observed by the observer.
observer - the observerIllegalArgumentException - if the observer declares no methods annotated with Observes, or such
methods do not declare a single parameterObservesboolean unsubscribe(Object observer)
observer - the observertrue if the observer is found and unsubscribed.void fire(Object event, String... qualifiers)
event - the eventqualifiers - optional event qualifiersvoid waitFor(Class<?> eventType)
eventType - the event typeRuntimeException - if the wait is interruptedvoid waitFor(Class<?> eventType, long duration, TimeUnit unit)
eventType - the event typeduration - the length of time to wait forunit - the time unit of the durationIllegalArgumentException - if the inputs are null or the duration is less or equal than zeroRuntimeException - if the wait is interruptedvoid stop()
Copyright © 2017. All Rights Reserved.