/* * ************************************************************************************* * 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.mgr; import com.espertech.esper.client.EventBean; import com.espertech.esper.client.EventType; import com.espertech.esper.client.SafeIterator; import com.espertech.esper.client.context.ContextPartitionSelector; import com.espertech.esper.client.context.ContextPartitionSelectorAll; import com.espertech.esper.client.context.ContextPartitionSelectorById; import com.espertech.esper.core.context.factory.StatementAgentInstanceFactoryResult; import com.espertech.esper.core.context.stmt.StatementAIResourceRegistryFactory; import com.espertech.esper.core.context.util.ContextDescriptor; import com.espertech.esper.core.context.util.ContextIteratorHandler; import com.espertech.esper.core.context.util.StatementAgentInstanceUtil; import com.espertech.esper.core.service.EPServicesContext; import com.espertech.esper.epl.expression.ExprValidationException; import com.espertech.esper.event.MappedEventBean; import com.espertech.esper.filter.FilterFaultHandler; import com.espertech.esper.filter.FilterSpecCompiled; import com.espertech.esper.filter.FilterSpecLookupable; import com.espertech.esper.filter.FilterValueSetParam; import com.espertech.esper.type.NumberSetParameter; import java.util.*; public class ContextManagerImpl implements ContextManager, ContextControllerLifecycleCallback, ContextIteratorHandler, FilterFaultHandler { private final String contextName; private final EPServicesContext servicesContext; private final ContextControllerFactory factory; private final Map<String, ContextControllerStatementDesc> statements = new LinkedHashMap<String, ContextControllerStatementDesc>(); // retain order of statement creation private final ContextDescriptor contextDescriptor; private final Map<Integer, ContextControllerTreeAgentInstanceList> agentInstances = new LinkedHashMap<Integer, ContextControllerTreeAgentInstanceList>(); /** * The single root context. * This represents the context declared first. */ private ContextController rootContext; private final ContextPartitionIdManager contextPartitionIdManager; public ContextManagerImpl(ContextControllerFactoryServiceContext factoryServiceContext) throws ExprValidationException { this.contextName = factoryServiceContext.getContextName(); this.servicesContext = factoryServiceContext.getServicesContext(); this.factory = factoryServiceContext.getAgentInstanceContextCreate().getStatementContext().getContextControllerFactoryService().getFactory(factoryServiceContext)[0]; this.rootContext = factory.createNoCallback(0, this); // single instance: created here and activated/deactivated later this.contextPartitionIdManager = factoryServiceContext.getAgentInstanceContextCreate().getStatementContext().getContextControllerFactoryService().allocatePartitionIdMgr(contextName, factoryServiceContext.getAgentInstanceContextCreate().getStatementContext().getStatementId()); StatementAIResourceRegistryFactory resourceRegistryFactory = factory.getStatementAIResourceRegistryFactory(); Map<String, Object> contextProps = factory.getContextBuiltinProps(); EventType contextPropsType = servicesContext.getEventAdapterService().createAnonymousMapType(contextName, contextProps); ContextPropertyRegistryImpl registry = new ContextPropertyRegistryImpl(factory.getContextDetailPartitionItems(), contextPropsType); contextDescriptor = new ContextDescriptor(contextName, factory.isSingleInstanceContext(), registry, resourceRegistryFactory, this, factory.getContextDetail()); } public void deactivateContextPartitions(Set<Integer> agentInstanceIds) { for (Integer agentInstanceId : agentInstanceIds) { ContextControllerTreeAgentInstanceList list = agentInstances.get(agentInstanceId); StatementAgentInstanceUtil.stopAgentInstances(list.getAgentInstances(), null, servicesContext, false); } } public Map<String, ContextControllerStatementDesc> getStatements() { return statements; } public ContextDescriptor getContextDescriptor() { return contextDescriptor; } public void addStatement(ContextControllerStatementBase statement, boolean isRecoveringResilient) throws ExprValidationException { // validation down the hierarchy ContextControllerStatementCtxCache caches = factory.validateStatement(statement); // add statement ContextControllerStatementDesc desc = new ContextControllerStatementDesc(statement, new ContextControllerStatementCtxCache[]{caches}); statements.put(statement.getStatementContext().getStatementId(), desc); // activate if this is the first statement if (statements.size() == 1) { activate(); // this may itself trigger a callback } // activate statement in respect to existing context partitions else { for (Map.Entry<Integer, ContextControllerTreeAgentInstanceList> entry : agentInstances.entrySet()) { AgentInstance agentInstance = startStatement(entry.getKey(), desc, rootContext, entry.getValue().getInitPartitionKey(), entry.getValue().getInitContextProperties(), isRecoveringResilient); entry.getValue().getAgentInstances().add(agentInstance); } } } public synchronized void stopStatement(String statementName, String statementId) { destroyStatement(statementName, statementId); } public synchronized void destroyStatement(String statementName, String statementId) { if (!statements.containsKey(statementId)) { return; } if (statements.size() == 1) { safeDestroy(); } else { removeStatement(statementId); } } public void safeDestroy() { if (rootContext != null) { // deactivate rootContext.deactivate(); factory.getStateCache().removeContext(contextName); for (Map.Entry<Integer, ContextControllerTreeAgentInstanceList> entryCP : agentInstances.entrySet()) { StatementAgentInstanceUtil.stopAgentInstances(entryCP.getValue().getAgentInstances(), null, servicesContext, true); } agentInstances.clear(); contextPartitionIdManager.clear(); statements.clear(); } } public synchronized ContextControllerInstanceHandle contextPartitionInstantiate( Integer optionalContextPartitionId, int pathId, ContextController originator, EventBean optionalTriggeringEvent, Map<String, Object> optionalTriggeringPattern, Object partitionKey, Map<String, Object> contextProperties, ContextControllerState states, ContextInternalFilterAddendum filterAddendum, boolean isRecoveringResilient) { // assign context id int assignedContextId; if (optionalContextPartitionId != null) { assignedContextId = optionalContextPartitionId; contextPartitionIdManager.addExisting(optionalContextPartitionId); } else { assignedContextId = contextPartitionIdManager.allocateId(); } // handle leaf creation List<AgentInstance> newInstances = new ArrayList<AgentInstance>(); for (Map.Entry<String, ContextControllerStatementDesc> statementEntry : statements.entrySet()) { ContextControllerStatementDesc statementDesc = statementEntry.getValue(); AgentInstance instance = startStatement(assignedContextId, statementDesc, originator, partitionKey, contextProperties, isRecoveringResilient); newInstances.add(instance); } // for all new contexts: evaluate this event for this statement if (optionalTriggeringEvent != null || optionalTriggeringPattern != null) { for (AgentInstance context : newInstances) { StatementAgentInstanceUtil.evaluateEventForStatement(servicesContext, optionalTriggeringEvent, optionalTriggeringPattern, context.getAgentInstanceContext()); } } // save leaf long filterVersion = servicesContext.getFilterService().getFiltersVersion(); agentInstances.put(assignedContextId, new ContextControllerTreeAgentInstanceList(filterVersion, partitionKey, contextProperties, newInstances)); // update the filter version for this handle factory.getFactoryContext().getAgentInstanceContextCreate().getEpStatementAgentInstanceHandle().getStatementFilterVersion().setStmtFilterVersion(filterVersion); return new ContextNestedHandleImpl(assignedContextId); } public synchronized void contextPartitionTerminate(ContextControllerInstanceHandle contextNestedHandle, Map<String, Object> terminationProperties) { ContextNestedHandleImpl handle = (ContextNestedHandleImpl) contextNestedHandle; ContextControllerTreeAgentInstanceList entry = agentInstances.remove(handle.getContextPartitionOrPathId()); if (entry != null) { StatementAgentInstanceUtil.stopAgentInstances(entry.getAgentInstances(), terminationProperties, servicesContext, false); entry.getAgentInstances().clear(); contextPartitionIdManager.removeId(contextNestedHandle.getContextPartitionOrPathId()); } } public void setContextPartitionRange(List<NumberSetParameter> partitionRanges) { rootContext.setContextPartitionRange(partitionRanges); } public FilterSpecLookupable getFilterLookupable(EventType eventType) { return factory.getFilterLookupable(eventType); } public synchronized Iterator<EventBean> iterator(String statementId) { AgentInstance[] instances = getAgentInstancesForStmt(statementId); return new AgentInstanceArrayIterator(instances); } public synchronized SafeIterator<EventBean> safeIterator(String statementId) { AgentInstance[] instances = getAgentInstancesForStmt(statementId); return new AgentInstanceArraySafeIterator(instances); } public synchronized Iterator<EventBean> iterator(String statementId, ContextPartitionSelector selector) { AgentInstance[] instances = getAgentInstancesForStmt(statementId, selector); return new AgentInstanceArrayIterator(instances); } public synchronized SafeIterator<EventBean> safeIterator(String statementId, ContextPartitionSelector selector) { AgentInstance[] instances = getAgentInstancesForStmt(statementId, selector); return new AgentInstanceArraySafeIterator(instances); } public Collection<Integer> getAgentInstanceIds(ContextPartitionSelector contextPartitionSelector) { return getAgentInstancesForSelector(contextPartitionSelector); } public synchronized void handleFilterFault(EventBean theEvent, long version) { StatementAgentInstanceUtil.handleFilterFault(theEvent, version, servicesContext, agentInstances); } private void activate() { rootContext.activate(null, null, null, null); } private AgentInstance[] getAgentInstancesForStmt(String statementId, ContextPartitionSelector selector) { Collection<Integer> agentInstanceIds = getAgentInstanceIds(selector); if (agentInstanceIds == null || agentInstanceIds.isEmpty()) { return new AgentInstance[0]; } List<AgentInstance> instances = new ArrayList<AgentInstance>(agentInstanceIds.size()); for (Integer agentInstanceId : agentInstanceIds) { ContextControllerTreeAgentInstanceList instancesList = agentInstances.get(agentInstanceId); if (instancesList != null) { Iterator<AgentInstance> instanceIt = instancesList.getAgentInstances().iterator(); for (; instanceIt.hasNext(); ) { AgentInstance instance = instanceIt.next(); if (instance.getAgentInstanceContext().getStatementContext().getStatementId().equals(statementId)) { instances.add(instance); } } } } return instances.toArray(new AgentInstance[instances.size()]); } private Collection<Integer> getAgentInstancesForSelector(ContextPartitionSelector selector) { Collection<Integer> agentInstanceIds; if (selector instanceof ContextPartitionSelectorById) { ContextPartitionSelectorById byId = (ContextPartitionSelectorById) selector; Set<Integer> ids = byId.getContextPartitionIds(); if (ids == null || ids.isEmpty()) { return Collections.emptyList(); } agentInstanceIds = new ArrayList<Integer>(ids); } else if (selector instanceof ContextPartitionSelectorAll) { agentInstanceIds = new ArrayList<Integer>(agentInstances.keySet()); } else { agentInstanceIds = rootContext.getSelectedContextPartitionPathIds(selector); if (agentInstanceIds == null || agentInstanceIds.isEmpty()) { return Collections.emptyList(); } } return agentInstanceIds; } private AgentInstance[] getAgentInstancesForStmt(String statementId) { List<AgentInstance> instances = new ArrayList<AgentInstance>(); for (Map.Entry<Integer, ContextControllerTreeAgentInstanceList> contextPartitionEntry : agentInstances.entrySet()) { Iterator<AgentInstance> instanceIt = contextPartitionEntry.getValue().getAgentInstances().iterator(); for (; instanceIt.hasNext(); ) { AgentInstance instance = instanceIt.next(); if (instance.getAgentInstanceContext().getStatementContext().getStatementId().equals(statementId)) { instances.add(instance); } } } return instances.toArray(new AgentInstance[instances.size()]); } private void removeStatement(String statementId) { ContextControllerStatementDesc statementDesc = statements.get(statementId); if (statementDesc == null) { return; } for (Map.Entry<Integer, ContextControllerTreeAgentInstanceList> contextPartitionEntry : agentInstances.entrySet()) { Iterator<AgentInstance> instanceIt = contextPartitionEntry.getValue().getAgentInstances().iterator(); for (; instanceIt.hasNext(); ) { AgentInstance instance = instanceIt.next(); if (!instance.getAgentInstanceContext().getStatementContext().getStatementId().equals(statementId)) { continue; } StatementAgentInstanceUtil.stop(instance.getStopCallback(), instance.getAgentInstanceContext(), instance.getFinalView(), servicesContext, true); instanceIt.remove(); } } statements.remove(statementId); } private AgentInstance startStatement(int contextId, ContextControllerStatementDesc statementDesc, ContextController originator, Object partitionKey, Map<String, Object> contextProperties, boolean isRecoveringResilient) { // build filters IdentityHashMap<FilterSpecCompiled, List<FilterValueSetParam>> filterAddendum = new IdentityHashMap<FilterSpecCompiled, List<FilterValueSetParam>>(); originator.getFactory().populateFilterAddendums(filterAddendum, statementDesc, partitionKey, contextId); AgentInstanceFilterProxy proxy = new AgentInstanceFilterProxyImpl(filterAddendum); // build built-in context properties contextProperties.put(ContextPropertyEventType.PROP_CTX_NAME, contextName); contextProperties.put(ContextPropertyEventType.PROP_CTX_ID, contextId); MappedEventBean contextBean = (MappedEventBean) servicesContext.getEventAdapterService().adapterForTypedMap(contextProperties, contextDescriptor.getContextPropertyRegistry().getContextEventType()); // activate StatementAgentInstanceFactoryResult result = StatementAgentInstanceUtil.start(servicesContext, statementDesc.getStatement(), false, contextId, contextBean, proxy, isRecoveringResilient); // save only instance data return new AgentInstance(result.getStopCallback(), result.getAgentInstanceContext(), result.getFinalView()); } public static class ContextNestedHandleImpl implements ContextControllerInstanceHandle { private int contextPartitionId; public ContextNestedHandleImpl(int contextPartitionId) { this.contextPartitionId = contextPartitionId; } public Integer getContextPartitionOrPathId() { return contextPartitionId; } } }