org.gcube.common.events
Interface Hub

All Known Implementing Classes:
DefaultHub

public interface Hub

Mediates between producers and observers of events.

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:

Qualifiers

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: