Wednesday, 17 April 2013

CometD and Camel in the Enterprise - A Working Example

Full code is available on GitHub

All the Java code for the project is available in Github - requires Maven to run. See the README for more details - link here.

The Key Tech Players

The demo shows these various pieces of kit working (hopefully) harmoniously together:

What's the Scenario?

  • Imagine a complex enterprise infrastructure, running a bunch of different systems, servers and technologies, with data flowing between them all.
  • Commonly there will be some sort of Messaging system in play - handling routing and transformation of the various message flows. In our example we have ApacheMQ as the Messaging Server.
  • The endpoints of some of these flows may be to send data to multiple clients. One way to do this is to route messages to a Topic, and have many clients subscribed to that topic - this is easy of the clients are Java, but not so easy if the clients are Browsers.
  • Typically browser clients will have to use a hand rolled polling approach to check for new data being available.
  • Using CometD - the Browser can use some javascript to subscribe to a CometD channel, keeping a long running connection open - and the endpoint of that channel can push data down directly to all its subscribers. Handily, Apache Camel comes with a CometD plugin that can handle all this on the server side for us.

The CometD and Camel Demo

The demo shows HTML messages being sent to an ActiveMQ JMS Queue, from where they are picked up by Camel and then routed to a CometD channel endpoint.

A HTML page consumes messages from the CometD channel - and as they are received, adds them to a list on the web page. An example of the HTML page is shown below (I've added some JQuery to initially flash the images in red, and then fade them out to black over time - just to make it obvious as new messages arrive).

The messages are just simple, generated automatically from a Java client app, which pushes them to ActiveMQ using a Spring JMSTemplate.



This flow is shown in the diagram below. All three constituent parts can be run from the same project (but they must be started in the sequence shown - ActiveMQ/Camel server first, then web browser, then Java client)


Running the Demo

  • See the README file in Github for full details on how to run the demo (just remember they need to be started in the sequence above - ActiveMQ\Camel server needs to be running first for the browser to consume the cometd channel and the client to send JMS message)

The Camel Route

  • Properties are set in application.properties

  • The Camel Route - listens on a Queue and outputs to a CometD channel

The Javascript Consumer



The Java Client Message Dispatcher


The Java Client Message Creator


Future Extensions


  • Obviously this is a pretty simple demo - in a real world situation you may not want to be sending raw HTML down the channel. A better solution would be JSON, allowing the client to extract and format how it wanted to.
  • (And if you're using Camel - then you're probably doing a bunch of other conversions and processing in the space between receiving and publishing the data.)

Sunday, 3 March 2013

Spring ActiveMQ Producer Client Template

Available on GitHub

Demo available on GitHub

Overview

This is just a very small, very simple template project for sending messages to JMS queues.

In my current role we have a lot of different components and systems glued together by ActiveMQ and Camel. When developing\integration testing in this environment - it is often useful to create ad-hoc messages and send them to queues directly. This is usually the case when you need to test a subset of a larger system.

I usually knock up a test app to do this, often replicating this functionality time and time again. So I thought it might be useful to pop this into a simple template project that can be easily reused. It also made sense to 'mavenise' and 'springify' to make it more easily extensible if you need to plug in other components and features in tests.

Just to reiterate - this is just a starting point for developer style, ad hoc testing to support the development process.

Running the Demo

  1. Prerequisites
    1. Running instance of ActiveMQ (local/remote)
    2. Maven and JDK installed
  2. Configuring
    1. Edit application.properties to point to your ActiveMQ instance - specifying broker url and queue name
    2. Edit 'StartDemo.java' to provide the ObjectMessage the endpoint is expecting
    3. Type 'maven exec:java' to run the StartDemo class

application.properties


Looking at the Code

All the Spring configuration is set up in the main application-context.xml

application-context.xml



The ObjectMessages are created in the main StartDemo.java class

StartDemo.java

Communication with the server is abstracted away into a Dispatcher object.

MessageDispatcher.java

And that's about it really!

Conclusion 


As stated at the start - this is just a throwaway project I use as a starting point when I need to write something to send messages to an ActiveMQ Queue/

It's a compromise between something super simple (like a simple class), and something that lends itself easily to being extended. What can often start off as a simple test can grow into something more complex - and as we have maven and spring all configured at the start - it's then very easy to add in extra dependencies if you find you need them.

Sunday, 24 February 2013

Complex Event Processing Made Easy (using Esper)


The following is a very simple example of event stream processing (using the ESPER engine).

 

Note - a full working example is available over on GitHub:



What is Complex Event processing (CEP)?

Complex Event Processing (CEP), or Event Stream Stream Processing (ESP) are technologies commonly used in Event-Driven systems. These type of systems consume, and react to a stream of event data in real time. Typically these will be things like financial trading, fraud identification and process monitoring systems – where you need to identify, make sense of, and react quickly to emerging patterns in a stream of data events.

Key Components of a CEP system

A CEP system is like your typical database model turned upside down. Whereas a typical database stores data, and runs queries against the data, a CEP data stores queries, and runs data through the queries.

To do this it basically needs:
  • Data – in the form of ‘Events’
  • Queries – using EPL (‘Event Processing Language’)
  • Listeners – code that ‘does something’ if the queries return results

A Simple Example - A Nuclear Power Plant

Take the example of a Nuclear Power Station..




Now, this is just an example – so please try and suspend your disbelief if you know something about Nuclear Cores, Critical Temperatures, and the like. It’s just an example. I could have picked equally unbelievable financial transaction data. But ...

Monitoring the Core Temperature

 Now I don’t know what the core is, or if it even exists in reality – but for this example lets assume our power station has one, and if it gets too hot – well, very bad things happen..



Lets also assume that we have temperature gauges (thermometers?) in place which take a reading of the core temperature every second – and send the data to a central monitoring system.

What are the requirements?

We need to be warned when 3 types of events are detected:
  • MONITOR
    • just tell us the average temperature every 10 seconds - for information purposes
  • WARNING
    • WARN us if we have 2 consecutive temperatures above a certain threshold
  • CRITICAL
    • ALERT us if we have 4 consecutive events, with the first one above a certain threshold, and each subsequent one greater than the last – and the last one being 1.5 times greater than the first. This is trying to alert us that we have a sudden, rising escalating temperature spike – a bit like the diagram below. And let’s assume this is a very bad thing.

Using Esper

  • There are a number of ways you could approach building a system to handle these requirements. For the purpose of this post though - we will look at using Esper to tackle this problem
  • How we approach this with Esper is:
    • Using Esper – we can create 3 queries (using EPL - Esper Query Language) to model each of these event patterns.
    • We then attach a listener to each query - this will be triggered when the EPL detects a matching pattern of events)
    • We create an Esper service, and register these queries (and their listeners)
    • We can then just throw Temperature data through the service – and let Esper tell alert the listeners when we get matches.
    • (A working example of this simple solution is available on Githib - see link above)

