Making An Event Listener
To make an event listener, create a Java class that extends the abstract
class
neo.xredsys.api.services.AsyncEventListenerService
.
This is a convenience class that extends
neo.nursery.AbstractNurseryService
. It provides
boilerplate implementations of the methods defined in the
neo.xredsys.api.IOEventListener
and
neo.xredsys.api.IOEventFilter
interfaces.
Your class must include implementations of the following methods:
accept(event)
-
This method is defined in the
neo.xredsys.api.services.AsyncEventListenerService
class. Use it to determine which events your listener will respond to. Returntrue
for all events you want the listener to respond to.This method is called synchronously and blocks other event listeners from receiving events while it is executing. You should therefore only use it carry out fast initial filtering of events.
handle(event)
-
This method is defined in the
neo.xredsys.api.services.AsyncEventListenerService
class. It is called every time youraccept(event)
method returnstrue
. Use it to perform whatever actions you want to be carried out for accepted events.This method is called asynchronously and therefore does not block other event listeners. The number of events waiting to be responded to by this method can be seen in the
backlog
property. The execution time of this method can be recorded by the optionalHitCollector
.
Your class must also have a public no argument constructor. For example:
public class MyService extends AsyncEventListenerService { public MyService() { super(false); } //More code goes here... }
This constructor creates an AsyncEventListenerService
that listens to all events, both local and remote. If you want to create
a service that only listens to local events, set
super(true)
in the constructor.
Your class may optionally implement the following methods as well:
startEventListener()
-
This method is defined in
neo.xredsys.api.services.AsyncEventListenerService
. You can use it to carry out any actions that you want to be performed when the service is started. You might, for example, use it to validate the configuration of your service. stopEventListener()
-
This method is defined in
neo.xredsys.api.services.AsyncEventListenerService
. You can use it to carry out any actions that you want to be performed when the service is stopped. You might, for example, use it to clear lists that have been populated while the service was running.
For more detailed information about
neo.xredsys.api.services.AsyncEventListenerService
,
see the javadoc.
Here is an example event listener called
com.mycompany.events.NewArticleNotifier
that:
-
Sends an e-mail to a configured e-mail address whenever a new content item is created
-
Validates its configuration on start-up
The class's constructor calls its super constructor with the parameter
true
:
public NewArticleNotifier() { super(true); }
This ensures that the service only listens to local events and will
therefore only send an e-mail when a content item is created on the
local server. Setting this parameter to false
would
result in multiple mails being sent for every content item created (one
from each server in the cluster).
Properties are defined to hold the both the address to which notifications are to be sent and the sender address to be included in the messages. It is considered good practice to inject parameters this way.
public void setEmail(final String pEmail) { this.email = pEmail; } public String getEmail() { return this.email; } public void setEmailSender(final EmailSender pEmailSender) { this.emailSender = pEmailSender; } public EmailSender getEmailSender() { return this.emailSender; }
The accept
method accepts only
OBJECT_CREATED
events, and only for objects of type
article. It is important to ensure that this method returns quickly
since it blocks the execution of other event listeners'
accept
methods. If your accept
method uses several criteria to select events, It is a good idea to
place the if tests that will reject most events first, as here:
@Override protected boolean accept(final IOEvent pEvent) throws Exception { if (IOEvent.OBJECT_CREATED == pEvent.getType()) { if (IOAtom.OBJECTTYPE_ARTICLE == pEvent.getObjectKey().getObjectType()) { return true; } } return false; }
The handle
method is only called only for events
where the accept
method has returned
true
. It is therefore safe to assume in this case
that the input event is an OBJECT_CREATED
event for
an article. The method is executed in a separate thread so it does not
need to be especially fast. If it executes too slowly to keep up with
the number of events being generated then the value of the
backlog
property will increase accordingly.
If you define a hit collector for your event
listener (see Performance monitoring in
Using An Event Listener), then the
execution time of this method will be recorded by the hit collector. You
can view the information gathered by the hit collector on the
escenic-admin
web application's Performance
Summary page. See
here
for information about escenic-admin
.
@Override protected void handle(final IOEvent pEvent) throws Exception { Article article = (Article) pEvent.getObject(); EmailEvent email = new EmailEvent(); email.setRecipients(new Address[] {new InternetAddress(getEmail())}); email.setSubject("New article with title '" + article.getTitle() + "' was created"); getEmailSender().sendMessage(email); }
The startEventListener
method is called after all
properties have been set, but before the
EventListener
is registered with the
Content Engine
so that it can receive events. If startEventListener
throws an exception then the EventListener
is not
registered and will not receive any events. The
startEventListener
method must include a
super.startEventListener()
call.
The example shown here performs some simple checks on the supplied configuration values:
@Override protected void startEventListener() throws IllegalStateException, IllegalArgumentException, Exception { super.startEventListener(); Validate.notNull(getEmailSender(), "Email sender is not set, will not start the '" + getClass().getName() + "' service"); Validate.notNull(getEmail(), "Email is not set, will not start the '" + getClass().getName() + "' service"); }
Here is the example code again in full, including all the necessary boilerplate code:
package com.mycompany.events; import javax.mail.Address; import javax.mail.internet.InternetAddress; import neo.xredsys.api.Article; import neo.xredsys.api.IOAtom; import neo.xredsys.api.IOEvent; import neo.xredsys.api.services.AsyncEventListenerService; import neo.xredsys.email.EmailEvent; import neo.xredsys.email.EmailSender; import org.apache.commons.lang.Validate; public class NewArticleNotifier extends AsyncEventListenerService { public NewArticleNotifier() { super(true); } private String email; public void setEmail(final String pEmail) { this.email = pEmail; } public String getEmail() { return this.email; } private EmailSender emailSender; public void setEmailSender(final EmailSender pEmailSender) { this.emailSender = pEmailSender; } public EmailSender getEmailSender() { return this.emailSender; } @Override protected boolean accept(final IOEvent pEvent) throws Exception { if (IOEvent.OBJECT_CREATED == pEvent.getType()) { if (IOAtom.OBJECTTYPE_ARTICLE == pEvent.getObjectKey().getObjectType()) { return true; } } return false; } @Override protected void handle(final IOEvent pEvent) throws Exception { Article article = (Article) pEvent.getObject(); EmailEvent email = new EmailEvent(); email.setRecipients(new Address[] {new InternetAddress(getEmail())}); email.setSubject("New article with title '" + article.getTitle() + "' was created"); getEmailSender().sendMessage(email); } @Override protected void startEventListener() throws IllegalStateException, IllegalArgumentException, Exception { super.startEventListener(); Validate.notNull(getEmailSender(), "Email sender is not set, will not start the '" + getClass().getName() + "' service"); Validate.notNull(getEmail(), "Email is not set, will not start the '" + getClass().getName() + "' service"); } }
Before an event listener can be used it must be:
-
Compiled
-
Added to the Content Engine's classpath
To compile the example you must add the following JAR files to the classpath:
engine-core-6.21.5-1.jar
-
This is the Escenic jar that contain most of the classes needed.
common-nursery-6.21.5-1.jar
-
The Content Engine's dependency injection framework.
commons-lang-2.3.jar
-
The Content Engine's validation framework.
mail-1.4.jar
-
This jar contain the dependency injection framework (Nursery) we use.