/*
***************************************************************************************
* 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.context.mgr;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.context.*;
import com.espertech.esper.collection.MultiKeyUntyped;
import com.espertech.esper.core.context.util.AgentInstanceContext;
import com.espertech.esper.core.context.util.ContextControllerSelectorUtil;
import com.espertech.esper.core.context.util.StatementAgentInstanceUtil;
import com.espertech.esper.core.service.StatementAgentInstanceLock;
import com.espertech.esper.epl.core.EngineImportService;
import com.espertech.esper.epl.expression.core.ExprEvaluator;
import com.espertech.esper.epl.expression.core.ExprNodeUtility;
import com.espertech.esper.epl.spec.ContextDetailCondition;
import com.espertech.esper.epl.spec.ContextDetailConditionCrontab;
import com.espertech.esper.event.EventAdapterService;
import com.espertech.esper.filter.FilterFaultHandler;
import com.espertech.esper.pattern.MatchedEventMap;
import com.espertech.esper.pattern.MatchedEventMapImpl;
import com.espertech.esper.schedule.ScheduleComputeHelper;
import com.espertech.esper.schedule.ScheduleSpec;
import java.util.*;
public class ContextControllerInitTerm implements ContextController, ContextControllerConditionCallback {
protected final int pathId;
protected final ContextControllerLifecycleCallback activationCallback;
protected final ContextControllerInitTermFactoryImpl factory;
protected ContextControllerCondition startCondition;
private Map<Object, EventBean> distinctContexts;
private EventBean nonDistinctLastTrigger;
private ExprEvaluator[] distinctEvaluators;
private EventBean[] eventsPerStream = new EventBean[1];
protected Map<ContextControllerCondition, ContextControllerInitTermInstance> endConditions = new LinkedHashMap<ContextControllerCondition, ContextControllerInitTermInstance>();
protected int currentSubpathId;
public ContextControllerInitTerm(int pathId, ContextControllerLifecycleCallback lifecycleCallback, ContextControllerInitTermFactoryImpl factory) {
this.pathId = pathId;
this.activationCallback = lifecycleCallback;
this.factory = factory;
if (factory.getContextDetail().getDistinctExpressions() != null && factory.getContextDetail().getDistinctExpressions().length > 0) {
distinctContexts = new HashMap<Object, EventBean>();
distinctEvaluators = ExprNodeUtility.getEvaluators(factory.getContextDetail().getDistinctExpressions());
}
}
public void importContextPartitions(ContextControllerState state, int pathIdToUse, ContextInternalFilterAddendum filterAddendum, AgentInstanceSelector agentInstanceSelector) {
initializeFromState(null, null, filterAddendum, state, pathIdToUse, agentInstanceSelector, true);
}
public void deletePath(ContextPartitionIdentifier identifier) {
ContextPartitionIdentifierInitiatedTerminated initterm = (ContextPartitionIdentifierInitiatedTerminated) identifier;
for (Map.Entry<ContextControllerCondition, ContextControllerInitTermInstance> entry : endConditions.entrySet()) {
if (ContextControllerInitTerm.compare(initterm.getStartTime(), initterm.getProperties(), initterm.getEndTime(),
entry.getValue().getStartTime(), entry.getValue().getStartProperties(), entry.getValue().getEndTime())) {
entry.getKey().deactivate();
endConditions.remove(entry.getKey());
removeDistinctKey(entry.getValue());
break;
}
}
}
public void activate(EventBean optionalTriggeringEvent, Map<String, Object> optionalTriggeringPattern, ContextControllerState controllerState, ContextInternalFilterAddendum filterAddendum, Integer importPathId) {
if (factory.getFactoryContext().getNestingLevel() == 1) {
controllerState = ContextControllerStateUtil.getRecoveryStates(factory.getFactoryContext().getStateCache(), factory.getFactoryContext().getOutermostContextName());
}
if (controllerState == null) {
startCondition = makeEndpoint(factory.getContextDetail().getStart(), filterAddendum, true, 0);
// if this is single-instance mode, check if we are currently running according to schedule
boolean currentlyRunning = startCondition.isImmediate();
if (!factory.getContextDetail().isOverlapping()) {
currentlyRunning = determineCurrentlyRunning(startCondition);
}
if (currentlyRunning) {
currentSubpathId++;
ContextControllerCondition endEndpoint = makeEndpoint(factory.getContextDetail().getEnd(), filterAddendum, false, currentSubpathId);
endEndpoint.activate(optionalTriggeringEvent, null, 0, factory.getFactoryContext().isRecoveringResilient());
long startTime = factory.getSchedulingService().getTime();
Long endTime = endEndpoint.getExpectedEndTime();
Map<String, Object> builtinProps = getBuiltinProperties(factory.getFactoryContext().getContextName(), startTime, endTime, Collections.<String, Object>emptyMap());
ContextControllerInstanceHandle instanceHandle = activationCallback.contextPartitionInstantiate(null, currentSubpathId, null, this, optionalTriggeringEvent, optionalTriggeringPattern, null, builtinProps, controllerState, filterAddendum, factory.getFactoryContext().isRecoveringResilient(), ContextPartitionState.STARTED);
endConditions.put(endEndpoint, new ContextControllerInitTermInstance(instanceHandle, null, startTime, endTime, currentSubpathId));
ContextControllerInitTermState state = new ContextControllerInitTermState(factory.getFactoryContext().getServicesContext().getSchedulingService().getTime(), builtinProps);
factory.getFactoryContext().getStateCache().addContextPath(factory.getFactoryContext().getOutermostContextName(), factory.getFactoryContext().getNestingLevel(), pathId, currentSubpathId, instanceHandle.getContextPartitionOrPathId(), state, factory.getBinding());
}
// non-overlapping and not currently running, or overlapping
if ((!factory.getContextDetail().isOverlapping() && !currentlyRunning) ||
factory.getContextDetail().isOverlapping()) {
startCondition.activate(optionalTriggeringEvent, null, 0, factory.getFactoryContext().isRecoveringResilient());
}
return;
}
startCondition = makeEndpoint(factory.getContextDetail().getStart(), filterAddendum, true, 0);
// if this is single-instance mode, check if we are currently running according to schedule
boolean currentlyRunning = false;
if (!factory.getContextDetail().isOverlapping()) {
currentlyRunning = determineCurrentlyRunning(startCondition);
}
if (!currentlyRunning) {
startCondition.activate(optionalTriggeringEvent, null, 0, factory.getFactoryContext().isRecoveringResilient());
}
int pathIdToUse = importPathId != null ? importPathId : pathId;
initializeFromState(optionalTriggeringEvent, optionalTriggeringPattern, filterAddendum, controllerState, pathIdToUse, null, false);
}
protected ContextControllerCondition makeEndpoint(ContextDetailCondition endpoint, ContextInternalFilterAddendum filterAddendum, boolean isStartEndpoint, int subPathId) {
return ContextControllerConditionFactory.getEndpoint(factory.getFactoryContext().getContextName(), factory.getFactoryContext().getServicesContext(), factory.getFactoryContext().getAgentInstanceContextCreate(),
endpoint, this, filterAddendum, isStartEndpoint,
factory.getFactoryContext().getNestingLevel(), pathId, subPathId);
}
public void visitSelectedPartitions(ContextPartitionSelector contextPartitionSelector, ContextPartitionVisitor visitor) {
int nestingLevel = factory.getFactoryContext().getNestingLevel();
if (contextPartitionSelector instanceof ContextPartitionSelectorFiltered) {
ContextPartitionSelectorFiltered filter = (ContextPartitionSelectorFiltered) contextPartitionSelector;
ContextPartitionIdentifierInitiatedTerminated identifier = new ContextPartitionIdentifierInitiatedTerminated();
for (Map.Entry<ContextControllerCondition, ContextControllerInitTermInstance> entry : endConditions.entrySet()) {
identifier.setEndTime(entry.getValue().getEndTime());
identifier.setStartTime(entry.getValue().getStartTime());
identifier.setProperties(entry.getValue().getStartProperties());
identifier.setContextPartitionId(entry.getValue().getInstanceHandle().getContextPartitionOrPathId());
if (filter.filter(identifier)) {
ContextControllerInitTermState state = new ContextControllerInitTermState(factory.getFactoryContext().getServicesContext().getSchedulingService().getTime(), entry.getValue().getStartProperties());
visitor.visit(nestingLevel, pathId, factory.getBinding(), state, this, entry.getValue().getInstanceHandle());
}
}
return;
}
if (contextPartitionSelector instanceof ContextPartitionSelectorById) {
ContextPartitionSelectorById filter = (ContextPartitionSelectorById) contextPartitionSelector;
for (Map.Entry<ContextControllerCondition, ContextControllerInitTermInstance> entry : endConditions.entrySet()) {
if (filter.getContextPartitionIds().contains(entry.getValue().getInstanceHandle().getContextPartitionOrPathId())) {
ContextControllerInitTermState state = new ContextControllerInitTermState(factory.getFactoryContext().getServicesContext().getSchedulingService().getTime(), entry.getValue().getStartProperties());
visitor.visit(nestingLevel, pathId, factory.getBinding(), state, this, entry.getValue().getInstanceHandle());
}
}
return;
}
if (contextPartitionSelector instanceof ContextPartitionSelectorAll) {
for (Map.Entry<ContextControllerCondition, ContextControllerInitTermInstance> entry : endConditions.entrySet()) {
ContextControllerInitTermState state = new ContextControllerInitTermState(factory.getFactoryContext().getServicesContext().getSchedulingService().getTime(), entry.getValue().getStartProperties());
visitor.visit(nestingLevel, pathId, factory.getBinding(), state, this, entry.getValue().getInstanceHandle());
}
return;
}
throw ContextControllerSelectorUtil.getInvalidSelector(new Class[0], contextPartitionSelector);
}
public void rangeNotification(Map<String, Object> builtinProperties, ContextControllerCondition originCondition, EventBean optionalTriggeringEvent, Map<String, Object> optionalTriggeringPattern, ContextInternalFilterAddendum filterAddendum) {
boolean endConditionNotification = originCondition != startCondition;
boolean startNow = startCondition instanceof ContextControllerConditionImmediate;
List<AgentInstance> agentInstancesLocksHeld = null;
this.nonDistinctLastTrigger = optionalTriggeringEvent;
if (startNow) {
factory.getFactoryContext().getServicesContext().getFilterService().acquireWriteLock();
}
try {
if (endConditionNotification) {
if (originCondition.isRunning()) {
originCondition.deactivate();
}
// indicate terminate
ContextControllerInitTermInstance instance = endConditions.remove(originCondition);
if (instance == null) {
return;
}
// For start-now (non-overlapping only) we hold the lock of the existing agent instance
// until the new one is ready.
if (startNow) {
agentInstancesLocksHeld = new ArrayList<AgentInstance>();
optionalTriggeringEvent = null; // since we are restarting, we don't want to evaluate the event twice
optionalTriggeringPattern = null;
}
activationCallback.contextPartitionTerminate(instance.getInstanceHandle(), builtinProperties, startNow, agentInstancesLocksHeld);
// remove distinct key
removeDistinctKey(instance);
// re-activate start condition if not overlapping
if (!factory.getContextDetail().isOverlapping()) {
startCondition.activate(optionalTriggeringEvent, null, 0, false);
}
factory.getFactoryContext().getStateCache().removeContextPath(factory.getFactoryContext().getOutermostContextName(), factory.getFactoryContext().getNestingLevel(), pathId, instance.getSubPathId());
}
// handle start-condition notification
if (!endConditionNotification || startNow) {
// Check if this is distinct-only and the key already exists
if (distinctContexts != null) {
boolean added = addDistinctKey(optionalTriggeringEvent);
if (!added) {
return;
}
}
// For single-instance mode, deactivate
if (!factory.getContextDetail().isOverlapping()) {
if (startCondition.isRunning()) {
startCondition.deactivate();
}
} else {
// For overlapping mode, make sure we activate again or stay activated
if (!startCondition.isRunning()) {
startCondition.activate(null, null, 0, factory.getFactoryContext().isRecoveringResilient());
}
}
currentSubpathId++;
ContextControllerCondition endEndpoint = makeEndpoint(factory.getContextDetail().getEnd(), filterAddendum, false, currentSubpathId);
MatchedEventMap matchedEventMap = getMatchedEventMap(builtinProperties);
endEndpoint.activate(null, matchedEventMap, 0, false);
long startTime = factory.getSchedulingService().getTime();
Long endTime = endEndpoint.getExpectedEndTime();
Map<String, Object> builtinProps = getBuiltinProperties(factory.getFactoryContext().getContextName(), startTime, endTime, builtinProperties);
ContextControllerInstanceHandle instanceHandle = activationCallback.contextPartitionInstantiate(null, currentSubpathId, null, this, optionalTriggeringEvent, optionalTriggeringPattern, new ContextControllerInitTermState(factory.getSchedulingService().getTime(), matchedEventMap.getMatchingEventsAsMap()), builtinProps, null, filterAddendum, factory.getFactoryContext().isRecoveringResilient(), ContextPartitionState.STARTED);
endConditions.put(endEndpoint, new ContextControllerInitTermInstance(instanceHandle, builtinProperties, startTime, endTime, currentSubpathId));
// install filter fault handlers, if necessary
installFilterFaultHandler(instanceHandle);
ContextControllerInitTermState state = new ContextControllerInitTermState(factory.getFactoryContext().getServicesContext().getSchedulingService().getTime(), builtinProperties);
factory.getFactoryContext().getStateCache().addContextPath(factory.getFactoryContext().getOutermostContextName(), factory.getFactoryContext().getNestingLevel(), pathId, currentSubpathId, instanceHandle.getContextPartitionOrPathId(), state, factory.getBinding());
}
} finally {
if (agentInstancesLocksHeld != null) {
for (AgentInstance agentInstance : agentInstancesLocksHeld) {
agentInstance.getAgentInstanceContext().getEpStatementAgentInstanceHandle().getStatementFilterVersion().setStmtFilterVersion(Long.MAX_VALUE);
if (agentInstance.getAgentInstanceContext().getStatementContext().getEpStatementHandle().isHasTableAccess()) {
agentInstance.getAgentInstanceContext().getTableExprEvaluatorContext().releaseAcquiredLocks();
}
agentInstance.getAgentInstanceContext().getAgentInstanceLock().releaseWriteLock();
}
}
if (startNow) {
factory.getFactoryContext().getServicesContext().getFilterService().releaseWriteLock();
}
}
}
private void installFilterFaultHandler(ContextControllerInstanceHandle instanceHandle) {
FilterFaultHandler myFaultHandler = null;
if (distinctContexts != null) {
myFaultHandler = new DistinctFilterFaultHandler(this);
} else {
if (startCondition instanceof ContextControllerConditionFilter) {
myFaultHandler = new NonDistinctFilterFaultHandler(this);
}
}
if (myFaultHandler != null && instanceHandle.getInstances() != null) {
for (AgentInstance agentInstance : instanceHandle.getInstances().getAgentInstances()) {
agentInstance.getAgentInstanceContext().getEpStatementAgentInstanceHandle().setFilterFaultHandler(myFaultHandler);
}
}
}
protected MatchedEventMap getMatchedEventMap(Map<String, Object> builtinProperties) {
Object[] props = new Object[factory.getMatchedEventMapMeta().getTagsPerIndex().length];
int count = 0;
for (String name : factory.getMatchedEventMapMeta().getTagsPerIndex()) {
props[count++] = builtinProperties.get(name);
}
return new MatchedEventMapImpl(factory.getMatchedEventMapMeta(), props);
}
protected boolean determineCurrentlyRunning(ContextControllerCondition startCondition) {
// we are not currently running if either of the endpoints is not crontab-triggered
if ((factory.getContextDetail().getStart() instanceof ContextDetailConditionCrontab) &&
((factory.getContextDetail().getEnd() instanceof ContextDetailConditionCrontab))) {
ScheduleSpec scheduleStart = ((ContextDetailConditionCrontab) factory.getContextDetail().getStart()).getSchedule();
ScheduleSpec scheduleEnd = ((ContextDetailConditionCrontab) factory.getContextDetail().getEnd()).getSchedule();
EngineImportService engineImportService = factory.getStatementContext().getEngineImportService();
long nextScheduledStartTime = ScheduleComputeHelper.computeNextOccurance(scheduleStart, factory.getTimeProvider().getTime(), engineImportService.getTimeZone(), engineImportService.getTimeAbacus());
long nextScheduledEndTime = ScheduleComputeHelper.computeNextOccurance(scheduleEnd, factory.getTimeProvider().getTime(), engineImportService.getTimeZone(), engineImportService.getTimeAbacus());
return nextScheduledStartTime >= nextScheduledEndTime;
}
if (startCondition instanceof ContextControllerConditionTimePeriod) {
ContextControllerConditionTimePeriod condition = (ContextControllerConditionTimePeriod) startCondition;
Long endTime = condition.getExpectedEndTime();
if (endTime != null && endTime <= 0) {
return true;
}
}
return startCondition instanceof ContextControllerConditionImmediate;
}
public ContextControllerFactory getFactory() {
return factory;
}
public int getPathId() {
return pathId;
}
public void deactivate() {
if (startCondition != null) {
if (startCondition.isRunning()) {
startCondition.deactivate();
}
}
for (Map.Entry<ContextControllerCondition, ContextControllerInitTermInstance> entry : endConditions.entrySet()) {
if (entry.getKey().isRunning()) {
entry.getKey().deactivate();
}
}
endConditions.clear();
factory.getFactoryContext().getStateCache().removeContextParentPath(factory.getFactoryContext().getOutermostContextName(), factory.getFactoryContext().getNestingLevel(), pathId);
}
public static Map<String, Object> getBuiltinProperties(String contextName, long startTime, Long endTime, Map<String, Object> startEndpointData) {
Map<String, Object> props = new HashMap<String, Object>();
props.put(ContextPropertyEventType.PROP_CTX_NAME, contextName);
props.put(ContextPropertyEventType.PROP_CTX_STARTTIME, startTime);
props.put(ContextPropertyEventType.PROP_CTX_ENDTIME, endTime);
props.putAll(startEndpointData);
return props;
}
private void initializeFromState(EventBean optionalTriggeringEvent,
Map<String, Object> optionalTriggeringPattern,
ContextInternalFilterAddendum filterAddendum,
ContextControllerState controllerState,
int pathIdToUse,
AgentInstanceSelector agentInstanceSelector,
boolean loadingExistingState) {
TreeMap<ContextStatePathKey, ContextStatePathValue> states = controllerState.getStates();
NavigableMap<ContextStatePathKey, ContextStatePathValue> childContexts = ContextControllerStateUtil.getChildContexts(factory.getFactoryContext(), pathIdToUse, states);
EventAdapterService eventAdapterService = factory.getFactoryContext().getServicesContext().getEventAdapterService();
int maxSubpathId = Integer.MIN_VALUE;
for (Map.Entry<ContextStatePathKey, ContextStatePathValue> entry : childContexts.entrySet()) {
ContextControllerInitTermState state = (ContextControllerInitTermState) factory.getBinding().byteArrayToObject(entry.getValue().getBlob(), eventAdapterService);
if (distinctContexts != null) {
ContextControllerConditionFilter filter = (ContextControllerConditionFilter) startCondition;
EventBean event = (EventBean) state.getPatternData().get(filter.getEndpointFilterSpec().getOptionalFilterAsName());
addDistinctKey(event);
}
if (controllerState.isImported()) {
Map.Entry<ContextControllerCondition, ContextControllerInitTermInstance> existing = null;
for (Map.Entry<ContextControllerCondition, ContextControllerInitTermInstance> entryExisting : endConditions.entrySet()) {
if (compare(state.getStartTime(), state.getPatternData(), null,
entryExisting.getValue().getStartTime(), entryExisting.getValue().getStartProperties(), null)) {
existing = entryExisting;
break;
}
}
if (existing != null) {
ContextControllerInstanceHandle existingHandle = existing.getValue().getInstanceHandle();
if (existingHandle != null) {
activationCallback.contextPartitionNavigate(existingHandle, this, controllerState, entry.getValue().getOptionalContextPartitionId(), filterAddendum, agentInstanceSelector, entry.getValue().getBlob(), loadingExistingState);
continue;
}
}
}
ContextControllerCondition endEndpoint = makeEndpoint(factory.getContextDetail().getEnd(), filterAddendum, false, entry.getKey().getSubPath());
long timeOffset = factory.getFactoryContext().getServicesContext().getSchedulingService().getTime() - state.getStartTime();
endEndpoint.activate(optionalTriggeringEvent, null, timeOffset, factory.getFactoryContext().isRecoveringResilient());
long startTime = state.getStartTime();
Long endTime = endEndpoint.getExpectedEndTime();
Map<String, Object> builtinProps = getBuiltinProperties(factory.getFactoryContext().getContextName(), startTime, endTime, state.getPatternData());
int contextPartitionId = entry.getValue().getOptionalContextPartitionId();
int assignedSubPathId = !controllerState.isImported() ? entry.getKey().getSubPath() : ++currentSubpathId;
ContextControllerInstanceHandle instanceHandle = activationCallback.contextPartitionInstantiate(contextPartitionId, assignedSubPathId, entry.getKey().getSubPath(), this, optionalTriggeringEvent, optionalTriggeringPattern, null, builtinProps, controllerState, filterAddendum, loadingExistingState || factory.getFactoryContext().isRecoveringResilient(), entry.getValue().getState());
endConditions.put(endEndpoint, new ContextControllerInitTermInstance(instanceHandle, state.getPatternData(), startTime, endTime, assignedSubPathId));
if (entry.getKey().getSubPath() > maxSubpathId) {
maxSubpathId = assignedSubPathId;
}
}
if (!controllerState.isImported()) {
currentSubpathId = maxSubpathId != Integer.MIN_VALUE ? maxSubpathId : 0;
}
}
public static boolean compare(long savedStartTime,
Map<String, Object> savedProperties,
Long savedEndTime,
long existingStartTime,
Map<String, Object> existingProperties,
Long existingEndTime) {
if (savedStartTime != existingStartTime) {
return false;
}
if (savedEndTime != null && existingEndTime != null && !savedEndTime.equals(existingEndTime)) {
return false;
}
for (Map.Entry<String, Object> savedEntry : savedProperties.entrySet()) {
Object existingValue = existingProperties.get(savedEntry.getKey());
Object savedValue = savedEntry.getValue();
if (savedValue == null && existingValue == null) {
continue;
}
if (savedValue == null || existingValue == null) {
return false;
}
if (existingValue.equals(savedValue)) {
continue;
}
if (existingValue instanceof EventBean && savedValue instanceof EventBean) {
if (((EventBean) existingValue).getUnderlying().equals(((EventBean) savedValue).getUnderlying())) {
continue;
}
}
return false;
}
return true;
}
private boolean addDistinctKey(EventBean optionalTriggeringEvent) {
Object key = getDistinctKey(optionalTriggeringEvent);
if (distinctContexts.containsKey(key)) {
return false;
}
distinctContexts.put(key, optionalTriggeringEvent);
return true;
}
private void removeDistinctKey(ContextControllerInitTermInstance value) {
if (distinctContexts == null) {
return;
}
ContextControllerConditionFilter filter = (ContextControllerConditionFilter) startCondition;
EventBean event = (EventBean) value.getStartProperties().get(filter.getEndpointFilterSpec().getOptionalFilterAsName());
Object key = getDistinctKey(event);
distinctContexts.remove(key);
}
private Object getDistinctKey(EventBean optionalTriggeringEvent) {
eventsPerStream[0] = optionalTriggeringEvent;
if (distinctEvaluators.length == 1) {
return distinctEvaluators[0].evaluate(eventsPerStream, true, factory.getFactoryContext().getAgentInstanceContextCreate());
}
Object[] results = new Object[distinctEvaluators.length];
int count = 0;
for (ExprEvaluator expr : distinctEvaluators) {
results[count] = expr.evaluate(eventsPerStream, true, factory.getFactoryContext().getAgentInstanceContextCreate());
count++;
}
return new MultiKeyUntyped(results);
}
private static class DistinctFilterFaultHandler implements FilterFaultHandler {
private final ContextControllerInitTerm contextControllerInitTerm;
private DistinctFilterFaultHandler(ContextControllerInitTerm contextControllerInitTerm) {
this.contextControllerInitTerm = contextControllerInitTerm;
}
public boolean handleFilterFault(EventBean theEvent, long version) {
/**
* Handle filter faults such as
* - a) App thread determines event E1 applies to CTX + CP1
* b) Timer thread destroys CP1
* c) App thread processes E1 for CTX allocating CP2, processing E1 for CP2
* d) App thread processes E1 for CP1, filter-faulting and ending up dropping the event for CP1 because of this handler
*
* - a) App thread determines event E1 applies to CTX + CP1
* b) App thread processes E1 for CTX, no action
* c) Timer thread destroys CP1
* d) App thread processes E1 for CP1, filter-faulting and ending up processing E1 into CTX because of this handler
*/
AgentInstanceContext aiCreate = contextControllerInitTerm.getFactory().getFactoryContext().getAgentInstanceContextCreate();
StatementAgentInstanceLock lock = aiCreate.getEpStatementAgentInstanceHandle().getStatementAgentInstanceLock();
lock.acquireWriteLock();
try {
Object key = contextControllerInitTerm.getDistinctKey(theEvent);
EventBean trigger = contextControllerInitTerm.distinctContexts.get(key);
// see if we find that context partition
if (trigger != null) {
// true for we have already handled this event
// false for filter fault
return trigger.equals(theEvent);
}
// not found: evaluate against context
StatementAgentInstanceUtil.evaluateEventForStatement(contextControllerInitTerm.getFactory().getFactoryContext().getServicesContext(),
theEvent, null, Collections.singletonList(new AgentInstance(null, aiCreate, null)));
return true; // we handled the event
} finally {
lock.releaseWriteLock();
}
}
}
private static class NonDistinctFilterFaultHandler implements FilterFaultHandler {
private final ContextControllerInitTerm contextControllerInitTerm;
private NonDistinctFilterFaultHandler(ContextControllerInitTerm contextControllerInitTerm) {
this.contextControllerInitTerm = contextControllerInitTerm;
}
public boolean handleFilterFault(EventBean theEvent, long version) {
/**
* Handle filter faults such as
* - a) App thread determines event E1 applies to CP1
* b) Timer thread destroys CP1
* c) App thread processes E1 for CP1, filter-faulting and ending up reprocessing the event against CTX because of this handler
*/
AgentInstanceContext aiCreate = contextControllerInitTerm.getFactory().getFactoryContext().getAgentInstanceContextCreate();
StatementAgentInstanceLock lock = aiCreate.getEpStatementAgentInstanceHandle().getStatementAgentInstanceLock();
lock.acquireWriteLock();
try {
EventBean trigger = contextControllerInitTerm.nonDistinctLastTrigger;
if (theEvent != trigger) {
StatementAgentInstanceUtil.evaluateEventForStatement(contextControllerInitTerm.getFactory().getFactoryContext().getServicesContext(),
theEvent, null, Collections.singletonList(new AgentInstance(null, aiCreate, null)));
}
return true; // we handled the event
} finally {
lock.releaseWriteLock();
}
}
}
}