Our Simple ESPER Solution

At the core of the system are the 3 queries for detecting the events.

Query 1 – MONITOR (Just monitor the  average temperature)

select avg(value) as avg_val 
from TemperatureEvent.win:time_batch(10 sec)

Query 2 – WARN (Tell us if we have 2 consecutive events which breach a threshold)


select * from TemperatureEvent "
 match_recognize ( 
   measures A as temp1, B as temp2 
   pattern (A B) 
   define  
     A as A.temperature > 400, 
     B as B.temperature > 400)

Query 3 – CRITICAL - 4 consecutive rising values above all above 100 with the fourth value being 1.5x greater than the first


select * from TemperatureEvent 
match_recognize ( 
measures A as temp1, B as temp2, C as temp3, D as temp4 
pattern (A B C D) 
define
A as A.temperature > 100, 
B as (A.temperature < B.value), 
C as (B.temperature < C.value), 
D as (C.temperature < D.value) and D.value > 
(A.value * 1.5))

Some Code Snippets

TemperatureEvent

  • We assume our incoming data arrives in the form of a TemperatureEvent POJO
  • If it doesn't - we can convert it to one, e.g. if it comes in via a JMS queue, our queue listener can convert it to a POJO. We don't have to do this, but doing so decouples us from the incoming data structure, and gives us more flexibility if we start to do more processing in our Java code outside the core Esper queries. An example of our POJO is below

package com.cor.cep.event;

package com.cor.cep.event;

import java.util.Date;

/**
 * Immutable Temperature Event class. 
 * The process control system creates these events. 
 * The TemperatureEventHandler picks these up 
 * and processes them.
 */
public class TemperatureEvent {

    /** Temperature in Celcius. */
    private int temperature;
    
    /** Time temerature reading was taken. */
    private Date timeOfReading;
    
    /**
     * Single value constructor.
     * @param value Temperature in Celsius.
     */
    /**
     * Temerature constructor.
     * @param temperature Temperature in Celsius
     * @param timeOfReading Time of Reading
     */
    public TemperatureEvent(int temperature, 
            Date timeOfReading) {
        this.temperature = temperature;
        this.timeOfReading = timeOfReading;
    }

    /**
     * Get the Temperature.
     * @return Temperature in Celsius
     */
    public int getTemperature() {
        return temperature;
    }
       
    /**
     * Get time Temperature reading was taken.
     * @return Time of Reading
     */
    public Date getTimeOfReading() {
        return timeOfReading;
    }

    @Override
    public String toString() {
        return "TemperatureEvent [" + temperature + "C]";
    }

}




Handling this Event

  • In our main handler class - TemperatureEventHandler.java, we initialise the Esper service. We register the package containing our TemperatureEvent so the EPL can use it.
  • We also create our 3 statements and add a listener to each statement
    

