by Cuong Nguyen
Changes to the database (i.e. create, update, delete) will fire an event. At the back-end of the ActionCenters system,we have built a mechanism to capture those events and deliver them to appropriate listeners. We call the mechanism Event Notification
The purpose of this document is to explain how Event Notification works and to guide on how to create a new web server event listener.
The Event Notification mechanism is visually described in the diagram below:
Architecturally, the ActionCenters backend has 2 main modules: the web server which includes the servlets that handle requests from the web clients and the UDM or Universal Data Model module managing managing data transactions to the database. CometD is an API handling publish/subscribe messages between the web server and the web clients and is a part of the web server module. The UDM interact with the database through Hibernate, an utility API that maps database tables to Java persistent objects.
Every time there is a web client's request that requires a change in the database e.g. add, remove, update a contribution or relationship in the database, a typical route for the request is to go to the web server, then to the UDM, then to the Hibernate and finally actually updated in the database (as indicated by the green arrow in the diagram). As soon as the change is committed to the database, the Hibernate will fire an event to report the change. The event will follow the path as indicated by the orange arrows in the diagram. At first, the changes will be caught by the UDM event listeners, which are:
org.actioncenters.udm.history.SaveHistoricalEventListener: Listening to the save or update event in the database.
org.actioncenters.udm.history.DeleteHistoricalEventListener: Listening to the delete event in the database.
org.actioncenters.udm.notification.PostCommitEventListener: Listening to the post-commit-insert event in the database.
The readers can refer to the configuration file actioncenters-udm-db.xml to see the relations between the Hibernate event listeners and the UDM event listeners.
After that, the UDM event listeners will check whether the newly changed entity allows notification of its changes (since different types of entities allow different specific change events on them to be notified). If yes, the UDM event listeners will let the entity to inform the Contribution Notification Service of the change.
The Contribution Notification Service(the org.actioncenters.core.contribution.svc.notification.impl.ContributionNotificationService class) is in charge of managing all the listeners in the web server. As soon as it receive the notification of the changes from some entity, it will deliver that event to the web server listeners which have registered for that event(more on Contribution Notification Service and web server listeners in the in the next section).
The web server listeners, on their turn, will perform some actions in response to the event they receive. For example, a web server listener might publish a CometD message to inform the web clients that a new contribution has been added.
The Event Notification has been used intensively in the ActionCenters system, mainly to ensure that the all the changes appear in the web clients must happen only after the changes have been commited in the database.
At times, developers want to handle database events in their own ways. In order to do that, they can create their own web server event listener and register it with the Contribution Notification Service.
This section illustrates how we can do that by showing the steps of creating the "CustomAddRelationshipListener". The purpose of this listener is to do something with the new relationship is added to the database.
As the first step, we create a new class that implements a listener interface. ActionCenters offers a number of interfaces corresponding to the "add", "remove", "update" events of some specific object. For example, to catch the "add a new relationship" event from the database we have IAddRelationshipListener interface; to catch the "remove a contribution" event from the database we have IRemoveContributionListener interface. The interfaces are all in the org.actioncenters.core.contribution.svc.notification.listeners package.
For our purpose, our new listener class will implement the IAddRelationListener interface. The code for the new class should look like this:
package org.yournamehere.listeners; import org.actioncenters.core.contribution.svc.notification.listeners.IAddRelationshipListener; public class CustomAddRelationshipListener implements IAddRelationshipListener { @Override public void relationshipAdded(IRelationship newRelationship) { //Do something here on the event that a new relationship is added } }
After we have a new listener class, we need to register this listener with the Contribution Notification Service. To do so, we just need to plug in a new bean of our listener class as a property of the Contribution Notification Service bean in the actioncenters.xml configuration file, as our ActionCenters backend has been built on Spring framework.
Specifically, as you go to the actioncenters.xml configuration file, locate the <bean id="notificationService" class="org.actioncenters.core.contribution.svc.notification.impl.ContributionNotificationService">, you should see something like this:
<bean id="notificationService" class="org.actioncenters.core.contribution.svc.notification.impl.ContributionNotificationService"> <property name="addContributionListeners"> <set> //... </set> </property> <property name="addRelationshipListeners"> <set> <bean class="org.actioncenters.listeners.contributionsservice.AddRelationshipListener" /> <bean class="org.actioncenters.listeners.contributionsservice.cachemanagement.AddRelationshipListener" /> </set> </property> <property name="removeContributionListeners"> <set> //... </set> </property> //... </bean>
Contribution Notification Service manages the listeners by classifying them into sets of listeners of the same type. For example, we have a set of "addContributionListers" which list all the listeners that listen to the "adding a new contribution" event, or the set of "addRelationshipListerners" which list the listeners listening to "adding a new relationship" event(see the code above). As our new listener listens to "adding a new relationship" event, we will list it in the "addRelationshipListeners" set. The code should look like this:
<bean id="notificationService" class="org.actioncenters.core.contribution.svc.notification.impl.ContributionNotificationService"> <property name="addContributionListeners"> <set> //... </set> </property> <property name="addRelationshipListeners"> <set> <bean class="org.actioncenters.listeners.contributionsservice.AddRelationshipListener" /> <bean class="org.actioncenters.listeners.contributionsservice.cachemanagement.AddRelationshipListener" /> <bean class="org.yournamehere.listeners.CustomAddRelationshipListener" /> </set> </property> <property name="removeContributionListeners"> <set> //... </set> </property> //... </bean>
To this point, the registration of the new listener with the Contribution Notification Service has completed. The new listener should be ready to work.