/* *************************************************************************************** * 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.core.context.util.ContextControllerSelectorUtil; import com.espertech.esper.core.context.util.StatementAgentInstanceUtil; import com.espertech.esper.epl.spec.ContextDetailHashItem; import java.util.*; public class ContextControllerHash implements ContextController, ContextControllerHashedInstanceCallback { protected final int pathId; protected final ContextControllerLifecycleCallback activationCallback; protected final ContextControllerHashFactoryImpl factory; protected final List<ContextControllerHashedFilterCallback> filterCallbacks = new ArrayList<ContextControllerHashedFilterCallback>(); protected final Map<Integer, ContextControllerInstanceHandle> partitionKeys = new LinkedHashMap<Integer, ContextControllerInstanceHandle>(); protected ContextInternalFilterAddendum activationFilterAddendum; protected int currentSubpathId; public ContextControllerHash(int pathId, ContextControllerLifecycleCallback activationCallback, ContextControllerHashFactoryImpl factory) { this.pathId = pathId; this.activationCallback = activationCallback; this.factory = factory; } public void importContextPartitions(ContextControllerState state, int pathIdToUse, ContextInternalFilterAddendum filterAddendum, AgentInstanceSelector agentInstanceSelector) { initializeFromState(null, null, state, pathIdToUse, agentInstanceSelector, true); } public void deletePath(ContextPartitionIdentifier identifier) { ContextPartitionIdentifierHash hash = (ContextPartitionIdentifierHash) identifier; partitionKeys.remove(hash.getHash()); } public void visitSelectedPartitions(ContextPartitionSelector contextPartitionSelector, ContextPartitionVisitor visitor) { int nestingLevel = factory.getFactoryContext().getNestingLevel(); if (contextPartitionSelector instanceof ContextPartitionSelectorHash) { ContextPartitionSelectorHash hash = (ContextPartitionSelectorHash) contextPartitionSelector; if (hash.getHashes() == null || hash.getHashes().isEmpty()) { return; } for (int hashCode : hash.getHashes()) { ContextControllerInstanceHandle handle = partitionKeys.get(hashCode); if (handle != null) { visitor.visit(nestingLevel, pathId, factory.getBinding(), hashCode, this, handle); } } return; } if (contextPartitionSelector instanceof ContextPartitionSelectorFiltered) { ContextPartitionSelectorFiltered filter = (ContextPartitionSelectorFiltered) contextPartitionSelector; ContextPartitionIdentifierHash identifierHash = new ContextPartitionIdentifierHash(); for (Map.Entry<Integer, ContextControllerInstanceHandle> entry : partitionKeys.entrySet()) { identifierHash.setHash(entry.getKey()); identifierHash.setContextPartitionId(entry.getValue().getContextPartitionOrPathId()); if (filter.filter(identifierHash)) { visitor.visit(nestingLevel, pathId, factory.getBinding(), entry.getKey(), this, entry.getValue()); } } return; } if (contextPartitionSelector instanceof ContextPartitionSelectorAll) { for (Map.Entry<Integer, ContextControllerInstanceHandle> entry : partitionKeys.entrySet()) { visitor.visit(nestingLevel, pathId, factory.getBinding(), entry.getKey(), this, entry.getValue()); } return; } if (contextPartitionSelector instanceof ContextPartitionSelectorById) { ContextPartitionSelectorById byId = (ContextPartitionSelectorById) contextPartitionSelector; for (Map.Entry<Integer, ContextControllerInstanceHandle> entry : partitionKeys.entrySet()) { int cpid = entry.getValue().getContextPartitionOrPathId(); if (byId.getContextPartitionIds().contains(cpid)) { visitor.visit(nestingLevel, pathId, factory.getBinding(), entry.getKey(), this, entry.getValue()); } } return; } throw ContextControllerSelectorUtil.getInvalidSelector(new Class[]{ContextPartitionSelectorHash.class}, contextPartitionSelector); } public void activate(EventBean optionalTriggeringEvent, Map<String, Object> optionalTriggeringPattern, ContextControllerState controllerState, ContextInternalFilterAddendum activationFilterAddendum, Integer importPathId) { ContextControllerFactoryContext factoryContext = factory.getFactoryContext(); this.activationFilterAddendum = activationFilterAddendum; if (factoryContext.getNestingLevel() == 1) { controllerState = ContextControllerStateUtil.getRecoveryStates(factory.getFactoryContext().getStateCache(), factoryContext.getOutermostContextName()); } if (controllerState == null) { // handle preallocate if (factory.getHashedSpec().isPreallocate()) { for (int i = 0; i < factory.getHashedSpec().getGranularity(); i++) { Map<String, Object> properties = ContextPropertyEventType.getHashBean(factoryContext.getContextName(), i); currentSubpathId++; // merge filter addendum, if any ContextInternalFilterAddendum filterAddendumToUse = activationFilterAddendum; if (factory.hasFiltersSpecsNestedContexts()) { filterAddendumToUse = activationFilterAddendum != null ? activationFilterAddendum.deepCopy() : new ContextInternalFilterAddendum(); factory.populateContextInternalFilterAddendums(filterAddendumToUse, i); } ContextControllerInstanceHandle handle = activationCallback.contextPartitionInstantiate(null, currentSubpathId, null, this, optionalTriggeringEvent, null, i, properties, controllerState, filterAddendumToUse, factory.getFactoryContext().isRecoveringResilient(), ContextPartitionState.STARTED); partitionKeys.put(i, handle); factory.getFactoryContext().getStateCache().addContextPath(factory.getFactoryContext().getOutermostContextName(), factory.getFactoryContext().getNestingLevel(), pathId, currentSubpathId, handle.getContextPartitionOrPathId(), i, factory.getBinding()); } return; } // start filters if not preallocated activateFilters(optionalTriggeringEvent); return; } // initialize from existing state int pathIdToUse = importPathId != null ? importPathId : pathId; initializeFromState(optionalTriggeringEvent, optionalTriggeringPattern, controllerState, pathIdToUse, null, false); // activate filters if (!factory.getHashedSpec().isPreallocate()) { activateFilters(null); } } protected void activateFilters(EventBean optionalTriggeringEvent) { ContextControllerFactoryContext factoryContext = factory.getFactoryContext(); for (ContextDetailHashItem item : factory.getHashedSpec().getItems()) { ContextControllerHashedFilterCallback callback = new ContextControllerHashedFilterCallback(factoryContext.getServicesContext(), factoryContext.getAgentInstanceContextCreate(), item, this, activationFilterAddendum); filterCallbacks.add(callback); if (optionalTriggeringEvent != null) { boolean match = StatementAgentInstanceUtil.evaluateFilterForStatement(factoryContext.getServicesContext(), optionalTriggeringEvent, factoryContext.getAgentInstanceContextCreate(), callback.getFilterHandle()); if (match) { callback.matchFound(optionalTriggeringEvent, null); } } } } public synchronized void create(int id, EventBean theEvent) { ContextControllerFactoryContext factoryContext = factory.getFactoryContext(); if (partitionKeys.containsKey(id)) { return; } Map<String, Object> properties = ContextPropertyEventType.getHashBean(factoryContext.getContextName(), id); currentSubpathId++; // merge filter addendum, if any ContextInternalFilterAddendum filterAddendumToUse = activationFilterAddendum; if (factory.hasFiltersSpecsNestedContexts()) { filterAddendumToUse = activationFilterAddendum != null ? activationFilterAddendum.deepCopy() : new ContextInternalFilterAddendum(); factory.populateContextInternalFilterAddendums(filterAddendumToUse, id); } ContextControllerInstanceHandle handle = activationCallback.contextPartitionInstantiate(null, currentSubpathId, null, this, theEvent, null, id, properties, null, filterAddendumToUse, factory.getFactoryContext().isRecoveringResilient(), ContextPartitionState.STARTED); partitionKeys.put(id, handle); factory.getFactoryContext().getStateCache().addContextPath(factoryContext.getOutermostContextName(), factoryContext.getNestingLevel(), pathId, currentSubpathId, handle.getContextPartitionOrPathId(), id, factory.getBinding()); // update the filter version for this handle long filterVersion = factoryContext.getServicesContext().getFilterService().getFiltersVersion(); factory.getFactoryContext().getAgentInstanceContextCreate().getEpStatementAgentInstanceHandle().getStatementFilterVersion().setStmtFilterVersion(filterVersion); } public ContextControllerFactory getFactory() { return factory; } public int getPathId() { return pathId; } public void deactivate() { ContextControllerFactoryContext factoryContext = factory.getFactoryContext(); for (ContextControllerHashedFilterCallback callback : filterCallbacks) { callback.destroy(factoryContext.getServicesContext().getFilterService()); } partitionKeys.clear(); filterCallbacks.clear(); factory.getFactoryContext().getStateCache().removeContextParentPath(factoryContext.getOutermostContextName(), factoryContext.getNestingLevel(), pathId); } private void initializeFromState(EventBean optionalTriggeringEvent, Map<String, Object> optionalTriggeringPattern, ContextControllerState controllerState, int pathIdToUse, AgentInstanceSelector agentInstanceSelector, boolean loadingExistingState) { ContextControllerFactoryContext factoryContext = factory.getFactoryContext(); TreeMap<ContextStatePathKey, ContextStatePathValue> states = controllerState.getStates(); NavigableMap<ContextStatePathKey, ContextStatePathValue> childContexts = ContextControllerStateUtil.getChildContexts(factoryContext, pathIdToUse, states); int maxSubpathId = Integer.MIN_VALUE; for (Map.Entry<ContextStatePathKey, ContextStatePathValue> entry : childContexts.entrySet()) { Integer hashAlgoGeneratedId = (Integer) factory.getBinding().byteArrayToObject(entry.getValue().getBlob(), null); // merge filter addendum, if any ContextInternalFilterAddendum filterAddendumToUse = activationFilterAddendum; if (factory.hasFiltersSpecsNestedContexts()) { filterAddendumToUse = activationFilterAddendum != null ? activationFilterAddendum.deepCopy() : new ContextInternalFilterAddendum(); factory.populateContextInternalFilterAddendums(filterAddendumToUse, hashAlgoGeneratedId); } // check if exists already if (controllerState.isImported()) { ContextControllerInstanceHandle existingHandle = partitionKeys.get(hashAlgoGeneratedId); if (existingHandle != null) { activationCallback.contextPartitionNavigate(existingHandle, this, controllerState, entry.getValue().getOptionalContextPartitionId(), filterAddendumToUse, agentInstanceSelector, entry.getValue().getBlob(), loadingExistingState); continue; } } Map<String, Object> properties = ContextPropertyEventType.getHashBean(factoryContext.getContextName(), hashAlgoGeneratedId); int assignedSubPathId = !controllerState.isImported() ? entry.getKey().getSubPath() : ++currentSubpathId; ContextControllerInstanceHandle handle = activationCallback.contextPartitionInstantiate(entry.getValue().getOptionalContextPartitionId(), assignedSubPathId, entry.getKey().getSubPath(), this, optionalTriggeringEvent, optionalTriggeringPattern, hashAlgoGeneratedId, properties, controllerState, filterAddendumToUse, loadingExistingState || factoryContext.isRecoveringResilient(), entry.getValue().getState()); partitionKeys.put(hashAlgoGeneratedId, handle); if (entry.getKey().getSubPath() > maxSubpathId) { maxSubpathId = assignedSubPathId; } } if (!controllerState.isImported()) { currentSubpathId = maxSubpathId != Integer.MIN_VALUE ? maxSubpathId : 0; } } }