Using BarbelHisto events
BarbelHisto
provides an event mechanism to extend the core functionality. Clients can implement event handler methods to handle the events. Amongst other uses these event handlers can drive the integration with external data sources. The event mechanism is based on Google Guavas EventBus
implementation.
Events are posted to synchronous and/or asynchronous EventBus
instances. In case events are posted to synchronous and asynchronous event bus, they are refered to as posted 'both way'. Synchronous events are executed in the same thread issueing the event, which means that the handler methods listening to synchronous events execute synchronously. This can be usefull for many scenarios, like pre-fetching data in a lazy loading BarbelHisto
instance. See the persistence tutorial for details.
Event types
The following events are posted by BarbelHisto
:
EventType.BARBELINITIALIZED
whenBarbelHisto
instance is created, only once perBarbelHisto
session, both way.EventType.INITIALIZEJOURNAL
when journal is created, only once per document journal creation, both wayEventType.ACQUIRELOCK
, whenBarbelHisto
starts updating a document journal, synchronous postEventType.REPLACEBITEMPORAL
, when versions are inactivated, maybe multiple times in a single update operation, both wayEventType.INSERTBITEMPORAL
, when new versions are inserted, one time per update operation, both wayEventType.UPDATEFINISHED
, when the update operation for journal was completed, once per save operation, both wayEventType.RELEASELOCK
, whenBarbelHisto
finishes the updating cycle, synchronous post- The
EventType.RETRIEVEDATA
event is posted each time when clients retrieve data fromBarbelHisto
. - The
EventType.ONLOADOPERATION
event is posted each time when clients load data intoBarbelHisto
using theload
operation. - The
EventType.UNONLOADOPERATION
event is posted each time when clients unload data fromBarbelHisto
using theunload
operation.
Events 2-7 are posted in exactly that order in an update operation performed by the save()
method of BarbelHisto
.
Event handler methods
Listeners to these events are implemented as the following examples:
public class UpdateEventListeners {
@Subscribe
public void handleInitialization(BarbelInitializedEvent event) {
// ... handle event
}
@Subscribe
public void handleInserts(InsertBitemporalEvent event) {
// ... handle event
}
@Subscribe
public void handleReplacements(ReplaceBitemporalEvent event) {
// ... handle event
}
}
@SuppressWarnings("unchecked")
public class LazyLoadingListener {
@Subscribe
public void handleRetrieveData(RetrieveDataEvent event) {
// ... handle event
}
@Subscribe
public void handleInitializeJournal(InitializeJournalEvent event) {
// ... handle event
}
}
Use the @Subscribe
annotation to subscribe the handler method to the event declared as parameter. The event passed contains the eventContext
that can be used to drive processing. It contains an instance of the DocumentJournal
that was or will be updated and the like. Clients can use these context parameters to implement sophisticated event handling. The context data is always a copy of what originally happened, so clients cannot harm BarbelHisto
s internal consistency.
Register listeners
To put listener classes in action clients register instances of the listener classes with BarbelHistoBuilder
.
BarbelHisto<DefaultDocument> core = BarbelHistoBuilder.barbel().withMode(BarbelMode.BITEMPORAL)
.withSynchronousEventListener(new LazyLoadingListener()).build();
The above snippet shows a registration in the synchronous event bus. Registration with asynchronous bus works accordingly.
Error handling
By default handler methods fail silently. This is because subsequent handler methods should still be executed when a previous handler fails. In synchronous scenarios, however, it can be very useful to stop processing if an event handler fails. Clients stop processing by setting the event passed into the handler method to HistoEvent.failed()
. As a consequence, BarbelHisto
will rollback any changes made to the instance in the running update operation and return an HistoEventFailedException
to the client. Here is an example pattern of using the described error handling.
public static class ShadowCollectionListeners {
@Subscribe
public void handleInserts(InsertBitemporalEvent event) {
try {
// some processing that may fail and client wants to handle that situation
} catch (Exception e) {
event.failed();
}
}
@Subscribe
public void handleReplacements(ReplaceBitemporalEvent event) {
try {
// some processing that may fail and client wants to handle that situation
} catch (Exception e) {
event.failed();
}
}
}
When an exception is thrown during processing of these event handlers, the event is set to failed, and BarbelHisto
will throw an exception right after leaving the event handler.