/**
 * Auto initialise our service after Spring bean wiring is complete.
 */
@Override
public void afterPropertiesSet() throws Exception {
    initService();
}


/**
 * Configure Esper Statement(s).
 */
public void initService() {

    Configuration config = new Configuration();
        
    // Recognise domain objects in this package in Esper.
    config.addEventTypeAutoName("com.cor.cep.event");
    epService = EPServiceProviderManager.getDefaultProvider(config);

    createCriticalTemperatureCheckExpression();
    createWarningTemperatureCheckExpression();
    createTemperatureMonitorExpression();
}


  • An example of creating the Critical Temperature warning and attaching the listener

   /**
     * EPL to check for a sudden critical rise across 4 events, 
     * where the last event is 1.5x greater than the first. 
     * This is checking for a sudden, sustained escalating 
     * rise in the temperature
     */
    private void createCriticalTemperatureCheckExpression() {
        
        LOG.debug("create Critical Temperature Check Expression");
        EPAdministrator epAdmin = epService.getEPAdministrator();
        criticalEventStatement = 
                epAdmin.createEPL(criticalEventSubscriber.getStatement());
        criticalEventStatement.setSubscriber(criticalEventSubscriber);
    }


  • And finally - an example of the listener for the Critical event. This just logs some debug - that's as far as this demo goes.

package com.cor.cep.subscriber;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.cor.cep.event.TemperatureEvent;

/**
 * Wraps Esper Statement and Listener. No dependency on Esper libraries.
 */
@Component
public class CriticalEventSubscriber implements StatementSubscriber {

    /** Logger */
    private static Logger LOG = 
            LoggerFactory.getLogger(CriticalEventSubscriber.class);

    /** Minimum starting threshold for a critical event. */
    private static final String CRITICAL_EVENT_THRESHOLD = "100";
    
    /**
     * If the last event in a critical sequence is this much greater 
     * than the first - issue a critical alert.
     */
    private static final String CRITICAL_EVENT_MULTIPLIER = "1.5";
    
    /**
     * {@inheritDoc}
     */
    public String getStatement() {
        
        // Example using 'Match Recognise' syntax.
        String criticalEventExpression = "select * from TemperatureEvent "
                + "match_recognize ( "
                + "measures A as temp1, B as temp2, C as temp3, D as temp4 "
                + "pattern (A B C D) " 
                + "define "
                + "       A as A.temperature > " + CRITICAL_EVENT_THRESHOLD + ", "
                + "       B as (A.temperature < B.temperature), "
                + "       C as (B.temperature < C.temperature), "
                + "       D as (C.temperature < D.temperature) " 
                + "and D.temperature > "
                + "(A.temperature * " + CRITICAL_EVENT_MULTIPLIER + ")" + ")";
        
        return criticalEventExpression;
    }
    
    /**
     * Listener method called when Esper has detected a pattern match.
     */
    public void update(Map<string temperatureevent=""> eventMap) {

        // 1st Temperature in the Critical Sequence
        TemperatureEvent temp1 = 
                (TemperatureEvent) eventMap.get("temp1");
        // 2nd Temperature in the Critical Sequence
        TemperatureEvent temp2 = 
                (TemperatureEvent) eventMap.get("temp2");
        // 3rd Temperature in the Critical Sequence
        TemperatureEvent temp3 = 
                (TemperatureEvent) eventMap.get("temp3");
        // 4th Temperature in the Critical Sequence
        TemperatureEvent temp4 = 
                (TemperatureEvent) eventMap.get("temp4");

        StringBuilder sb = new StringBuilder();
        sb.append("***************************************");
        sb.append("\n* [ALERT] : CRITICAL EVENT DETECTED! ");
        sb.append("\n* " + temp1 + " > " + temp2 + 
                " > " + temp3 + " > " + temp4);
        sb.append("\n***************************************");

        LOG.debug(sb.toString());
    }

    
}


The Running Demo

Full instructions for running the demo can be found here:

https://github.com/corsoft/esper-demo-nuclear

An example of the running demo is shown below - it generates random Temperature events and sends them through the Esper processor (in the real world this would come in via a JMS queue, http endpoint or socket listener).

When any of our 3 queries detect a match - debug is dumped to the console. In a real world solution each of these 3 listeners would handle the events differently - maybe by sending messages to alert queues/endpoints for other parts of the system to pick up the processing.



Conclusions

Using a system like Esper is a neat way to monitor and spot patterns in data in real time with minimal code.

This is obviously (and intentionally) a very bare bones demo, barely touching the surface of the capabilities available. Check out the Esper web site for more info and demos.

Esper also has a plugin for Apache Camel Integration engine - which allows you to configure you EPL queries directly in XML Spring camel routes, removing the need for any Java code completely (we will possibly cover this in a later blog post!)