I ever tried using
Apache Camel to solve the
event notification problem.
Given a Sensor (event source) and a Display (listener), here's how I would implement it:
public class Sensor {
@EndpointInject(uri="seda:sensor.events")
private ProducerTemplate sensorProducer;
private void fireSensor(SensorEvent sensorEvent) {
sensorProducer.sendBody(sensorEvent);
}
}
public class Display {
@Consume(uri="seda:sensor.events")
public void sensorUpdated(SensorEvent sensorEvent) {
// ... code to update ...
}
}
Advantages
As you can see, the code is pretty concise and elegant. Even
Listener interfaces are not needed here. Simply agree on an event object, and the endpoint (channel) URI, and the event is wired up.
POJO is somewhat preserved, if not for
ProducerTemplate.
It's possible to receive response from listeners (asynchronously), but I think it should be thought as a feature of the routing engine, not the event notification framework.
Issues
The above isn't a true
publish-subscribe though, since
Camel's seda component won't support multiple consumers (multicasting) until Camel 2.2.0 is released.
It also uses hard coded endpoint URIs, which is quick and convenient for singleton event sources but falls apart when there are several event sources of the same type.
A routing engine introduces one more concept besides event sources, listeners, and event objects:
endpoints (channels a.k.a. topics). I hope it's possible to remove this, but all publish-subscribe event notification frameworks use it, including Dojo AJAX Toolkit's
dojo.publish.
The event source object can be put inside the event object so the listeners can filter it, which addresses one side of the problem.
Making endpoint URIs dynamic is another alternative, i.e. referring to its own Spring bean name via
BeanNameAware.
Yet another alternative is having a router-consumer that routes the messages (events) to actual listeners. This way, listeners attach to the router similar to old JavaBean event notification way. But I think this is getting too complex.
Dynamic Endpoints
Here's some code to illustrate how to implement event notification with Apache Camel dynamic endpoints.
public class Sensor {
// dynamically created or injected
private Endpoint sensorEndpoint;
@EndpointInject
private ProducerTemplate producer;
private void fireSensor(SensorEvent sensorEvent) {
producer.sendBody(sensorEndpoint, sensorEvent);
}
}
public class Display {
@Autowired
private Endpoint sensorEndpoint;
private Consumer sensorConsumer;
@PostConstruct
public void initialize() {
// BeanProcessor should automatically
// match the method based on argument type
sensorConsumer = sensorEndpoint.createConsumer(
new BeanProcessor(this, sensorEndpoint.getCamelContext()));
sensorConsumer.start();
}
@PreDestroy
public void destroy() {
sensorConsumer.stop();
}
public void sensorUpdated(SensorEvent sensorEvent) {
// ... code to update ...
}
}
It's far from elegant. Especially the part where the
Event Driven Consumer has to be created, configured, started, and stopped manually.
It's also somewhat decoupled, since the consumer needs to only know the endpoint object or the endpoint URI. And the producer doesn't have to iterate all consumers and call their callbacks one by one.
Update: I've written a more
advanced proof-of-concept event notification with Apache Camel here.