/* *************************************************************************************** * Copyright (C) 2006 EsperTech, Inc. All rights reserved. * * http://www.espertech.com/esper * * http://www.espertech.com * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the GPL license * * a copy of which has been included with this distribution in the license.txt file. * *************************************************************************************** */ package com.espertech.esper.core.service; import com.espertech.esper.client.*; import com.espertech.esper.client.context.ContextPartitionDescriptor; import com.espertech.esper.client.context.ContextPartitionSelector; import com.espertech.esper.client.context.ContextPartitionVariableState; import com.espertech.esper.client.dataflow.EPDataFlowRuntime; import com.espertech.esper.client.hook.ExceptionHandlerExceptionType; import com.espertech.esper.client.soda.EPStatementObjectModel; import com.espertech.esper.client.time.CurrentTimeEvent; import com.espertech.esper.client.time.CurrentTimeSpanEvent; import com.espertech.esper.client.time.TimerControlEvent; import com.espertech.esper.client.time.TimerEvent; import com.espertech.esper.client.util.EventRenderer; import com.espertech.esper.collection.ArrayBackedCollection; import com.espertech.esper.collection.DualWorkQueue; import com.espertech.esper.collection.ThreadWorkQueue; import com.espertech.esper.core.context.mgr.ContextManager; import com.espertech.esper.core.context.util.EPStatementAgentInstanceHandle; import com.espertech.esper.core.context.util.EPStatementAgentInstanceHandleComparator; import com.espertech.esper.core.start.*; import com.espertech.esper.core.thread.*; import com.espertech.esper.epl.annotation.AnnotationUtil; import com.espertech.esper.epl.declexpr.ExprDeclaredNode; import com.espertech.esper.epl.expression.core.ExprEvaluatorContext; import com.espertech.esper.epl.expression.core.ExprValidationException; import com.espertech.esper.epl.expression.subquery.ExprSubselectNode; import com.espertech.esper.epl.expression.visitor.ExprNodeSubselectDeclaredDotVisitor; import com.espertech.esper.epl.metric.MetricReportingPath; import com.espertech.esper.epl.script.AgentInstanceScriptContext; import com.espertech.esper.epl.spec.*; import com.espertech.esper.epl.spec.util.StatementSpecRawAnalyzer; import com.espertech.esper.epl.table.mgmt.TableExprEvaluatorContext; import com.espertech.esper.epl.variable.VariableMetaData; import com.espertech.esper.epl.variable.VariableReader; import com.espertech.esper.event.util.EventRendererImpl; import com.espertech.esper.filter.FilterHandle; import com.espertech.esper.filter.FilterHandleCallback; import com.espertech.esper.metrics.instrumentation.InstrumentationHelper; import com.espertech.esper.metrics.jmx.JmxGetter; import com.espertech.esper.schedule.*; import com.espertech.esper.timer.TimerCallback; import com.espertech.esper.util.ExecutionPathDebugLog; import com.espertech.esper.util.MetricUtil; import com.espertech.esper.util.ThreadLogUtil; import com.espertech.esper.util.UuidGenerator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Node; import java.lang.annotation.Annotation; import java.net.URI; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; /** * Implements runtime interface. Also accepts timer callbacks for synchronizing time events with regular events * sent in. */ public class EPRuntimeImpl implements EPRuntimeSPI, EPRuntimeEventSender, TimerCallback, InternalEventRouteDest { protected EPServicesContext services; protected boolean isLatchStatementInsertStream; protected boolean isUsingExternalClocking; protected boolean isPrioritized; protected volatile UnmatchedListener unmatchedListener; protected AtomicLong routedInternal; protected AtomicLong routedExternal; protected EventRenderer eventRenderer; protected InternalEventRouter internalEventRouter; protected ExprEvaluatorContext engineFilterAndDispatchTimeContext; protected ThreadWorkQueue threadWorkQueue; protected ThreadLocal<ArrayBackedCollection<FilterHandle>> matchesArrayThreadLocal; protected ThreadLocal<ArrayBackedCollection<ScheduleHandle>> scheduleArrayThreadLocal; protected ThreadLocal<Map<EPStatementAgentInstanceHandle, Object>> matchesPerStmtThreadLocal; protected ThreadLocal<Map<EPStatementAgentInstanceHandle, Object>> schedulePerStmtThreadLocal; /** * Constructor. * * @param services - references to services */ public EPRuntimeImpl(final EPServicesContext services) { this.services = services; this.threadWorkQueue = new ThreadWorkQueue(); isLatchStatementInsertStream = this.services.getEngineSettingsService().getEngineSettings().getThreading().isInsertIntoDispatchPreserveOrder(); isUsingExternalClocking = !this.services.getEngineSettingsService().getEngineSettings().getThreading().isInternalTimerEnabled(); isPrioritized = services.getEngineSettingsService().getEngineSettings().getExecution().isPrioritized(); routedInternal = new AtomicLong(); routedExternal = new AtomicLong(); engineFilterAndDispatchTimeContext = new ExprEvaluatorContext() { private ExpressionResultCacheService expressionResultCacheService = services.getExpressionResultCacheSharable(); public TimeProvider getTimeProvider() { return services.getSchedulingService(); } public ExpressionResultCacheService getExpressionResultCacheService() { return expressionResultCacheService; } public int getAgentInstanceId() { return -1; } public EventBean getContextProperties() { return null; } public AgentInstanceScriptContext getAllocateAgentInstanceScriptContext() { return null; } public String getStatementName() { return null; } public String getEngineURI() { return null; } public int getStatementId() { return -1; } public StatementAgentInstanceLock getAgentInstanceLock() { return null; } public StatementType getStatementType() { return null; } public TableExprEvaluatorContext getTableExprEvaluatorContext() { throw new UnsupportedOperationException("Table-access evaluation is not supported in this expression"); } public Object getStatementUserObject() { return null; } }; initThreadLocals(); services.getThreadingService().initThreading(services, this); } /** * Sets the route for events to use * * @param internalEventRouter router */ public void setInternalEventRouter(InternalEventRouter internalEventRouter) { this.internalEventRouter = internalEventRouter; } @JmxGetter(name = "NumInsertIntoEvents", description = "Number of inserted-into events") public long getRoutedInternal() { return routedInternal.get(); } @JmxGetter(name = "NumRoutedEvents", description = "Number of routed events") public long getRoutedExternal() { return routedExternal.get(); } public void timerCallback() { long msec = services.getTimeSource().getTimeMillis(); if ((ExecutionPathDebugLog.isDebugEnabled) && (log.isDebugEnabled() && (ExecutionPathDebugLog.isTimerDebugEnabled))) { log.debug(".timerCallback Evaluating scheduled callbacks, time is " + msec); } CurrentTimeEvent currentTimeEvent = new CurrentTimeEvent(msec); sendEvent(currentTimeEvent); } public void sendEventAvro(Object avroGenericDataDotRecord, String avroEventTypeName) { if (avroGenericDataDotRecord == null) { throw new IllegalArgumentException("Invalid null event object"); } if ((ExecutionPathDebugLog.isDebugEnabled) && (log.isDebugEnabled())) { log.debug(".sendMap Processing event " + avroGenericDataDotRecord.toString()); } if ((ThreadingOption.isThreadingEnabled) && (services.getThreadingService().isInboundThreading())) { services.getThreadingService().submitInbound(new InboundUnitSendAvro(avroGenericDataDotRecord, avroEventTypeName, services, this)); } else { // Process event EventBean eventBean = wrapEventAvro(avroGenericDataDotRecord, avroEventTypeName); processWrappedEvent(eventBean); } } public void sendEvent(Object theEvent) throws EPException { if (theEvent == null) { log.error(".sendEvent Null object supplied"); return; } if ((ExecutionPathDebugLog.isDebugEnabled) && (log.isDebugEnabled())) { if ((!(theEvent instanceof CurrentTimeEvent)) || (ExecutionPathDebugLog.isTimerDebugEnabled)) { log.debug(".sendEvent Processing event " + theEvent); } } // Process event if ((ThreadingOption.isThreadingEnabled) && (services.getThreadingService().isInboundThreading())) { services.getThreadingService().submitInbound(new InboundUnitSendEvent(theEvent, this)); } else { processEvent(theEvent); } } public void sendEvent(org.w3c.dom.Node document) throws EPException { if (document == null) { log.error(".sendEvent Null object supplied"); return; } if ((ExecutionPathDebugLog.isDebugEnabled) && (log.isDebugEnabled())) { log.debug(".sendEvent Processing DOM node event " + document); } // Process event if ((ThreadingOption.isThreadingEnabled) && (services.getThreadingService().isInboundThreading())) { services.getThreadingService().submitInbound(new InboundUnitSendDOM(document, services, this)); } else { // Get it wrapped up, process event EventBean eventBean = wrapEvent(document); processEvent(eventBean); } } public EventBean wrapEvent(Node node) { return services.getEventAdapterService().adapterForDOM(node); } public void route(org.w3c.dom.Node document) throws EPException { if (document == null) { log.error(".sendEvent Null object supplied"); return; } if ((ExecutionPathDebugLog.isDebugEnabled) && (log.isDebugEnabled())) { log.debug(".sendEvent Processing DOM node event " + document); } // Get it wrapped up, process event EventBean eventBean = services.getEventAdapterService().adapterForDOM(document); threadWorkQueue.addBack(eventBean); } public void routeAvro(Object avroGenericDataDotRecord, String avroEventTypeName) throws EPException { if (avroGenericDataDotRecord == null) { log.error(".sendEvent Null object supplied"); return; } if ((ExecutionPathDebugLog.isDebugEnabled) && (log.isDebugEnabled())) { log.debug(".sendEvent Processing Avro event " + avroGenericDataDotRecord); } // Get it wrapped up, process event EventBean eventBean = services.getEventAdapterService().adapterForAvro(avroGenericDataDotRecord, avroEventTypeName); threadWorkQueue.addBack(eventBean); } public void sendEvent(Map map, String mapEventTypeName) throws EPException { if (map == null) { throw new IllegalArgumentException("Invalid null event object"); } if ((ExecutionPathDebugLog.isDebugEnabled) && (log.isDebugEnabled())) { log.debug(".sendMap Processing event " + map); } if ((ThreadingOption.isThreadingEnabled) && (services.getThreadingService().isInboundThreading())) { services.getThreadingService().submitInbound(new InboundUnitSendMap(map, mapEventTypeName, services, this)); } else { // Process event EventBean eventBean = wrapEvent(map, mapEventTypeName); processWrappedEvent(eventBean); } } public void sendEvent(Object[] propertyValues, String objectArrayEventTypeName) throws EPException { if (propertyValues == null) { throw new IllegalArgumentException("Invalid null event object"); } if ((ExecutionPathDebugLog.isDebugEnabled) && (log.isDebugEnabled())) { log.debug(".sendMap Processing event " + Arrays.toString(propertyValues)); } if ((ThreadingOption.isThreadingEnabled) && (services.getThreadingService().isInboundThreading())) { services.getThreadingService().submitInbound(new InboundUnitSendObjectArray(propertyValues, objectArrayEventTypeName, services, this)); } else { // Process event EventBean eventBean = wrapEvent(propertyValues, objectArrayEventTypeName); processWrappedEvent(eventBean); } } public EventBean wrapEvent(Map map, String eventTypeName) { return services.getEventAdapterService().adapterForMap(map, eventTypeName); } public EventBean wrapEvent(Object[] objectArray, String eventTypeName) { return services.getEventAdapterService().adapterForObjectArray(objectArray, eventTypeName); } public EventBean wrapEventAvro(Object avroGenericDataDotRecord, String eventTypeName) { return services.getEventAdapterService().adapterForAvro(avroGenericDataDotRecord, eventTypeName); } public void route(Map map, String eventTypeName) throws EPException { if (map == null) { throw new IllegalArgumentException("Invalid null event object"); } if ((ExecutionPathDebugLog.isDebugEnabled) && (log.isDebugEnabled())) { log.debug(".route Processing event " + map); } // Process event EventBean theEvent = services.getEventAdapterService().adapterForMap(map, eventTypeName); if (internalEventRouter.isHasPreprocessing()) { theEvent = internalEventRouter.preprocess(theEvent, engineFilterAndDispatchTimeContext); if (theEvent == null) { return; } } threadWorkQueue.addBack(theEvent); } public void route(Object[] objectArray, String eventTypeName) throws EPException { if (objectArray == null) { throw new IllegalArgumentException("Invalid null event object"); } if ((ExecutionPathDebugLog.isDebugEnabled) && (log.isDebugEnabled())) { log.debug(".route Processing event " + Arrays.toString(objectArray)); } // Process event EventBean theEvent = services.getEventAdapterService().adapterForObjectArray(objectArray, eventTypeName); if (internalEventRouter.isHasPreprocessing()) { theEvent = internalEventRouter.preprocess(theEvent, engineFilterAndDispatchTimeContext); if (theEvent == null) { return; } } threadWorkQueue.addBack(theEvent); } public long getNumEventsEvaluated() { return services.getFilterService().getNumEventsEvaluated(); } public void resetStats() { services.getFilterService().resetStats(); routedInternal.set(0); routedExternal.set(0); } public void routeEventBean(EventBean theEvent) { threadWorkQueue.addBack(theEvent); } public void route(Object theEvent) { routedExternal.incrementAndGet(); if (internalEventRouter.isHasPreprocessing()) { EventBean eventBean = services.getEventAdapterService().adapterForBean(theEvent); theEvent = internalEventRouter.preprocess(eventBean, engineFilterAndDispatchTimeContext); if (theEvent == null) { return; } } threadWorkQueue.addBack(theEvent); } // Internal route of events via insert-into, holds a statement lock public void route(EventBean theEvent, EPStatementHandle epStatementHandle, boolean addToFront) { if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qRouteBetweenStmt(theEvent, epStatementHandle, addToFront); } routedInternal.incrementAndGet(); if (isLatchStatementInsertStream) { if (addToFront) { Object latch = epStatementHandle.getInsertIntoFrontLatchFactory().newLatch(theEvent); threadWorkQueue.addFront(latch); } else { Object latch = epStatementHandle.getInsertIntoBackLatchFactory().newLatch(theEvent); threadWorkQueue.addBack(latch); } } else { if (addToFront) { threadWorkQueue.addFront(theEvent); } else { threadWorkQueue.addBack(theEvent); } } if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aRouteBetweenStmt(); } } /** * Process an unwrapped event. * * @param theEvent to process. */ public void processEvent(Object theEvent) { if (theEvent instanceof TimerEvent) { processTimeEvent((TimerEvent) theEvent); return; } EventBean eventBean; if (theEvent instanceof EventBean) { eventBean = (EventBean) theEvent; } else { eventBean = wrapEvent(theEvent); } processWrappedEvent(eventBean); } public EventBean wrapEvent(Object theEvent) { return services.getEventAdapterService().adapterForBean(theEvent); } public void processWrappedEvent(EventBean eventBean) { if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qStimulantEvent(eventBean, services.getEngineURI()); } if (internalEventRouter.isHasPreprocessing()) { eventBean = internalEventRouter.preprocess(eventBean, engineFilterAndDispatchTimeContext); if (eventBean == null) { return; } } // Acquire main processing lock which locks out statement management if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qEvent(eventBean, services.getEngineURI(), true); } services.getEventProcessingRWLock().acquireReadLock(); try { processMatches(eventBean); } catch (RuntimeException ex) { matchesArrayThreadLocal.get().clear(); throw new EPException(ex); } finally { services.getEventProcessingRWLock().releaseReadLock(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aEvent(); } } // Dispatch results to listeners // Done outside of the read-lock to prevent lockups when listeners create statements dispatch(); // Work off the event queue if any events accumulated in there via a route() or insert-into processThreadWorkQueue(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aStimulantEvent(); } } private void processTimeEvent(TimerEvent theEvent) { if (theEvent instanceof TimerControlEvent) { TimerControlEvent timerControlEvent = (TimerControlEvent) theEvent; if (timerControlEvent.getClockType() == TimerControlEvent.ClockType.CLOCK_INTERNAL) { // Start internal clock which supplies CurrentTimeEvent events every 100ms // This may be done without delay thus the write lock indeed must be reentrant. if (services.getConfigSnapshot().getEngineDefaults().getTimeSource().getTimeUnit() != TimeUnit.MILLISECONDS) { throw new EPException("Internal timer requires millisecond time resolution"); } services.getTimerService().startInternalClock(); isUsingExternalClocking = false; } else { // Stop internal clock, for unit testing and for external clocking services.getTimerService().stopInternalClock(true); isUsingExternalClocking = true; } return; } if (theEvent instanceof CurrentTimeEvent) { CurrentTimeEvent current = (CurrentTimeEvent) theEvent; long currentTime = current.getTime(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qStimulantTime(currentTime, services.getEngineURI()); } // Evaluation of all time events is protected from statement management if ((ExecutionPathDebugLog.isDebugEnabled) && (log.isDebugEnabled()) && (ExecutionPathDebugLog.isTimerDebugEnabled)) { log.debug(".processTimeEvent Setting time and evaluating schedules for time " + currentTime); } if (isUsingExternalClocking && (currentTime == services.getSchedulingService().getTime())) { if (log.isWarnEnabled()) { log.warn("Duplicate time event received for currentTime " + currentTime); } } services.getSchedulingService().setTime(currentTime); if (MetricReportingPath.isMetricsEnabled) { services.getMetricsReportingService().processTimeEvent(currentTime); } processSchedule(currentTime); // Let listeners know of results dispatch(); // Work off the event queue if any events accumulated in there via a route() processThreadWorkQueue(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aStimulantTime(); } return; } // handle time span CurrentTimeSpanEvent span = (CurrentTimeSpanEvent) theEvent; long targetTime = span.getTargetTime(); long currentTime = services.getSchedulingService().getTime(); Long optionalResolution = span.getOptionalResolution(); if (isUsingExternalClocking && (targetTime < currentTime)) { if (log.isWarnEnabled()) { log.warn("Past or current time event received for currentTime " + targetTime); } } // Evaluation of all time events is protected from statement management if ((ExecutionPathDebugLog.isDebugEnabled) && (log.isDebugEnabled()) && (ExecutionPathDebugLog.isTimerDebugEnabled)) { log.debug(".processTimeEvent Setting time span and evaluating schedules for time " + targetTime + " optional resolution " + span.getOptionalResolution()); } while (currentTime < targetTime) { if ((optionalResolution != null) && (optionalResolution > 0)) { currentTime += optionalResolution; } else { Long nearest = services.getSchedulingService().getNearestTimeHandle(); if (nearest == null) { currentTime = targetTime; } else { currentTime = nearest; } } if (currentTime > targetTime) { currentTime = targetTime; } if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qStimulantTime(currentTime, services.getEngineURI()); } // Evaluation of all time events is protected from statement management if ((ExecutionPathDebugLog.isDebugEnabled) && (log.isDebugEnabled()) && (ExecutionPathDebugLog.isTimerDebugEnabled)) { log.debug(".processTimeEvent Setting time and evaluating schedules for time " + currentTime); } services.getSchedulingService().setTime(currentTime); if (MetricReportingPath.isMetricsEnabled) { services.getMetricsReportingService().processTimeEvent(currentTime); } processSchedule(currentTime); // Let listeners know of results dispatch(); // Work off the event queue if any events accumulated in there via a route() processThreadWorkQueue(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aStimulantTime(); } } } private void processSchedule(long time) { if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qTime(time, services.getEngineURI()); } ArrayBackedCollection<ScheduleHandle> handles = scheduleArrayThreadLocal.get(); // Evaluation of schedules is protected by an optional scheduling service lock and then the engine lock // We want to stay in this order for allowing the engine lock as a second-order lock to the // services own lock, if it has one. services.getEventProcessingRWLock().acquireReadLock(); try { services.getSchedulingService().evaluate(handles); } finally { services.getEventProcessingRWLock().releaseReadLock(); } services.getEventProcessingRWLock().acquireReadLock(); try { processScheduleHandles(handles); } catch (RuntimeException ex) { handles.clear(); throw ex; } finally { services.getEventProcessingRWLock().releaseReadLock(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aTime(); } } } public void processScheduleHandles(ArrayBackedCollection<ScheduleHandle> handles) { if (ThreadLogUtil.ENABLED_TRACE) { ThreadLogUtil.trace("Found schedules for", handles.size()); } if (handles.size() == 0) { return; } // handle 1 result separately for performance reasons if (handles.size() == 1) { Object[] handleArray = handles.getArray(); EPStatementHandleCallback handle = (EPStatementHandleCallback) handleArray[0]; if ((MetricReportingPath.isMetricsEnabled) && (handle.getAgentInstanceHandle().getStatementHandle().getMetricsHandle().isEnabled())) { long cpuTimeBefore = MetricUtil.getCPUCurrentThread(); long wallTimeBefore = MetricUtil.getWall(); processStatementScheduleSingle(handle, services); long wallTimeAfter = MetricUtil.getWall(); long cpuTimeAfter = MetricUtil.getCPUCurrentThread(); long deltaCPU = cpuTimeAfter - cpuTimeBefore; long deltaWall = wallTimeAfter - wallTimeBefore; services.getMetricsReportingService().accountTime(handle.getAgentInstanceHandle().getStatementHandle().getMetricsHandle(), deltaCPU, deltaWall, 1); } else { if ((ThreadingOption.isThreadingEnabled) && (services.getThreadingService().isTimerThreading())) { services.getThreadingService().submitTimerWork(new TimerUnitSingle(services, this, handle)); } else { processStatementScheduleSingle(handle, services); } } handles.clear(); return; } Object[] matchArray = handles.getArray(); int entryCount = handles.size(); // sort multiple matches for the event into statements Map<EPStatementAgentInstanceHandle, Object> stmtCallbacks = schedulePerStmtThreadLocal.get(); stmtCallbacks.clear(); for (int i = 0; i < entryCount; i++) { EPStatementHandleCallback handleCallback = (EPStatementHandleCallback) matchArray[i]; EPStatementAgentInstanceHandle handle = handleCallback.getAgentInstanceHandle(); ScheduleHandleCallback callback = handleCallback.getScheduleCallback(); Object entry = stmtCallbacks.get(handle); // This statement has not been encountered before if (entry == null) { stmtCallbacks.put(handle, callback); continue; } // This statement has been encountered once before if (entry instanceof ScheduleHandleCallback) { ScheduleHandleCallback existingCallback = (ScheduleHandleCallback) entry; ArrayDeque<ScheduleHandleCallback> entries = new ArrayDeque<ScheduleHandleCallback>(); entries.add(existingCallback); entries.add(callback); stmtCallbacks.put(handle, entries); continue; } // This statement has been encountered more then once before ArrayDeque<ScheduleHandleCallback> entries = (ArrayDeque<ScheduleHandleCallback>) entry; entries.add(callback); } handles.clear(); for (Map.Entry<EPStatementAgentInstanceHandle, Object> entry : stmtCallbacks.entrySet()) { EPStatementAgentInstanceHandle handle = entry.getKey(); Object callbackObject = entry.getValue(); if ((MetricReportingPath.isMetricsEnabled) && (handle.getStatementHandle().getMetricsHandle().isEnabled())) { long cpuTimeBefore = MetricUtil.getCPUCurrentThread(); long wallTimeBefore = MetricUtil.getWall(); processStatementScheduleMultiple(handle, callbackObject, services); long wallTimeAfter = MetricUtil.getWall(); long cpuTimeAfter = MetricUtil.getCPUCurrentThread(); long deltaCPU = cpuTimeAfter - cpuTimeBefore; long deltaWall = wallTimeAfter - wallTimeBefore; int numInput = (callbackObject instanceof Collection) ? ((Collection) callbackObject).size() : 1; services.getMetricsReportingService().accountTime(handle.getStatementHandle().getMetricsHandle(), deltaCPU, deltaWall, numInput); } else { if ((ThreadingOption.isThreadingEnabled) && (services.getThreadingService().isTimerThreading())) { services.getThreadingService().submitTimerWork(new TimerUnitMultiple(services, this, handle, callbackObject)); } else { processStatementScheduleMultiple(handle, callbackObject, services); } } if (isPrioritized && handle.isPreemptive()) { break; } } } /** * Works off the thread's work queue. */ public void processThreadWorkQueue() { DualWorkQueue queues = threadWorkQueue.getThreadQueue(); if (queues.getFrontQueue().isEmpty()) { boolean haveDispatched = services.getNamedWindowDispatchService().dispatch(); if (haveDispatched) { // Dispatch results to listeners dispatch(); if (!queues.getFrontQueue().isEmpty()) { processThreadWorkQueueFront(queues); } } } else { processThreadWorkQueueFront(queues); } Object item; while ((item = queues.getBackQueue().poll()) != null) { if (item instanceof InsertIntoLatchSpin) { processThreadWorkQueueLatchedSpin((InsertIntoLatchSpin) item); } else if (item instanceof InsertIntoLatchWait) { processThreadWorkQueueLatchedWait((InsertIntoLatchWait) item); } else { processThreadWorkQueueUnlatched(item); } boolean haveDispatched = services.getNamedWindowDispatchService().dispatch(); if (haveDispatched) { dispatch(); } if (!queues.getFrontQueue().isEmpty()) { processThreadWorkQueueFront(queues); } } } private void processThreadWorkQueueFront(DualWorkQueue queues) { Object item; while ((item = queues.getFrontQueue().poll()) != null) { if (item instanceof InsertIntoLatchSpin) { processThreadWorkQueueLatchedSpin((InsertIntoLatchSpin) item); } else if (item instanceof InsertIntoLatchWait) { processThreadWorkQueueLatchedWait((InsertIntoLatchWait) item); } else { processThreadWorkQueueUnlatched(item); } boolean haveDispatched = services.getNamedWindowDispatchService().dispatch(); if (haveDispatched) { dispatch(); } } } private void processThreadWorkQueueLatchedWait(InsertIntoLatchWait insertIntoLatch) { // wait for the latch to complete EventBean eventBean = insertIntoLatch.await(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qEvent(eventBean, services.getEngineURI(), false); } services.getEventProcessingRWLock().acquireReadLock(); try { processMatches(eventBean); } catch (RuntimeException ex) { matchesArrayThreadLocal.get().clear(); throw ex; } finally { insertIntoLatch.done(); services.getEventProcessingRWLock().releaseReadLock(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aEvent(); } } dispatch(); } private void processThreadWorkQueueLatchedSpin(InsertIntoLatchSpin insertIntoLatch) { // wait for the latch to complete EventBean eventBean = insertIntoLatch.await(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qEvent(eventBean, services.getEngineURI(), false); } services.getEventProcessingRWLock().acquireReadLock(); try { processMatches(eventBean); } catch (RuntimeException ex) { matchesArrayThreadLocal.get().clear(); throw ex; } finally { insertIntoLatch.done(); services.getEventProcessingRWLock().releaseReadLock(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aEvent(); } } dispatch(); } private void processThreadWorkQueueUnlatched(Object item) { EventBean eventBean; if (item instanceof EventBean) { eventBean = (EventBean) item; } else { eventBean = services.getEventAdapterService().adapterForBean(item); } if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qEvent(eventBean, services.getEngineURI(), false); } services.getEventProcessingRWLock().acquireReadLock(); try { processMatches(eventBean); } catch (RuntimeException ex) { matchesArrayThreadLocal.get().clear(); throw ex; } finally { services.getEventProcessingRWLock().releaseReadLock(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aEvent(); } } dispatch(); } protected void processMatches(EventBean theEvent) { // get matching filters ArrayBackedCollection<FilterHandle> matches = matchesArrayThreadLocal.get(); long version = services.getFilterService().evaluate(theEvent, matches); if (ThreadLogUtil.ENABLED_TRACE) { ThreadLogUtil.trace("Found matches for underlying ", matches.size(), theEvent.getUnderlying()); } if (matches.size() == 0) { if (unmatchedListener != null) { services.getEventProcessingRWLock().releaseReadLock(); // Allow listener to create new statements try { unmatchedListener.update(theEvent); } catch (Throwable t) { log.error("Exception thrown by unmatched listener: " + t.getMessage(), t); } finally { // acquire read lock for release by caller services.getEventProcessingRWLock().acquireReadLock(); } } return; } Map<EPStatementAgentInstanceHandle, Object> stmtCallbacks = matchesPerStmtThreadLocal.get(); Object[] matchArray = matches.getArray(); int entryCount = matches.size(); for (int i = 0; i < entryCount; i++) { EPStatementHandleCallback handleCallback = (EPStatementHandleCallback) matchArray[i]; EPStatementAgentInstanceHandle handle = handleCallback.getAgentInstanceHandle(); // Self-joins require that the internal dispatch happens after all streams are evaluated. // Priority or preemptive settings also require special ordering. if (handle.isCanSelfJoin() || isPrioritized) { Object callbacks = stmtCallbacks.get(handle); if (callbacks == null) { stmtCallbacks.put(handle, handleCallback.getFilterCallback()); } else if (callbacks instanceof ArrayDeque) { ArrayDeque<FilterHandleCallback> q = (ArrayDeque<FilterHandleCallback>) callbacks; q.add(handleCallback.getFilterCallback()); } else { ArrayDeque<FilterHandleCallback> q = new ArrayDeque<FilterHandleCallback>(4); q.add((FilterHandleCallback) callbacks); q.add(handleCallback.getFilterCallback()); stmtCallbacks.put(handle, q); } continue; } if ((MetricReportingPath.isMetricsEnabled) && (handle.getStatementHandle().getMetricsHandle().isEnabled())) { long cpuTimeBefore = MetricUtil.getCPUCurrentThread(); long wallTimeBefore = MetricUtil.getWall(); processStatementFilterSingle(handle, handleCallback, theEvent, version); long wallTimeAfter = MetricUtil.getWall(); long cpuTimeAfter = MetricUtil.getCPUCurrentThread(); long deltaCPU = cpuTimeAfter - cpuTimeBefore; long deltaWall = wallTimeAfter - wallTimeBefore; services.getMetricsReportingService().accountTime(handle.getStatementHandle().getMetricsHandle(), deltaCPU, deltaWall, 1); } else { if ((ThreadingOption.isThreadingEnabled) && (services.getThreadingService().isRouteThreading())) { services.getThreadingService().submitRoute(new RouteUnitSingle(this, handleCallback, theEvent, version)); } else { processStatementFilterSingle(handle, handleCallback, theEvent, version); } } } matches.clear(); if (stmtCallbacks.isEmpty()) { return; } for (Map.Entry<EPStatementAgentInstanceHandle, Object> entry : stmtCallbacks.entrySet()) { EPStatementAgentInstanceHandle handle = entry.getKey(); Object callbackList = entry.getValue(); if ((MetricReportingPath.isMetricsEnabled) && (handle.getStatementHandle().getMetricsHandle().isEnabled())) { long cpuTimeBefore = MetricUtil.getCPUCurrentThread(); long wallTimeBefore = MetricUtil.getWall(); processStatementFilterMultiple(handle, callbackList, theEvent, version); long wallTimeAfter = MetricUtil.getWall(); long cpuTimeAfter = MetricUtil.getCPUCurrentThread(); long deltaCPU = cpuTimeAfter - cpuTimeBefore; long deltaWall = wallTimeAfter - wallTimeBefore; int size = 1; if (callbackList instanceof Collection) { size = ((Collection) callbackList).size(); } services.getMetricsReportingService().accountTime(handle.getStatementHandle().getMetricsHandle(), deltaCPU, deltaWall, size); } else { if ((ThreadingOption.isThreadingEnabled) && (services.getThreadingService().isRouteThreading())) { services.getThreadingService().submitRoute(new RouteUnitMultiple(this, callbackList, theEvent, handle, version)); } else { processStatementFilterMultiple(handle, callbackList, theEvent, version); } } if (isPrioritized && handle.isPreemptive()) { break; } } stmtCallbacks.clear(); } /** * Processing multiple schedule matches for a statement. * * @param handle statement handle * @param callbackObject object containing matches * @param services engine services */ public static void processStatementScheduleMultiple(EPStatementAgentInstanceHandle handle, Object callbackObject, EPServicesContext services) { if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qTimeCP(handle, services.getSchedulingService().getTime()); } handle.getStatementAgentInstanceLock().acquireWriteLock(); try { if (!handle.isDestroyed()) { if (handle.isHasVariables()) { services.getVariableService().setLocalVersion(); } if (callbackObject instanceof ArrayDeque) { ArrayDeque<ScheduleHandleCallback> callbackList = (ArrayDeque<ScheduleHandleCallback>) callbackObject; for (ScheduleHandleCallback callback : callbackList) { callback.scheduledTrigger(services.getEngineLevelExtensionServicesContext()); } } else { ScheduleHandleCallback callback = (ScheduleHandleCallback) callbackObject; callback.scheduledTrigger(services.getEngineLevelExtensionServicesContext()); } // internal join processing, if applicable handle.internalDispatch(); } } catch (RuntimeException ex) { services.getExceptionHandlingService().handleException(ex, handle, ExceptionHandlerExceptionType.PROCESS, null); } finally { if (handle.isHasTableAccess()) { services.getTableService().getTableExprEvaluatorContext().releaseAcquiredLocks(); } handle.getStatementAgentInstanceLock().releaseWriteLock(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aTimeCP(); } } } /** * Processing single schedule matche for a statement. * * @param handle statement handle * @param services engine services */ public static void processStatementScheduleSingle(EPStatementHandleCallback handle, EPServicesContext services) { if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qTimeCP(handle.getAgentInstanceHandle(), services.getSchedulingService().getTime()); } StatementAgentInstanceLock statementLock = handle.getAgentInstanceHandle().getStatementAgentInstanceLock(); statementLock.acquireWriteLock(); try { if (!handle.getAgentInstanceHandle().isDestroyed()) { if (handle.getAgentInstanceHandle().isHasVariables()) { services.getVariableService().setLocalVersion(); } handle.getScheduleCallback().scheduledTrigger(services.getEngineLevelExtensionServicesContext()); handle.getAgentInstanceHandle().internalDispatch(); } } catch (RuntimeException ex) { services.getExceptionHandlingService().handleException(ex, handle.getAgentInstanceHandle(), ExceptionHandlerExceptionType.PROCESS, null); } finally { if (handle.getAgentInstanceHandle().isHasTableAccess()) { services.getTableService().getTableExprEvaluatorContext().releaseAcquiredLocks(); } handle.getAgentInstanceHandle().getStatementAgentInstanceLock().releaseWriteLock(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aTimeCP(); } } } /** * Processing multiple filter matches for a statement. * * @param handle statement handle * @param callbackList object containing callbacks * @param theEvent to process * @param version filter version */ public void processStatementFilterMultiple(EPStatementAgentInstanceHandle handle, Object callbackList, EventBean theEvent, long version) { if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qEventCP(theEvent, handle, services.getSchedulingService().getTime()); } handle.getStatementAgentInstanceLock().acquireWriteLock(); try { if (handle.isHasVariables()) { services.getVariableService().setLocalVersion(); } if (!handle.isCurrentFilter(version)) { boolean handled = false; if (handle.getFilterFaultHandler() != null) { handled = handle.getFilterFaultHandler().handleFilterFault(theEvent, version); } if (!handled) { handleFilterFault(handle, theEvent); } } else { if (callbackList instanceof Collection) { Collection<FilterHandleCallback> callbacks = (Collection<FilterHandleCallback>) callbackList; handle.getMultiMatchHandler().handle(callbacks, theEvent); } else { FilterHandleCallback single = (FilterHandleCallback) callbackList; single.matchFound(theEvent, null); } // internal join processing, if applicable handle.internalDispatch(); } } catch (RuntimeException ex) { services.getExceptionHandlingService().handleException(ex, handle, ExceptionHandlerExceptionType.PROCESS, theEvent); } finally { if (handle.isHasTableAccess()) { services.getTableService().getTableExprEvaluatorContext().releaseAcquiredLocks(); } handle.getStatementAgentInstanceLock().releaseWriteLock(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aEventCP(); } } } /** * Process a single match. * * @param handle statement * @param handleCallback callback * @param theEvent event to indicate * @param version filter version */ public void processStatementFilterSingle(EPStatementAgentInstanceHandle handle, EPStatementHandleCallback handleCallback, EventBean theEvent, long version) { if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qEventCP(theEvent, handle, services.getSchedulingService().getTime()); } handle.getStatementAgentInstanceLock().acquireWriteLock(); try { if (handle.isHasVariables()) { services.getVariableService().setLocalVersion(); } if (!handle.isCurrentFilter(version)) { boolean handled = false; if (handle.getFilterFaultHandler() != null) { handled = handle.getFilterFaultHandler().handleFilterFault(theEvent, version); } if (!handled) { handleFilterFault(handle, theEvent); } } else { handleCallback.getFilterCallback().matchFound(theEvent, null); } // internal join processing, if applicable handle.internalDispatch(); } catch (RuntimeException ex) { services.getExceptionHandlingService().handleException(ex, handle, ExceptionHandlerExceptionType.PROCESS, theEvent); } finally { if (handle.isHasTableAccess()) { services.getTableService().getTableExprEvaluatorContext().releaseAcquiredLocks(); } handleCallback.getAgentInstanceHandle().getStatementAgentInstanceLock().releaseWriteLock(); if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aEventCP(); } } } protected void handleFilterFault(EPStatementAgentInstanceHandle faultingHandle, EventBean theEvent) { ArrayDeque<FilterHandle> callbacksForStatement = new ArrayDeque<FilterHandle>(); long version = services.getFilterService().evaluate(theEvent, callbacksForStatement, faultingHandle.getStatementId()); if (callbacksForStatement.size() == 1) { EPStatementHandleCallback handleCallback = (EPStatementHandleCallback) callbacksForStatement.getFirst(); processStatementFilterSingle(handleCallback.getAgentInstanceHandle(), handleCallback, theEvent, version); return; } if (callbacksForStatement.isEmpty()) { return; } Map<EPStatementAgentInstanceHandle, Object> stmtCallbacks; if (isPrioritized) { stmtCallbacks = new TreeMap<EPStatementAgentInstanceHandle, Object>(EPStatementAgentInstanceHandleComparator.INSTANCE); } else { stmtCallbacks = new HashMap<EPStatementAgentInstanceHandle, Object>(); } for (FilterHandle filterHandle : callbacksForStatement) { EPStatementHandleCallback handleCallback = (EPStatementHandleCallback) filterHandle; EPStatementAgentInstanceHandle handle = handleCallback.getAgentInstanceHandle(); if (handle.isCanSelfJoin() || isPrioritized) { Object callbacks = stmtCallbacks.get(handle); if (callbacks == null) { stmtCallbacks.put(handle, handleCallback.getFilterCallback()); } else if (callbacks instanceof ArrayDeque) { ArrayDeque<FilterHandleCallback> q = (ArrayDeque<FilterHandleCallback>) callbacks; q.add(handleCallback.getFilterCallback()); } else { ArrayDeque<FilterHandleCallback> q = new ArrayDeque<FilterHandleCallback>(4); q.add((FilterHandleCallback) callbacks); q.add(handleCallback.getFilterCallback()); stmtCallbacks.put(handle, q); } continue; } processStatementFilterSingle(handle, handleCallback, theEvent, version); } if (stmtCallbacks.isEmpty()) { return; } for (Map.Entry<EPStatementAgentInstanceHandle, Object> entry : stmtCallbacks.entrySet()) { EPStatementAgentInstanceHandle handle = entry.getKey(); Object callbackList = entry.getValue(); processStatementFilterMultiple(handle, callbackList, theEvent, version); if (isPrioritized && handle.isPreemptive()) { break; } } } /** * Dispatch events. */ public void dispatch() { try { services.getDispatchService().dispatch(); } catch (RuntimeException ex) { throw new EPException(ex); } } public boolean isExternalClockingEnabled() { return isUsingExternalClocking; } /** * Destroy for destroying an engine instance: sets references to null and clears thread-locals */ public void destroy() { services = null; removeFromThreadLocals(); matchesArrayThreadLocal = null; matchesPerStmtThreadLocal = null; scheduleArrayThreadLocal = null; schedulePerStmtThreadLocal = null; } public void initialize() { initThreadLocals(); threadWorkQueue = new ThreadWorkQueue(); } public void clearCaches() { initThreadLocals(); } public void setUnmatchedListener(UnmatchedListener listener) { this.unmatchedListener = listener; } public void setVariableValue(String variableName, Object variableValue) throws EPException { VariableMetaData metaData = services.getVariableService().getVariableMetaData(variableName); checkVariable(variableName, metaData, true, false); services.getVariableService().getReadWriteLock().writeLock().lock(); try { services.getVariableService().checkAndWrite(variableName, EPStatementStartMethod.DEFAULT_AGENT_INSTANCE_ID, variableValue); services.getVariableService().commit(); } finally { services.getVariableService().getReadWriteLock().writeLock().unlock(); } } public void setVariableValue(Map<String, Object> variableValues) throws EPException { setVariableValueInternal(variableValues, EPStatementStartMethod.DEFAULT_AGENT_INSTANCE_ID, false); } public void setVariableValue(Map<String, Object> variableValues, int agentInstanceId) throws VariableValueException, VariableNotFoundException { setVariableValueInternal(variableValues, agentInstanceId, true); } public Object getVariableValue(String variableName) throws EPException { services.getVariableService().setLocalVersion(); VariableMetaData metaData = services.getVariableService().getVariableMetaData(variableName); if (metaData == null) { throw new VariableNotFoundException("Variable by name '" + variableName + "' has not been declared"); } if (metaData.getContextPartitionName() != null) { throw new VariableNotFoundException("Variable by name '" + variableName + "' has been declared for context '" + metaData.getContextPartitionName() + "' and cannot be read without context partition selector"); } VariableReader reader = services.getVariableService().getReader(variableName, EPStatementStartMethod.DEFAULT_AGENT_INSTANCE_ID); Object value = reader.getValue(); if (value == null || reader.getVariableMetaData().getEventType() == null) { return value; } return ((EventBean) value).getUnderlying(); } public Map<String, List<ContextPartitionVariableState>> getVariableValue(Set<String> variableNames, ContextPartitionSelector contextPartitionSelector) throws VariableNotFoundException { services.getVariableService().setLocalVersion(); String contextPartitionName = null; for (String variableName : variableNames) { VariableMetaData metaData = services.getVariableService().getVariableMetaData(variableName); if (metaData == null) { throw new VariableNotFoundException("Variable by name '" + variableName + "' has not been declared"); } if (metaData.getContextPartitionName() == null) { throw new VariableNotFoundException("Variable by name '" + variableName + "' is a global variable and not context-partitioned"); } if (contextPartitionName == null) { contextPartitionName = metaData.getContextPartitionName(); } else { if (!contextPartitionName.equals(metaData.getContextPartitionName())) { throw new VariableNotFoundException("Variable by name '" + variableName + "' is a declared for context '" + metaData.getContextPartitionName() + "' however the expected context is '" + contextPartitionName + "'"); } } } ContextManager contextManager = services.getContextManagementService().getContextManager(contextPartitionName); if (contextManager == null) { throw new VariableNotFoundException("Context by name '" + contextPartitionName + "' cannot be found"); } Map<Integer, ContextPartitionDescriptor> contextPartitions = contextManager.extractPaths(contextPartitionSelector).getContextPartitionInformation(); if (contextPartitions.isEmpty()) { return Collections.emptyMap(); } Map<String, List<ContextPartitionVariableState>> statesMap = new HashMap<String, List<ContextPartitionVariableState>>(); for (String variableName : variableNames) { List<ContextPartitionVariableState> states = new ArrayList<ContextPartitionVariableState>(); statesMap.put(variableName, states); for (Map.Entry<Integer, ContextPartitionDescriptor> entry : contextPartitions.entrySet()) { VariableReader reader = services.getVariableService().getReader(variableName, entry.getKey()); Object value = reader.getValue(); if (value != null && reader.getVariableMetaData().getEventType() != null) { value = ((EventBean) value).getUnderlying(); } states.add(new ContextPartitionVariableState(entry.getKey(), entry.getValue().getIdentifier(), value)); } } return statesMap; } public Map<String, Object> getVariableValue(Set<String> variableNames) throws EPException { services.getVariableService().setLocalVersion(); Map<String, Object> values = new HashMap<String, Object>(); for (String variableName : variableNames) { VariableMetaData metaData = services.getVariableService().getVariableMetaData(variableName); checkVariable(variableName, metaData, false, false); VariableReader reader = services.getVariableService().getReader(variableName, EPStatementStartMethod.DEFAULT_AGENT_INSTANCE_ID); if (reader == null) { throw new VariableNotFoundException("Variable by name '" + variableName + "' has not been declared"); } Object value = reader.getValue(); if (value != null && reader.getVariableMetaData().getEventType() != null) { value = ((EventBean) value).getUnderlying(); } values.put(variableName, value); } return values; } public Map<String, Object> getVariableValueAll() throws EPException { services.getVariableService().setLocalVersion(); Map<String, VariableReader> variables = services.getVariableService().getVariableReadersNonCP(); Map<String, Object> values = new HashMap<String, Object>(); for (Map.Entry<String, VariableReader> entry : variables.entrySet()) { Object value = entry.getValue().getValue(); values.put(entry.getValue().getVariableMetaData().getVariableName(), value); } return values; } public Map<String, Class> getVariableTypeAll() { Map<String, VariableReader> variables = services.getVariableService().getVariableReadersNonCP(); Map<String, Class> values = new HashMap<String, Class>(); for (Map.Entry<String, VariableReader> entry : variables.entrySet()) { Class type = entry.getValue().getVariableMetaData().getType(); values.put(entry.getValue().getVariableMetaData().getVariableName(), type); } return values; } public Class getVariableType(String variableName) { VariableMetaData metaData = services.getVariableService().getVariableMetaData(variableName); if (metaData == null) { return null; } return metaData.getType(); } public EPOnDemandQueryResult executeQuery(String epl, ContextPartitionSelector[] contextPartitionSelectors) { if (contextPartitionSelectors == null) { throw new IllegalArgumentException("No context partition selectors provided"); } return executeQueryInternal(epl, null, null, contextPartitionSelectors); } public EPOnDemandQueryResult executeQuery(String epl) { return executeQueryInternal(epl, null, null, null); } public EPOnDemandQueryResult executeQuery(EPStatementObjectModel model) { return executeQueryInternal(null, model, null, null); } public EPOnDemandQueryResult executeQuery(EPStatementObjectModel model, ContextPartitionSelector[] contextPartitionSelectors) { if (contextPartitionSelectors == null) { throw new IllegalArgumentException("No context partition selectors provided"); } return executeQueryInternal(null, model, null, contextPartitionSelectors); } public EPOnDemandQueryResult executeQuery(EPOnDemandPreparedQueryParameterized parameterizedQuery) { return executeQueryInternal(null, null, parameterizedQuery, null); } public EPOnDemandQueryResult executeQuery(EPOnDemandPreparedQueryParameterized parameterizedQuery, ContextPartitionSelector[] contextPartitionSelectors) { return executeQueryInternal(null, null, parameterizedQuery, contextPartitionSelectors); } private EPOnDemandQueryResult executeQueryInternal(String epl, EPStatementObjectModel model, EPOnDemandPreparedQueryParameterized parameterizedQuery, ContextPartitionSelector[] contextPartitionSelectors) { try { EPPreparedExecuteMethod executeMethod = getExecuteMethod(epl, model, parameterizedQuery); EPPreparedQueryResult result = executeMethod.execute(contextPartitionSelectors); return new EPQueryResultImpl(result); } catch (EPStatementException ex) { throw ex; } catch (Throwable t) { String message = "Error executing statement: " + t.getMessage(); log.info(message, t); throw new EPStatementException(message, t, epl); } } public EPOnDemandPreparedQuery prepareQuery(String epl) { return prepareQueryInternal(epl, null); } public EPOnDemandPreparedQuery prepareQuery(EPStatementObjectModel model) { return prepareQueryInternal(null, model); } public EPOnDemandPreparedQueryParameterized prepareQueryWithParameters(String epl) { // compile to specification String stmtName = UuidGenerator.generate(); StatementSpecRaw statementSpec = EPAdministratorHelper.compileEPL(epl, epl, true, stmtName, services, SelectClauseStreamSelectorEnum.ISTREAM_ONLY); // map to object model thus finding all substitution parameters and their indexes StatementSpecUnMapResult unmapped = StatementSpecMapper.unmap(statementSpec); // the prepared statement is the object model plus a list of substitution parameters // map to specification will refuse any substitution parameters that are unfilled return new EPPreparedStatementImpl(unmapped.getObjectModel(), unmapped.getSubstitutionParams(), epl); } private EPOnDemandPreparedQuery prepareQueryInternal(String epl, EPStatementObjectModel model) { try { EPPreparedExecuteMethod startMethod = getExecuteMethod(epl, model, null); return new EPPreparedQueryImpl(startMethod, epl); } catch (EPStatementException ex) { throw ex; } catch (Throwable t) { String message = "Error executing statement: " + t.getMessage(); log.debug(message, t); throw new EPStatementException(message, epl); } } private EPPreparedExecuteMethod getExecuteMethod(String epl, EPStatementObjectModel model, EPOnDemandPreparedQueryParameterized parameterizedQuery) { String stmtName = UuidGenerator.generate(); int stmtId = -1; try { StatementSpecRaw spec; if (epl != null) { spec = EPAdministratorHelper.compileEPL(epl, epl, true, stmtName, services, SelectClauseStreamSelectorEnum.ISTREAM_ONLY); } else if (model != null) { spec = StatementSpecMapper.map(model, services.getEngineImportService(), services.getVariableService(), services.getConfigSnapshot(), services.getSchedulingService(), services.getEngineURI(), services.getPatternNodeFactory(), services.getNamedWindowMgmtService(), services.getContextManagementService(), services.getExprDeclaredService(), services.getTableService()); epl = model.toEPL(); } else { EPPreparedStatementImpl prepared = (EPPreparedStatementImpl) parameterizedQuery; spec = StatementSpecMapper.map(prepared.getModel(), services.getEngineImportService(), services.getVariableService(), services.getConfigSnapshot(), services.getSchedulingService(), services.getEngineURI(), services.getPatternNodeFactory(), services.getNamedWindowMgmtService(), services.getContextManagementService(), services.getExprDeclaredService(), services.getTableService()); epl = prepared.getOptionalEPL(); if (epl == null) { epl = prepared.getModel().toEPL(); } } Annotation[] annotations = AnnotationUtil.compileAnnotations(spec.getAnnotations(), services.getEngineImportService(), epl); boolean writesToTables = StatementLifecycleSvcUtil.isWritesToTables(spec, services.getTableService()); StatementContext statementContext = services.getStatementContextFactory().makeContext(stmtId, stmtName, epl, StatementType.SELECT, services, null, true, annotations, null, true, spec, Collections.<ExprSubselectNode>emptyList(), writesToTables, null); // walk subselects, alias expressions, declared expressions, dot-expressions ExprNodeSubselectDeclaredDotVisitor visitor; try { visitor = StatementSpecRawAnalyzer.walkSubselectAndDeclaredDotExpr(spec); } catch (ExprValidationException ex) { throw new EPStatementException(ex.getMessage(), epl); } StatementSpecCompiled compiledSpec = StatementLifecycleSvcImpl.compile(spec, epl, statementContext, false, true, annotations, visitor.getSubselects(), Collections.<ExprDeclaredNode>emptyList(), spec.getTableExpressions(), services); if (compiledSpec.getInsertIntoDesc() != null) { return new EPPreparedExecuteIUDInsertInto(compiledSpec, services, statementContext); } else if (compiledSpec.getFireAndForgetSpec() == null) { // null indicates a select-statement, same as continuous query if (compiledSpec.getUpdateSpec() != null) { throw new EPStatementException("Provided EPL expression is a continuous query expression (not an on-demand query), please use the administrator createEPL API instead", epl); } return new EPPreparedExecuteMethodQuery(compiledSpec, services, statementContext); } else if (compiledSpec.getFireAndForgetSpec() instanceof FireAndForgetSpecDelete) { return new EPPreparedExecuteIUDSingleStreamDelete(compiledSpec, services, statementContext); } else if (compiledSpec.getFireAndForgetSpec() instanceof FireAndForgetSpecUpdate) { return new EPPreparedExecuteIUDSingleStreamUpdate(compiledSpec, services, statementContext); } else { throw new IllegalStateException("Unrecognized FAF code " + compiledSpec.getFireAndForgetSpec()); } } catch (EPStatementException ex) { throw ex; } catch (Throwable t) { String message = "Error executing statement: " + t.getMessage(); log.debug(message, t); throw new EPStatementException(message, t, epl); } } public EventSender getEventSender(String eventTypeName) { return services.getEventAdapterService().getStaticTypeEventSender(this, eventTypeName, services.getThreadingService()); } public EventSender getEventSender(URI[] uri) throws EventTypeException { return services.getEventAdapterService().getDynamicTypeEventSender(this, uri, services.getThreadingService()); } public EventRenderer getEventRenderer() { if (eventRenderer == null) { eventRenderer = new EventRendererImpl(); } return eventRenderer; } public long getCurrentTime() { return services.getSchedulingService().getTime(); } public Long getNextScheduledTime() { return services.getSchedulingService().getNearestTimeHandle(); } public Map<String, Long> getStatementNearestSchedules() { return getStatementNearestSchedulesInternal(services.getSchedulingService(), services.getStatementLifecycleSvc()); } protected static Map<String, Long> getStatementNearestSchedulesInternal(SchedulingServiceSPI schedulingService, StatementLifecycleSvc statementLifecycleSvc) { final Map<Integer, Long> schedulePerStatementId = new HashMap<Integer, Long>(); schedulingService.visitSchedules(new ScheduleVisitor() { public void visit(ScheduleVisit visit) { if (schedulePerStatementId.containsKey(visit.getStatementId())) { return; } schedulePerStatementId.put(visit.getStatementId(), visit.getTimestamp()); } }); Map<String, Long> result = new HashMap<String, Long>(); for (Map.Entry<Integer, Long> schedule : schedulePerStatementId.entrySet()) { String stmtName = statementLifecycleSvc.getStatementNameById(schedule.getKey()); if (stmtName != null) { result.put(stmtName, schedule.getValue()); } } return result; } public String getEngineURI() { return services.getEngineURI(); } public EPDataFlowRuntime getDataFlowRuntime() { return services.getDataFlowService(); } private void removeFromThreadLocals() { if (matchesArrayThreadLocal != null) { matchesArrayThreadLocal.remove(); } if (matchesPerStmtThreadLocal != null) { matchesPerStmtThreadLocal.remove(); } if (scheduleArrayThreadLocal != null) { scheduleArrayThreadLocal.remove(); } if (schedulePerStmtThreadLocal != null) { schedulePerStmtThreadLocal.remove(); } } private void initThreadLocals() { removeFromThreadLocals(); matchesArrayThreadLocal = new ThreadLocal<ArrayBackedCollection<FilterHandle>>() { protected synchronized ArrayBackedCollection<FilterHandle> initialValue() { return new ArrayBackedCollection<FilterHandle>(100); } }; scheduleArrayThreadLocal = new ThreadLocal<ArrayBackedCollection<ScheduleHandle>>() { protected synchronized ArrayBackedCollection<ScheduleHandle> initialValue() { return new ArrayBackedCollection<ScheduleHandle>(100); } }; matchesPerStmtThreadLocal = new ThreadLocal<Map<EPStatementAgentInstanceHandle, Object>>() { protected synchronized Map<EPStatementAgentInstanceHandle, Object> initialValue() { if (isPrioritized) { return new TreeMap<EPStatementAgentInstanceHandle, Object>(EPStatementAgentInstanceHandleComparator.INSTANCE); } else { return new HashMap<EPStatementAgentInstanceHandle, Object>(); } } }; schedulePerStmtThreadLocal = new ThreadLocal<Map<EPStatementAgentInstanceHandle, Object>>() { protected synchronized Map<EPStatementAgentInstanceHandle, Object> initialValue() { if (isPrioritized) { return new TreeMap<EPStatementAgentInstanceHandle, Object>(EPStatementAgentInstanceHandleComparator.INSTANCE); } else { return new HashMap<EPStatementAgentInstanceHandle, Object>(); } } }; } private void checkVariable(String variableName, VariableMetaData metaData, boolean settable, boolean requireContextPartitioned) { if (metaData == null) { throw new VariableNotFoundException("Variable by name '" + variableName + "' has not been declared"); } if (!requireContextPartitioned) { if (metaData.getContextPartitionName() != null) { throw new VariableNotFoundException("Variable by name '" + variableName + "' has been declared for context '" + metaData.getContextPartitionName() + "' and cannot be set without context partition selectors"); } } else { if (metaData.getContextPartitionName() == null) { throw new VariableNotFoundException("Variable by name '" + variableName + "' is a global variable and not context-partitioned"); } } if (settable && metaData.isConstant()) { throw new VariableConstantValueException("Variable by name '" + variableName + "' is declared as constant and may not be assigned a new value"); } } private void setVariableValueInternal(Map<String, Object> variableValues, int agentInstanceId, boolean requireContextPartitioned) throws EPException { // verify for (Map.Entry<String, Object> entry : variableValues.entrySet()) { String variableName = entry.getKey(); VariableMetaData metaData = services.getVariableService().getVariableMetaData(variableName); checkVariable(variableName, metaData, true, requireContextPartitioned); } // set values services.getVariableService().getReadWriteLock().writeLock().lock(); try { for (Map.Entry<String, Object> entry : variableValues.entrySet()) { String variableName = entry.getKey(); try { services.getVariableService().checkAndWrite(variableName, agentInstanceId, entry.getValue()); } catch (RuntimeException ex) { services.getVariableService().rollback(); throw ex; } } services.getVariableService().commit(); } finally { services.getVariableService().getReadWriteLock().writeLock().unlock(); } } protected static final Logger log = LoggerFactory.getLogger(EPRuntimeImpl.class); }