The idea described here is originally by Tomek Szymański. I just enhanced it a little.
Seam events are a very convenient tool to divide your business logic into smaller pieces, and add some new behaviour as necessary. However, they are very unstructured – an event name is just a String that you’ve got to remember. It’s hard to find out what events your application raises, what are the parameters and in what situations the events are actually raised – there’s no place (in code) to document it.Inflatable Toys
As a remedy, you can create a special package (let’s say events
), where, for each event that your application raises, you create an interface corresponding to that event. So, if you raise an event org.myapp.events.MessageCreated
, you create a MessageCreated
interface in the org.myapp.events
package. In the javadoc for this interface, you can describe when the event is raised and what are the parameters.
Furthermore, all components that contain methods, which observe the event, can implement the corresponding event interface (so it will be used as a marker interface). All modern IDEs let you find implementations of an interface, so finding out which methods are observing your event is trivial!
Taking it a step further, the marker interface may also contain a method declaration. An implementation of that method should observe the event. That way, you can make it even easier to provide information about the parameters of the event. For example:
package org.myapp.events;
public interface MessageCreated {
void handleMessageCreated(Message message, User user);
}
package org.myapp.components;
@Name("sendEmails")
public class SendEmails implements MessageCreated {
@Observer("org.myapp.events.MessageCreated")
void handleMessageCreated(Message message, User user) {
// Send an e-mail to the administrator that there is a new
// message
}
}
Finally, what about raising events? If you raise them programmatically, you may also use the interface, instead of the String
form of the event name. For example:
public void sendMessage() {
// ...
Events.instance().raiseEvent(MessageCreated.class.getName(),
message, user);
// ...
}
This has two benefits. Firstly, by finding the usages of the MessageCreated
interface, you know where the event is raised. Secondly, it’s refactor-safe: when you decide to rename the event, you just rename or move the interface. Your IDE does the rest for you (unless your IDE is vim ;) ).
Of course, you’ll still need to use the String
form of the event’s name in the @Raise
annotation and when raising events in pages.xml
.
To sum up: creating marker interfaces for events gives you a place to document them, and can provide partial safe refactoring of event names. What are your practicies when using Seam events?
Adam
comments powered by Disqus