Chapter 4. API Reference

4.1. Overview

Esper has 2 primary interfaces that this section outlines: The admininistrative interface and the runtime interface.

Use Esper's administrative interface to create event patterns and EQL statements as discussed in Section 5.1, “Event Pattern Overview” and Section 6.1, “EQL Introduction”.

Use Esper's runtime interface to send events into the engine, emit events and get statistics for an engine instance.

The JavaDoc documentation is also a great source for API information.

4.2. Engine Instances

Each instance of an Esper engine is completely independent of other engine instances and has it's own administrative and runtime interface.

An instance of the Esper engine is obtained via static methods on the EPServiceProviderManager class. The getDefaultProvider method and the getProvider(String URI) methods return an instance of the Esper engine. The latter can be used to obtain multiple instances of the engine for different URI values. The EPServiceProviderManager determines if the URI matches all prior URI values and returns the same engine instance for the same URI value. If the URI has not been seen before, a new Engine instance is created.

The code snipped below gets the default instance Esper engine. Subsequent calls to get the default engine instance return the same instance.

EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();

This code snippet gets an Esper engine for uri RFIDProcessor1. Subsequent calls to get an engine with the same uri return the same instance.

EPServiceProvider epService = EPServiceProviderManager.getProvider("RFIDProcessor1");

A existing Esper engine instance can be reset via the initialize method on the EPServiceProvider instance. This stops and removes all statements in the Engine.

4.3. The Administrative Interface

Create event patterns or EQL statements via the administrative interface EPAdministrator.

This code snippet gets an Esper engine then creates an event pattern and an EQL statement.

EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
EPAdministrator admin = epService.getEPAdministrator();
EPStatement 10secRecurTrigger = admin.createPattern("every timer:at(*, *, *, *, *, */10)");
EPStatement weightedAvgView = admin.createEQL(
    "select * from MarketDataBean(symbol='IBM').win:time(60).stat:weighted_avg('price', 'volume')");

The createPattern and createEQL methods return EPStatement instances. Statement are automatically started and active when created. A statement can also be stopped and started again via the stop and start methods shown in the code snippet below.

weightedAvgView.stop();
weightedAvgView.start();

We can subscribe to updates posted by a statement via the addListener and removeListener methods the EPStatement statement. We need to provide an implementation of the UpdateListener interface to the statement.

UpdateListener myListener = new MyUpdateListener();	// MyUpdateListener implements UpdateListener
weightedAvgView.addListener(myListener);

EQL statements and event patterns publish old data and new data to registered UpdateListener listeners. Old data published by views constists of the events representing the prior values of derived data held by the statement. New data published by views is the events representing the new values of derived data held by the statement.

Subscribing to events posted by a statement is following a push model, ie. the engine pushes data to listeners when when events are received that cause data to change or patterns to match. Alternatively, statements can also serve up data in a pull model via the iterator method. This can come in handy if we are not interested in all new updates, but only want to perform a frequent poll for the latest data. For example, a event pattern that fires avery 5 seconds could be used to pull data from an EQL statement.The code snippet below demonstrates some pull code.

Iterator<EventBean> eventIter = weightedAvgView.iterator();
for (EventBean event : eventIter) {
   // .. do something ..
}

This is a second example:

double averagePrice = (Double) eqlStatement.iterator().next().get("average");

4.4. The Runtime Interface

The EPRuntime interface is used to send events for processing into an Esper engine, and to emit Events from an engine instance to the outside world.

The below code sippet shows how to send events to the engine.

EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
EPRuntime runtime = epService.getEPRuntime();

// Send an example event containing stock market data
runtime.sendEvent(new MarketDataBean('IBM', 75.0));		

Another important method in the runtime interface is the route method. This method is designed for use by UpdateListener implementations that need to send events into an engine instance.

The emit and addEmittedListener methods can be used to emit events from a runtime to a registered set of one or more emitted event listeners. Events are emitted on an event channel identified by a name. Listeners are implementations of the EmittedListener interface. Listeners can specify a channel to listen to and thus only receive events posted to that channel. Listeners can also supply no channel name and thus receive emitted events posted on any channel. Channels are uniquely identified by a string channel name.

4.5. Event Class Requirements

A event is a immutable record of a past occurance of an action or state change. A event can have a set of event properties that supply information about the event. A event also has an event class.

In Esper, events are object instances that expose event properties through JavaBean-style getter methods. Events classes do not have to be fully compliant to the JavaBean specification, however for the Esper engine to obtain event properties, the required JavaBean getter methods must be present.

Classes that represent events should be made immutable. As events are recordings of a state change or action that occured in the past, the relevant event properties should not be changable. However this is not a hard requirement and the Esper engine accepts events that are mutable as well.

4.6. Time-Keeping Events

Special events are provided that can be used to control the time-keeping of an engine instance. There are two models for an engine to keep track of time. Internal clocking is when the engine instance relies on the java.util.Timer class for time tick events. External clocking can be used to supply time ticks to the engine. The latter is useful for testing time-based event sequences or for synchronizing the engine with an external time source.

By default, the Esper engine uses internal time ticks. This behavior can be changed by sending a timer control event to the engine as shown below.

EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
EPRuntime runtime = epService.getEPRuntime();
// switch to external clocking
runtime.sendEvent(new TimerControlEvent(TimerControlEvent.ClockType.CLOCK_EXTERNAL));

// send a time tick
long timeInMillis = System.currentTimeMillis();	// Or get the time somewhere else
runtime.sendEvent(new CurrentTimeEvent(timeInMillis));

4.7. Events Received from the Engine

The Esper engine posts events to registered UpdateListener instances ('push' method for receiving events). For many statements events can also be pulled from statements via the iterator method. Both pull and push supply EventBean instances representing the events generated by the engine or events supplied to the engine. Each EventBean instance represents an event, with each event being either an artificial event, composite event or an event supplied to the engine via it's runtime interface.

The getEventType methods supplies an event's event type information represented by an EventType instance. The EventType supplies event property names and types as well as information about the underlying object to the event.

The engine may generate artificial events that contain information derived from event streams. A typical example for artificial events are the events posted for a statement to calculate univariate statistics on an event property. The below example shows such a statement and interogates the events that the engine publishes.

// Derive univariate statistics on price for the last 100 market data events
String viewExpr = "select * from MarketDataBean(symbol='IBM').win:length(100).stat:uni('price')";
EPStatement priceStatsView = epService.getEPAdministrator().createEQL(viewExpr);
priceStatsView.addListener(testListener);
// Example listener code
public class MyUpdateListener implements UpdateListener
{
    public void update(EventBean[] newData, EventBean[] oldData)
    {
		// Interrogate events
		System.out.println("new average price=" + newData[0].get("average");
	}
}

Composite events are events that aggregate one or more other events. Composite events are typically created by the engine for statements that join two event streams, and for event patterns in which the causal events are retained and reported in a composite event. The example below shows such an event pattern.

// Look for a pattern where AEvent follows BEvent
String pattern = "a=AEvent -> b=BEvent";
EPStatement stmt = epService.getEPAdministrator().createPattern(pattern);
stmt.addListener(testListener);
// Example listener code
public class MyUpdateListener implements UpdateListener
{
    public void update(EventBean[] newData, EventBean[] oldData)
    {
		System.out.println("a event=" + newData[0].get("a").getUnderlying());
		System.out.println("b event=" + newData[0].get("b").getUnderlying());
	}
}