package sushi.esper;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.w3c.dom.Node;
import sushi.adapter.SushiTrafficAdapter;
import sushi.adapter.SushiWeatherAdapter;
import sushi.event.SushiEvent;
import sushi.event.SushiEventType;
import sushi.query.SushiLiveQueryListener;
import sushi.query.SushiPatternQuery;
import sushi.query.SushiPatternQueryListener;
import sushi.query.SushiQuery;
import sushi.transformation.TransformationListener;
import sushi.util.XMLUtils;
import com.espertech.esper.client.Configuration;
import com.espertech.esper.client.ConfigurationEventTypeXMLDOM;
import com.espertech.esper.client.EPAdministrator;
import com.espertech.esper.client.EPRuntime;
import com.espertech.esper.client.EPServiceProviderManager;
import com.espertech.esper.client.EPStatement;
import com.espertech.esper.client.EventType;
import com.espertech.esper.client.time.CurrentTimeEvent;
import com.espertech.esper.client.time.TimerControlEvent;
import com.espertech.esper.core.service.EPServiceProviderSPI;
/**
* Adapter for the Esper event proccesing engine.
*/
@SuppressWarnings("serial")
public class SushiStreamProcessingAdapter implements Serializable {
private static SushiStreamProcessingAdapter instance = null;
private Configuration esperConfiguration;
private EPServiceProviderSPI esperServiceProvider;
private EPRuntime esperRuntime;
private HashMap<SushiQuery, SushiLiveQueryListener> queryListeners;
private boolean activatedTomTomAdapter = false;
private boolean activatedWeatherAdapter = false;
private SushiTrafficAdapter trafficAdapter;
private SushiWeatherAdapter weatherAdapter;
private SushiStreamProcessingAdapter() {
initialize();
}
public static SushiStreamProcessingAdapter getInstance() {
//lazy initialize
if (instance == null) {
instance = new SushiStreamProcessingAdapter();
instance.initializeAdapter();
}
return instance;
}
public static boolean instanceIsCleared() {
return (instance == null);
}
public static void clearInstance() {
if (instance != null) {
instance.weatherAdapter.deleteQuartzJob();
instance.trafficAdapter.deleteQuartzJob();
}
instance = null;
}
private void initialize() {
esperConfiguration = new Configuration();
esperConfiguration.addPlugInSingleRowFunction("currentDate", "sushi.esper.SushiUtils", "currentDate");
esperConfiguration.addPlugInSingleRowFunction("formatDate", "sushi.esper.SushiUtils", "formatDate");
esperConfiguration.addPlugInSingleRowFunction("getIntersection", "sushi.esper.SushiUtils", "getIntersection");
esperConfiguration.addPlugInSingleRowFunction("isIntersectionNotEmpty", "sushi.esper.SushiUtils", "isIntersectionNotEmpty");
esperConfiguration.addPlugInSingleRowFunction("integerValueFromEvent", "sushi.esper.SushiUtils", "integerValueFromEvent");
esperConfiguration.addPlugInSingleRowFunction("doubleValueFromEvent", "sushi.esper.SushiUtils", "doubleValueFromEvent");
esperConfiguration.addPlugInSingleRowFunction("stringValueFromEvent", "sushi.esper.SushiUtils", "stringValueFromEvent");
esperConfiguration.addPlugInSingleRowFunction("dateValueFromEvent", "sushi.esper.SushiUtils", "dateValueFromEvent");
esperConfiguration.addPlugInSingleRowFunction("sumFromEventList", "sushi.esper.SushiUtils", "sumFromEventList");
// esperConfiguration.addPlugInSingleRowFunction("intersection", "sushi.esper.SushiUtils", "intersection");
esperServiceProvider = (EPServiceProviderSPI)EPServiceProviderManager.getProvider(EPServiceProviderSPI.DEFAULT_ENGINE_URI, esperConfiguration);
esperServiceProvider.initialize();
esperRuntime = esperServiceProvider.getEPRuntime();
esperRuntime.sendEvent(new TimerControlEvent(TimerControlEvent.ClockType.CLOCK_EXTERNAL));
queryListeners = new HashMap<SushiQuery, SushiLiveQueryListener>();
registerExistingEventTypes();
List<SushiQuery> queries = SushiQuery.getAllLiveQueries();
for(int i = 0; i < queries.size(); i++){
addLiveQuery(queries.get(i));
}
}
private void initializeAdapter() {
this.weatherAdapter = new SushiWeatherAdapter();
this.weatherAdapter.scheduleQuartzJob();
this.trafficAdapter = new SushiTrafficAdapter();
this.trafficAdapter.scheduleQuartzJob();
}
/**
* checks database for eventtypes and register them to EPP
* creates window for eventtyp
* useful if server was shut down
*/
public void registerExistingEventTypes() {
for (SushiEventType eventType: SushiEventType.findAll()) {
System.out.println("Registered event type '" + eventType + "' from database.");
createWindow(eventType);
}
}
/**
* checks if eventtype is already registered
*/
public boolean isEventType(SushiEventType eventType) {
return esperServiceProvider.getEPAdministrator().getConfiguration().isEventTypeExists(eventType.getTypeName());
}
/**
* returns information of eventtyp from {@link EventType.getPropertyType(String)}
*/
public Class getEventTypeInfo(SushiEventType eventType, String attribute) {
EventType type = esperServiceProvider.getEPAdministrator().getConfiguration().getEventType(eventType.getTypeName());
if (type.isProperty(attribute) == false) return null;
return type.getPropertyType(attribute);
}
/**
* checks if eventyp has attribut in Esper
* @param eventType
* @param attribute
* @return
*/
public Boolean eventTypeHasAttribute(SushiEventType eventType, String attribute) {
EventType type = esperServiceProvider.getEPAdministrator().getConfiguration().getEventType(eventType.getTypeName());
return type.isProperty(attribute);
}
/**
* returns attribute names of eventtyp
* @param eventType
* @return
*/
public String[] getAttributesOfEventType(SushiEventType eventType) {
EventType type = esperServiceProvider.getEPAdministrator().getConfiguration().getEventType(eventType.getTypeName());
return type.getPropertyNames();
}
/**
* add event
* @param events
*/
public void addEvents(List<SushiEvent> events) {
for (SushiEvent event: events) {
addEvent(event);
}
}
/**
* converts the SushiEvents in XMLEvents and send them to esper
* @param event
*/
public void addEvent(SushiEvent event) {
Node node = XMLUtils.eventToNode(event);
// XMLUtils.printDocument((Document) node);
if (node == null) System.err.println("Event was not parseable!");
long timeInMilliseconds = event.getTimestamp().getTime();
this.esperRuntime.sendEvent(new CurrentTimeEvent(timeInMilliseconds));
this.esperRuntime.sendEvent(node);
}
/**
* converts SushiEventtyp to XML and send it to Esper
* @param eventType
*/
public void addEventType(SushiEventType eventType) {
if (isEventType(eventType)) return;
ConfigurationEventTypeXMLDOM dom = EsperUtils.eventTypeToXMLDom(eventType);
this.esperServiceProvider.getEPAdministrator().getConfiguration().addEventType(eventType.getTypeName(), dom);
this.createWindow(eventType);
}
/**
* deletes given events from event window
* @param events
*/
public void removeEvents(List<SushiEvent> events) {
for (SushiEvent event: events) {
removeEvent(event);
}
}
/**
* delete given event from event window
* @param event
*/
public void removeEvent(SushiEvent event) {
StringBuffer sb = new StringBuffer();
sb.append("DELETE FROM " + event.getEventType().getTypeName() + "Window WHERE ");
sb.append("(Timestamp.getTime() = " + event.getTimestamp().getTime() + ")");
Iterator<String> iterator = event.getValues().keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
Serializable value = event.getValues().get(key);
if (value instanceof String) {
sb.append(" AND (" + key + " = '" + value + "')");
} else if (value instanceof Date) {
sb.append(" AND (" + key + ".getTime() = " + ((Date) value).getTime() + ")");
} else {
sb.append(" AND (" + key + " = " + value + ")");
}
}
this.esperRuntime.executeQuery(sb.toString());
}
/**
* deletes Eventype from Esper
* @param eventType
*/
public void removeEventType(SushiEventType eventType) {
this.esperServiceProvider.getEPAdministrator().getConfiguration().removeEventType(eventType.getTypeName(), true);
}
/**
* returns live query with title as name
* @param title
* @return
*/
public SushiQuery getLiveQueryByTitle(String title){
for (SushiQuery query : queryListeners.keySet()){
if (query.getTitle().equals(title)){
return query;
}
}
return null;
}
/**
* registers live query to Esper and starts a listener to it
*
* @param liveQuery
* @return Listener which will get notifications if live-query gets triggered
*/
public SushiLiveQueryListener addLiveQuery(SushiQuery liveQuery) {
EPStatement newStatement = esperServiceProvider.getEPAdministrator().createEPL(liveQuery.getQueryString());
SushiLiveQueryListener listener = new SushiLiveQueryListener(liveQuery);
newStatement.addListener(listener);
queryListeners.put(liveQuery, listener);
return listener;
}
public SushiPatternQueryListener addPatternQuery(SushiPatternQuery sushiPatternQuery) {
EPStatement newStatement = esperServiceProvider.getEPAdministrator().createEPL(sushiPatternQuery.getQueryString());
SushiLiveQueryListener listener = new SushiPatternQueryListener(sushiPatternQuery);
newStatement.addListener(listener);
sushiPatternQuery.setEPStatement(newStatement);
queryListeners.put(sushiPatternQuery, listener);
return (SushiPatternQueryListener) listener;
}
public SushiPatternQueryListener updatePatternQuery(SushiPatternQuery sushiPatternQuery) {
//Erstes altes Statement löschen
esperServiceProvider.getEPAdministrator().getStatement(sushiPatternQuery.getEPStatement().getName()).destroy();
EPStatement newStatement = esperServiceProvider.getEPAdministrator().createEPL(sushiPatternQuery.getQueryString());
newStatement.addListener(sushiPatternQuery.getListener());
sushiPatternQuery.setEPStatement(newStatement);
return (SushiPatternQueryListener) sushiPatternQuery.getListener();
}
/**
* remove live query from Esper
* @param queryName
* @return
*/
public boolean removeLiveQuery(String queryName) {
SushiQuery query = getLiveQueryByTitle(queryName);
queryListeners.remove(query);
return query.remove() != null;
}
/**
* returns names of live queries which are currently registered
* @return
*/
public List<String> getAllLiveQueryTitles() {
ArrayList<String> titles = new ArrayList<String>();
for (SushiQuery query: queryListeners.keySet()){
if(query.isLiveQuery()){
titles.add(query.getTitle());
}
}
return titles;
}
/**
* get names of saved ondemand queries
* @return
*/
public List<String> getAllOnDemandQueryTitles() {
ArrayList<String> titles = new ArrayList<String>();
for (SushiQuery query: queryListeners.keySet()){
if(query.isOnDemanQuery()){
titles.add(query.getTitle());
}
}
return titles;
}
/**
* returns query string of saved query
* @param queryName
* @return
* @throws Exception
*/
public String getQueryByQueryName(String queryName) throws Exception {
for (SushiQuery query : queryListeners.keySet()){
if (query.getTitle() == queryName){
return query.getQueryString();
}
}
throw new Exception("NoQueryFoundError");
}
/**
* return SushiLiveQueryListener which has the given name
* @param queryName
* @return
*/
public SushiLiveQueryListener getListenerByName(String queryName) {
SushiQuery query = getLiveQueryByTitle(queryName);
return queryListeners.get(query);
}
/**
* return SushiLiveQueryListener which has the given query
* @param queryString
* @return
*/
public SushiLiveQueryListener getListenerByQuery(String queryString) {
SushiQuery query;
try {
query = getLiveQueriesByQueryString(queryString);
return queryListeners.get(query);
} catch (Exception e) {
return null;
}
}
public SushiQuery getLiveQueriesByQueryString(String queryString) throws Exception {
for (SushiQuery query : queryListeners.keySet()){
if (query.getQueryString() == queryString){
return query;
}
}
throw new Exception("NoQueryFoundError");
}
/**
* creates window in esper for the given eventtype
* @param eventType
*/
public void createWindow(SushiEventType eventType) {
if (!isEventType(eventType)) {
addEventType(eventType);
return;
}
if (hasWindow(eventType.getTypeName() + "Window")) return;
esperServiceProvider.getEPAdministrator().createEPL("CREATE WINDOW " + eventType.getTypeName() + "Window.win:keepall() AS " + eventType.getTypeName() );
esperServiceProvider.getEPAdministrator().createEPL("INSERT INTO " + eventType.getTypeName() + "Window SELECT * FROM " + eventType.getTypeName());
}
public EPRuntime getEsperRuntime() {
return esperRuntime;
}
public void setEsperRuntime(EPRuntime esperRuntime) {
this.esperRuntime = esperRuntime;
}
/**
* return the names of the current active windows
* @return
*/
public String[] getWindowNames() {
String[] names = esperServiceProvider.getNamedWindowService().getNamedWindows();
return names;
}
/**
* checks if window already exists
* @param windowName
* @return
*/
public boolean hasWindow(String windowName){
return esperServiceProvider.getNamedWindowService().isNamedWindow(windowName);
}
public EPAdministrator getEsperAdministrator() {
return esperServiceProvider.getEPAdministrator();
}
public boolean isActivatedTomTomAdapter() {
return activatedTomTomAdapter;
}
public void setActivatedTomTomAdapter(boolean activatedTomTomAdapter) {
this.activatedTomTomAdapter = activatedTomTomAdapter;
}
public boolean isActivatedWeatherAdapter() {
return activatedWeatherAdapter;
}
public void setActivatedWeatherAdapter(boolean activatedWeatherAdapter) {
this.activatedWeatherAdapter = activatedWeatherAdapter;
}
public TransformationListener createTransformationListener(SushiEventType eventType) {
return new TransformationListener(eventType);
}
public EPStatement createStatement(String query, String name) {
return getEsperAdministrator().createEPL(query, name);
}
public EPStatement getStatement(String name) {
return getEsperAdministrator().getStatement(name);
}
}