swing and spring integration - topics - part 3
If you look at different event broker implementation, such as that in OSGi, contemplated for e4 and eventbus.org, they all talk about subscribing to events based on a topic string. The topic string is like a URI that denotes topics of interest and typically relate to some type of hierarchy of objects, actions, services or some combination of these. We saw in the last blog that is fairly easy to implement a subscriber type mechanism that selects on an event type and an arbitrary SpEL expression (AND’d together). Combined together with spring integration’s method injection, we can also have a flexible method signature. How would we implement event topics specified as URI-like strings? You can also think of these strings similar to RESTful URIs that denote traversing a container hierarchy. Seems useful.
In addition to topics, we also may want to filter events that we process based on the source in some way. While we do not want to go back to the tight coupling associated with the classic listener observer pattern, how do filter on events from specific sources for specific properties/attributes on objects (similar to the addPropertyChangeListener interface that can listen to a specific property or to all properties)? This implies we want fairly fine grained control over what messages we receive. Clearly, we are placing greater and greater burdens on the receivers/listeners than in the standard java listener architectural style which places the burden of selecting “who” receives which messages on the event source.
In a sense, we want to place the burden of listening to events on the listener and not have any dependencies on the source of events. If we think of dependencies, our listener needs to know topics, filtering criteria (about when to handle the event) as well as subject. A subject is an object that the event is about. It may or may not be the source of the event. Other objects could fire an event/message on-behalf of a subject.
Our approach is to use spring integration’s headers to record the topic and subject then allow the event subscriber to filter on those criteria. After all, the headers are just another source of metadata about the event that may not actually be part of the event object.
- Add a subject property to the headers.
- Add a topic property to the headers. The topic should be a string path using a separator character to separate logical concepts in the topic “URI.” We would need to enhance our internal machinery to provide regex matching capability on the topic.
- Add a topic parameter to some of the MessageChannel.send() methods in the EventPublisher convenience class.
- A suggested naming scheme for topics within an application.
- Leave it to the method handler in the POJO object to determine if the subject is the right dependency to act on. Because the subject is the logical dependency of the event handling object, we do not want to enforce restrictions on how dependencies are stored—again we are placing a bigger burden on the listener/receiver/handler than on the source of the event.
First, we can add a MessageSelector that selects on a header value keyed by the string “topic” and use a regex. We’ll expand our annotation EventTypeSubscriber to handle topic regex expressions:
and enhance the annotation then add publishing with a topic header value in our EventPublisher class: we need some additional changes to create the selector based on the topic pattern but you can look at the code for those portions. We can also define a logger for all messages on a channel (like a wire-tap or a channel interceptor): and we see that the output is what we expect. Regexes are tricky to master so specifying a topic path with a more friendly regex matcher would probably make sense e.g. * means matching any remaining paths, etc. A couple of the last points in our approach still need to be taken care of. One is how to determine if an event is from an object of specific interest that we want to process a message from? That object, being the subject, would be a dependency. We see that we can add a “source” object to our message payloads, much like deriving from java.util.EventObject but then our message payloads all have to derive from an event object. This seems burdensome so we can add a subject header value to our messages. Since the spring integration project is all about within JVM integration, we should be okay with this. What if the messages are transported across another wire protocol? We’ll have to deal with that when the need arises because there would probably be application specific approaches we would need to take. For now, lets put the subject in the header. We’ll define some utilities methods to help extract the value form the header. We can always use @Header annotation to have our annotated method obtain the “subject” object directly a parameter in our annotated method call. We would then keep a list of dependencies in our handler object and check the subject to see if it is a dependency that we care about. As in:and add a little bit of test configuration in the context to test it out. Note that any object can be a dependency as long as its in the dependency list and has a well defined equals method so that the contains(..) check checks correctly. As to the last question, what is a strong approach to creating topics, well that's pretty application dependent. You can look at eventbus.org or eclipse e4 for this topic. Generally, you'll want some type of base name that is unique, coupled with the component name and perhaps a verb, such as GET or DELETE or ADD separated by a path character, say '/'. The, construct your regex topic pattern matchers carefully. If you want to use the topics for property/attribute changes on individual objects, you'll probably want to add some more machinery to the EventPublisher class to handle adding new and old values, etc. much in the spirit of a property change event. Of course, you could just send the property change event object to the channel and ensure that the any receivers has its dependency list if that is relevant to your application. If you want to use the channel for property change events, its probably worth writing a small adapter because many libraries expect the PCL architectural style and you need to adapt PCL firings to fire onto the primary channel. and subscriptions can, if you use topic strings carefully, be something like: Topic strings are highly prone to mistyping so be careful.