/*
* *************************************************************************************
* Copyright (C) 2008 EsperTech, Inc. All rights reserved. *
* http://esper.codehaus.org *
* 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.context.util;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.core.context.factory.StatementAgentInstanceFactoryResult;
import com.espertech.esper.core.context.factory.StatementAgentInstancePreload;
import com.espertech.esper.core.context.mgr.AgentInstance;
import com.espertech.esper.core.context.mgr.AgentInstanceFilterProxy;
import com.espertech.esper.core.context.mgr.ContextControllerStatementBase;
import com.espertech.esper.core.context.mgr.ContextControllerTreeAgentInstanceList;
import com.espertech.esper.core.context.stmt.AIRegistryAggregation;
import com.espertech.esper.core.context.stmt.AIRegistryExpr;
import com.espertech.esper.core.context.subselect.SubSelectStrategyHolder;
import com.espertech.esper.core.service.*;
import com.espertech.esper.core.start.EPStatementStopMethodImpl;
import com.espertech.esper.epl.expression.*;
import com.espertech.esper.epl.script.AgentInstanceScriptContext;
import com.espertech.esper.epl.view.OutputProcessViewTerminable;
import com.espertech.esper.event.MappedEventBean;
import com.espertech.esper.filter.FilterHandle;
import com.espertech.esper.util.StopCallback;
import com.espertech.esper.view.Viewable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.*;
public class StatementAgentInstanceUtil {
private static final Log log = LogFactory.getLog(EPStatementStopMethodImpl.class);
public static void handleFilterFault(EventBean theEvent, long version, EPServicesContext servicesContext, Map<Integer, ContextControllerTreeAgentInstanceList> agentInstanceListMap) {
for (Map.Entry<Integer, ContextControllerTreeAgentInstanceList> agentInstanceEntry : agentInstanceListMap.entrySet()) {
if (agentInstanceEntry.getValue().getFilterVersionAfterAllocation() > version) {
for (AgentInstance context : agentInstanceEntry.getValue().getAgentInstances()) {
StatementAgentInstanceUtil.evaluateEventForStatement(servicesContext, theEvent, null, context.getAgentInstanceContext());
}
}
}
}
public static void stopAgentInstances(List<AgentInstance> agentInstances, Map<String, Object> terminationProperties, EPServicesContext servicesContext, boolean isStatementStop) {
if (agentInstances == null) {
return;
}
for (AgentInstance instance : agentInstances) {
stopAgentInstance(instance, terminationProperties, servicesContext, isStatementStop);
}
}
public static void stopAgentInstance(AgentInstance agentInstance, Map<String, Object> terminationProperties, EPServicesContext servicesContext, boolean isStatementStop) {
if (terminationProperties != null) {
agentInstance.getAgentInstanceContext().getContextProperties().getProperties().putAll(terminationProperties);
}
StatementAgentInstanceUtil.stop(agentInstance.getStopCallback(), agentInstance.getAgentInstanceContext(), agentInstance.getFinalView(), servicesContext, isStatementStop);
}
public static void stopSafe(Collection<StopCallback> terminationCallbacks, StopCallback[] stopCallbacks, StatementContext statementContext) {
StopCallback[] terminationArr = terminationCallbacks.toArray(new StopCallback[terminationCallbacks.size()]);
stopSafe(terminationArr, statementContext);
stopSafe(stopCallbacks, statementContext);
}
public static void stopSafe(StopCallback[] stopMethods, StatementContext statementContext) {
for (StopCallback stopCallback : stopMethods) {
stopSafe(stopCallback, statementContext);
}
}
public static void stopSafe(StopCallback stopMethod, StatementContext statementContext) {
try {
stopMethod.stop();
}
catch (RuntimeException e) {
log.warn("Failed to perform statement stop for statement '" + statementContext.getStatementName() +
"' expression '" + statementContext.getExpression() + "' : " + e.getMessage(), e);
}
}
public static void stop(StopCallback stopCallback, AgentInstanceContext agentInstanceContext, Viewable finalView, EPServicesContext servicesContext, boolean isStatementStop) {
// obtain statement lock
StatementAgentInstanceLock lock = agentInstanceContext.getEpStatementAgentInstanceHandle().getStatementAgentInstanceLock();
lock.acquireWriteLock(null);
try {
if (finalView instanceof OutputProcessViewTerminable && !isStatementStop) {
OutputProcessViewTerminable terminable = (OutputProcessViewTerminable) finalView;
terminable.terminated();
}
stopSafe(stopCallback, agentInstanceContext.getStatementContext());
if (servicesContext.getSchedulableAgentInstanceDirectory() != null) {
servicesContext.getSchedulableAgentInstanceDirectory().remove(agentInstanceContext.getStatementContext().getStatementId(), agentInstanceContext.getAgentInstanceId());
}
// indicate method resolution
agentInstanceContext.getStatementContext().getMethodResolutionService().destroyedAgentInstance(agentInstanceContext.getAgentInstanceId());
// release resource
agentInstanceContext.getStatementContext().getStatementAgentInstanceRegistry().deassign(agentInstanceContext.getAgentInstanceId());
// cause any remaining schedules, that may concide with the caller's schedule, to be ignored
agentInstanceContext.getEpStatementAgentInstanceHandle().setDestroyed(true);
// cause any filters, that may concide with the caller's filters, to be ignored
agentInstanceContext.getEpStatementAgentInstanceHandle().getStatementFilterVersion().setStmtFilterVersion(Long.MAX_VALUE);
if (agentInstanceContext.getStatementContext().getExtensionServicesContext() != null) {
agentInstanceContext.getStatementContext().getExtensionServicesContext().endContextPartition(agentInstanceContext.getAgentInstanceId());
}
}
finally {
lock.releaseWriteLock(null);
}
}
public static StatementAgentInstanceFactoryResult start(EPServicesContext servicesContext,
ContextControllerStatementBase statement,
boolean isSingleInstanceContext,
int agentInstanceId,
MappedEventBean agentInstanceProperties,
AgentInstanceFilterProxy agentInstanceFilterProxy,
boolean isRecoveringResilient)
{
StatementContext statementContext = statement.getStatementContext();
// make a new lock for the agent instance or use the already-allocated default lock
StatementAgentInstanceLock agentInstanceLock;
if (isSingleInstanceContext) {
agentInstanceLock = statementContext.getDefaultAgentInstanceLock();
}
else {
agentInstanceLock = servicesContext.getStatementLockFactory().getStatementLock(statementContext.getStatementName(), statementContext.getExpression(), statementContext.getAnnotations(), statementContext.isStatelessSelect());
}
// share the filter version between agent instance handle (callbacks) and agent instance context
StatementAgentInstanceFilterVersion filterVersion = new StatementAgentInstanceFilterVersion();
// create handle that comtains lock for use in scheduling and filter callbacks
EPStatementAgentInstanceHandle agentInstanceHandle = new EPStatementAgentInstanceHandle(statementContext.getEpStatementHandle(), agentInstanceLock, agentInstanceId, filterVersion);
// create agent instance context
AgentInstanceScriptContext agentInstanceScriptContext = null;
if (statementContext.getDefaultAgentInstanceScriptContext() != null) {
agentInstanceScriptContext = new AgentInstanceScriptContext();
}
AgentInstanceContext agentInstanceContext = new AgentInstanceContext(statementContext, agentInstanceHandle, agentInstanceId, agentInstanceFilterProxy, agentInstanceProperties, agentInstanceScriptContext);
StatementAgentInstanceLock statementAgentInstanceLock = agentInstanceContext.getEpStatementAgentInstanceHandle().getStatementAgentInstanceLock();
statementAgentInstanceLock.acquireWriteLock(null);
try {
// start
StatementAgentInstanceFactoryResult startResult = statement.getFactory().newContext(agentInstanceContext, isRecoveringResilient);
// hook up with listeners+subscribers
startResult.getFinalView().addView(statement.getMergeView()); // hook output to merge view
// assign agents for expression-node based strategies
AIRegistryExpr aiExprSvc = statementContext.getStatementAgentInstanceRegistry().getAgentInstanceExprService();
AIRegistryAggregation aiAggregationSvc = statementContext.getStatementAgentInstanceRegistry().getAgentInstanceAggregationService();
// allocate aggregation service
if (startResult.getOptionalAggegationService() != null) {
aiAggregationSvc.assignService(agentInstanceId, startResult.getOptionalAggegationService());
}
// allocate subquery
for (Map.Entry<ExprSubselectNode, SubSelectStrategyHolder> item : startResult.getSubselectStrategies().entrySet()) {
ExprSubselectNode node = item.getKey();
SubSelectStrategyHolder strategyHolder = item.getValue();
aiExprSvc.getSubselectService(node).assignService(agentInstanceId, strategyHolder.getStategy());
aiExprSvc.getSubselectAggregationService(node).assignService(agentInstanceId, strategyHolder.getSubselectAggregationService());
// allocate prior within subquery
for (Map.Entry<ExprPriorNode, ExprPriorEvalStrategy> priorEntry : strategyHolder.getPriorStrategies().entrySet()) {
aiExprSvc.getPriorServices(priorEntry.getKey()).assignService(agentInstanceId, priorEntry.getValue());
}
// allocate previous within subquery
for (Map.Entry<ExprPreviousNode, ExprPreviousEvalStrategy> prevEntry : strategyHolder.getPreviousNodeStrategies().entrySet()) {
aiExprSvc.getPreviousServices(prevEntry.getKey()).assignService(agentInstanceId, prevEntry.getValue());
}
}
// allocate prior-expressions
for (Map.Entry<ExprPriorNode, ExprPriorEvalStrategy> item : startResult.getPriorNodeStrategies().entrySet()) {
aiExprSvc.getPriorServices(item.getKey()).assignService(agentInstanceId, item.getValue());
}
// allocate previous-expressions
for (Map.Entry<ExprPreviousNode, ExprPreviousEvalStrategy> item : startResult.getPreviousNodeStrategies().entrySet()) {
aiExprSvc.getPreviousServices(item.getKey()).assignService(agentInstanceId, item.getValue());
}
// execute preloads, if any
for (StatementAgentInstancePreload preload : startResult.getPreloadList()) {
preload.executePreload();
}
if (statementContext.getExtensionServicesContext() != null) {
statementContext.getExtensionServicesContext().startContextPartition(startResult, agentInstanceId);
}
// instantiate
return startResult;
}
finally {
statementAgentInstanceLock.releaseWriteLock(null);
}
}
public static void evaluateEventForStatement(EPServicesContext servicesContext, EventBean theEvent, Map<String, Object> optionalTriggeringPattern, AgentInstanceContext agentInstanceContext) {
if (theEvent != null) {
evaluateEventForStatementInternal(servicesContext, theEvent, agentInstanceContext);
}
if (optionalTriggeringPattern != null) {
// evaluation order definition is up to the originator of the triggering pattern
for (Map.Entry<String, Object> entry : optionalTriggeringPattern.entrySet()) {
if (entry.getValue() instanceof EventBean) {
evaluateEventForStatementInternal(servicesContext, (EventBean) entry.getValue(), agentInstanceContext);
}
else if (entry.getValue() instanceof EventBean[]) {
EventBean[] eventsArray = (EventBean[]) entry.getValue();
for (EventBean eventElement : eventsArray) {
evaluateEventForStatementInternal(servicesContext, eventElement, agentInstanceContext);
}
}
}
}
}
private static void evaluateEventForStatementInternal(EPServicesContext servicesContext, EventBean theEvent, AgentInstanceContext agentInstanceContext) {
// context was created - reevaluate for the given event
ArrayDeque<FilterHandle> callbacks = new ArrayDeque<FilterHandle>();
servicesContext.getFilterService().evaluate(theEvent, callbacks, agentInstanceContext.getStatementContext().getStatementId());
try
{
servicesContext.getVariableService().setLocalVersion();
// sub-selects always go first
for (FilterHandle handle : callbacks)
{
EPStatementHandleCallback callback = (EPStatementHandleCallback) handle;
if (callback.getAgentInstanceHandle() != agentInstanceContext.getEpStatementAgentInstanceHandle()) {
continue;
}
callback.getFilterCallback().matchFound(theEvent, null);
}
agentInstanceContext.getEpStatementAgentInstanceHandle().internalDispatch(agentInstanceContext);
// No thread work queue processing: leave that for later, but dispatch (i.e. no processThreadWorkQueue);
servicesContext.getInternalEventEngineRouteDest().dispatch();
}
catch (RuntimeException ex) {
servicesContext.getExceptionHandlingService().handleException(ex, agentInstanceContext.getEpStatementAgentInstanceHandle());
}
}
public static boolean evaluateFilterForStatement(EPServicesContext servicesContext, EventBean theEvent, AgentInstanceContext agentInstanceContext, FilterHandle filterHandle) {
// context was created - reevaluate for the given event
ArrayDeque<FilterHandle> callbacks = new ArrayDeque<FilterHandle>();
servicesContext.getFilterService().evaluate(theEvent, callbacks, agentInstanceContext.getStatementContext().getStatementId());
try
{
servicesContext.getVariableService().setLocalVersion();
// sub-selects always go first
for (FilterHandle handle : callbacks)
{
if (handle == filterHandle) {
return true;
}
}
agentInstanceContext.getEpStatementAgentInstanceHandle().internalDispatch(agentInstanceContext);
}
catch (RuntimeException ex) {
servicesContext.getExceptionHandlingService().handleException(ex, agentInstanceContext.getEpStatementAgentInstanceHandle());
}
return false;
}
public static StopCallback getStopCallback(List<StopCallback> stopCallbacks, final AgentInstanceContext agentInstanceContext) {
final StopCallback[] stopCallbackArr = stopCallbacks.toArray(new StopCallback[stopCallbacks.size()]);
return new StopCallback() {
public void stop() {
StatementAgentInstanceUtil.stopSafe(agentInstanceContext.getTerminationCallbackRO(), stopCallbackArr, agentInstanceContext.getStatementContext());
}
};
}
}