/* *************************************************************************************** * 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.ContextControllerSelectorUtil; import com.espertech.esper.core.context.util.StatementAgentInstanceUtil; import com.espertech.esper.epl.spec.ContextDetailPartitionItem; import com.espertech.esper.event.EventAdapterService; import java.util.*; public class ContextControllerPartitioned implements ContextController, ContextControllerPartitionedInstanceCreateCallback { protected final int pathId; protected final ContextControllerLifecycleCallback activationCallback; protected final ContextControllerPartitionedFactoryImpl factory; protected final List<ContextControllerPartitionedFilterCallback> filterCallbacks = new ArrayList<ContextControllerPartitionedFilterCallback>(); protected final HashMap<Object, ContextControllerInstanceHandle> partitionKeys = new HashMap<Object, ContextControllerInstanceHandle>(); private ContextInternalFilterAddendum activationFilterAddendum; protected int currentSubpathId; public ContextControllerPartitioned(int pathId, ContextControllerLifecycleCallback activationCallback, ContextControllerPartitionedFactoryImpl factory) { this.pathId = pathId; this.activationCallback = activationCallback; this.factory = factory; } public void importContextPartitions(ContextControllerState state, int pathIdToUse, ContextInternalFilterAddendum filterAddendum, AgentInstanceSelector agentInstanceSelector) { initializeFromState(null, null, filterAddendum, state, pathIdToUse, agentInstanceSelector, true); } public void deletePath(ContextPartitionIdentifier identifier) { ContextPartitionIdentifierPartitioned partitioned = (ContextPartitionIdentifierPartitioned) identifier; partitionKeys.remove(getKeyObjectForLookup(partitioned.getKeys())); } public void visitSelectedPartitions(ContextPartitionSelector contextPartitionSelector, ContextPartitionVisitor visitor) { int nestingLevel = factory.getFactoryContext().getNestingLevel(); if (contextPartitionSelector instanceof ContextPartitionSelectorFiltered) { ContextPartitionSelectorFiltered filtered = (ContextPartitionSelectorFiltered) contextPartitionSelector; ContextPartitionIdentifierPartitioned identifier = new ContextPartitionIdentifierPartitioned(); for (Map.Entry<Object, ContextControllerInstanceHandle> entry : partitionKeys.entrySet()) { identifier.setContextPartitionId(entry.getValue().getContextPartitionOrPathId()); Object[] identifierOA = getKeyObjectsAccountForMultikey(entry.getKey()); identifier.setKeys(identifierOA); if (filtered.filter(identifier)) { visitor.visit(nestingLevel, pathId, factory.getBinding(), identifierOA, this, entry.getValue()); } } return; } else if (contextPartitionSelector instanceof ContextPartitionSelectorSegmented) { ContextPartitionSelectorSegmented partitioned = (ContextPartitionSelectorSegmented) contextPartitionSelector; if (partitioned.getPartitionKeys() == null || partitioned.getPartitionKeys().isEmpty()) { return; } for (Object[] keyObjects : partitioned.getPartitionKeys()) { Object key = getKeyObjectForLookup(keyObjects); ContextControllerInstanceHandle instanceHandle = partitionKeys.get(key); if (instanceHandle != null && instanceHandle.getContextPartitionOrPathId() != null) { visitor.visit(nestingLevel, pathId, factory.getBinding(), keyObjects, this, instanceHandle); } } return; } else if (contextPartitionSelector instanceof ContextPartitionSelectorById) { ContextPartitionSelectorById filtered = (ContextPartitionSelectorById) contextPartitionSelector; for (Map.Entry<Object, ContextControllerInstanceHandle> entry : partitionKeys.entrySet()) { if (filtered.getContextPartitionIds().contains(entry.getValue().getContextPartitionOrPathId())) { visitor.visit(nestingLevel, pathId, factory.getBinding(), getKeyObjectsAccountForMultikey(entry.getKey()), this, entry.getValue()); } } return; } else if (contextPartitionSelector instanceof ContextPartitionSelectorAll) { for (Map.Entry<Object, ContextControllerInstanceHandle> entry : partitionKeys.entrySet()) { visitor.visit(nestingLevel, pathId, factory.getBinding(), getKeyObjectsAccountForMultikey(entry.getKey()), this, entry.getValue()); } return; } throw ContextControllerSelectorUtil.getInvalidSelector(new Class[]{ContextPartitionSelectorSegmented.class}, contextPartitionSelector); } public void activate(EventBean optionalTriggeringEvent, Map<String, Object> optionalTriggeringPattern, ContextControllerState controllerState, ContextInternalFilterAddendum filterAddendum, Integer importPathId) { ContextControllerFactoryContext factoryContext = factory.getFactoryContext(); this.activationFilterAddendum = filterAddendum; for (ContextDetailPartitionItem item : factory.getSegmentedSpec().getItems()) { ContextControllerPartitionedFilterCallback callback = new ContextControllerPartitionedFilterCallback(factoryContext.getServicesContext(), factoryContext.getAgentInstanceContextCreate(), item, this, filterAddendum); filterCallbacks.add(callback); if (optionalTriggeringEvent != null) { boolean match = StatementAgentInstanceUtil.evaluateFilterForStatement(factoryContext.getServicesContext(), optionalTriggeringEvent, factoryContext.getAgentInstanceContextCreate(), callback.getFilterHandle()); if (match) { callback.matchFound(optionalTriggeringEvent, null); } } } if (factoryContext.getNestingLevel() == 1) { controllerState = ContextControllerStateUtil.getRecoveryStates(factory.getFactoryContext().getStateCache(), factoryContext.getOutermostContextName()); } if (controllerState == null) { return; } int pathIdToUse = importPathId != null ? importPathId : pathId; initializeFromState(optionalTriggeringEvent, optionalTriggeringPattern, filterAddendum, controllerState, pathIdToUse, null, false); } public ContextControllerFactory getFactory() { return factory; } public int getPathId() { return pathId; } public synchronized void deactivate() { ContextControllerFactoryContext factoryContext = factory.getFactoryContext(); for (ContextControllerPartitionedFilterCallback callback : filterCallbacks) { callback.destroy(factoryContext.getServicesContext().getFilterService()); } partitionKeys.clear(); filterCallbacks.clear(); factory.getFactoryContext().getStateCache().removeContextParentPath(factoryContext.getOutermostContextName(), factoryContext.getNestingLevel(), pathId); } public synchronized void create(Object key, EventBean theEvent) { boolean exists = partitionKeys.containsKey(key); if (exists) { return; } currentSubpathId++; // determine properties available for querying ContextControllerFactoryContext factoryContext = factory.getFactoryContext(); Map<String, Object> props = ContextPropertyEventType.getPartitionBean(factoryContext.getContextName(), 0, key, factory.getSegmentedSpec().getItems().get(0).getPropertyNames()); // merge filter addendum, if any ContextInternalFilterAddendum filterAddendum = activationFilterAddendum; if (factory.hasFiltersSpecsNestedContexts()) { filterAddendum = activationFilterAddendum != null ? activationFilterAddendum.deepCopy() : new ContextInternalFilterAddendum(); factory.populateContextInternalFilterAddendums(filterAddendum, key); } ContextControllerInstanceHandle handle = activationCallback.contextPartitionInstantiate(null, currentSubpathId, null, this, theEvent, null, key, props, null, filterAddendum, false, ContextPartitionState.STARTED); partitionKeys.put(key, handle); // update the filter version for this handle long filterVersion = factoryContext.getServicesContext().getFilterService().getFiltersVersion(); factory.getFactoryContext().getAgentInstanceContextCreate().getEpStatementAgentInstanceHandle().getStatementFilterVersion().setStmtFilterVersion(filterVersion); Object[] keyObjectSaved = getKeyObjectsAccountForMultikey(key); factory.getFactoryContext().getStateCache().addContextPath(factoryContext.getOutermostContextName(), factoryContext.getNestingLevel(), pathId, currentSubpathId, handle.getContextPartitionOrPathId(), keyObjectSaved, factory.getBinding()); } private Object[] getKeyObjectsAccountForMultikey(Object key) { if (key instanceof MultiKeyUntyped) { return ((MultiKeyUntyped) key).getKeys(); } else { return new Object[]{key}; } } private Object getKeyObjectForLookup(Object[] keyObjects) { if (keyObjects.length > 1) { return new MultiKeyUntyped(keyObjects); } else { return keyObjects[0]; } } private void initializeFromState(EventBean optionalTriggeringEvent, Map<String, Object> optionalTriggeringPattern, ContextInternalFilterAddendum filterAddendum, ContextControllerState controllerState, int pathIdToUse, AgentInstanceSelector agentInstanceSelector, boolean loadingExistingState) { ContextControllerFactoryContext factoryContext = factory.getFactoryContext(); TreeMap<ContextStatePathKey, ContextStatePathValue> states = controllerState.getStates(); // restart if there are states int maxSubpathId = Integer.MIN_VALUE; NavigableMap<ContextStatePathKey, ContextStatePathValue> childContexts = ContextControllerStateUtil.getChildContexts(factoryContext, pathIdToUse, states); EventAdapterService eventAdapterService = factory.getFactoryContext().getServicesContext().getEventAdapterService(); for (Map.Entry<ContextStatePathKey, ContextStatePathValue> entry : childContexts.entrySet()) { Object[] keys = (Object[]) factory.getBinding().byteArrayToObject(entry.getValue().getBlob(), eventAdapterService); Object mapKey = getKeyObjectForLookup(keys); // merge filter addendum, if any ContextInternalFilterAddendum myFilterAddendum = activationFilterAddendum; if (factory.hasFiltersSpecsNestedContexts()) { filterAddendum = activationFilterAddendum != null ? activationFilterAddendum.deepCopy() : new ContextInternalFilterAddendum(); factory.populateContextInternalFilterAddendums(filterAddendum, mapKey); } // check if exists already if (controllerState.isImported()) { ContextControllerInstanceHandle existingHandle = partitionKeys.get(mapKey); if (existingHandle != null) { activationCallback.contextPartitionNavigate(existingHandle, this, controllerState, entry.getValue().getOptionalContextPartitionId(), myFilterAddendum, agentInstanceSelector, entry.getValue().getBlob(), loadingExistingState); continue; } } Map<String, Object> props = ContextPropertyEventType.getPartitionBean(factoryContext.getContextName(), 0, mapKey, factory.getSegmentedSpec().getItems().get(0).getPropertyNames()); int assignedSubpathId = !controllerState.isImported() ? entry.getKey().getSubPath() : ++currentSubpathId; ContextControllerInstanceHandle handle = activationCallback.contextPartitionInstantiate(entry.getValue().getOptionalContextPartitionId(), assignedSubpathId, entry.getKey().getSubPath(), this, optionalTriggeringEvent, optionalTriggeringPattern, mapKey, props, controllerState, myFilterAddendum, loadingExistingState || factoryContext.isRecoveringResilient(), entry.getValue().getState()); partitionKeys.put(mapKey, handle); if (entry.getKey().getSubPath() > maxSubpathId) { maxSubpathId = assignedSubpathId; } } if (!controllerState.isImported()) { currentSubpathId = maxSubpathId != Integer.MIN_VALUE ? maxSubpathId : 0; } } }