/* *************************************************************************************** * 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.epl.named; import com.espertech.esper.client.ConfigurationEngineDefaults; import com.espertech.esper.client.EventBean; import com.espertech.esper.client.EventType; import com.espertech.esper.client.annotation.AuditEnum; import com.espertech.esper.core.context.util.AgentInstanceContext; import com.espertech.esper.core.context.util.EPStatementAgentInstanceHandle; import com.espertech.esper.core.service.StatementResultService; import com.espertech.esper.epl.expression.core.ExprNodeUtility; import com.espertech.esper.event.vaevent.ValueAddEventProcessor; import com.espertech.esper.timer.TimeSourceService; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; /** * This view is hooked into a named window's view chain as the last view and handles dispatching of named window * insert and remove stream results via {@link NamedWindowMgmtService} to consuming statements. */ public class NamedWindowTailView { protected final EventType eventType; protected final NamedWindowMgmtService namedWindowMgmtService; protected final NamedWindowDispatchService namedWindowDispatchService; protected final StatementResultService statementResultService; protected final ValueAddEventProcessor revisionProcessor; protected final boolean isPrioritized; protected final boolean isParentBatchWindow; protected volatile Map<EPStatementAgentInstanceHandle, List<NamedWindowConsumerView>> consumersNonContext; // handles as copy-on-write protected final TimeSourceService timeSourceService; protected final ConfigurationEngineDefaults.Threading threadingConfig; public NamedWindowTailView(EventType eventType, NamedWindowMgmtService namedWindowMgmtService, NamedWindowDispatchService namedWindowDispatchService, StatementResultService statementResultService, ValueAddEventProcessor revisionProcessor, boolean prioritized, boolean parentBatchWindow, TimeSourceService timeSourceService, ConfigurationEngineDefaults.Threading threadingConfig) { this.eventType = eventType; this.namedWindowMgmtService = namedWindowMgmtService; this.namedWindowDispatchService = namedWindowDispatchService; this.statementResultService = statementResultService; this.revisionProcessor = revisionProcessor; this.isPrioritized = prioritized; this.isParentBatchWindow = parentBatchWindow; this.consumersNonContext = NamedWindowUtil.createConsumerMap(isPrioritized); this.threadingConfig = threadingConfig; this.timeSourceService = timeSourceService; } /** * Returns true to indicate that the data window view is a batch view. * * @return true if batch view */ public boolean isParentBatchWindow() { return isParentBatchWindow; } public EventType getEventType() { return eventType; } public StatementResultService getStatementResultService() { return statementResultService; } public NamedWindowMgmtService getNamedWindowMgmtService() { return namedWindowMgmtService; } public NamedWindowDispatchService getNamedWindowDispatchService() { return namedWindowDispatchService; } public boolean isPrioritized() { return isPrioritized; } public ValueAddEventProcessor getRevisionProcessor() { return revisionProcessor; } public Map<EPStatementAgentInstanceHandle, List<NamedWindowConsumerView>> getConsumersNonContext() { return consumersNonContext; } public NamedWindowConsumerView addConsumer(NamedWindowConsumerDesc consumerDesc) { NamedWindowConsumerCallback consumerCallback = new NamedWindowConsumerCallback() { public Iterator<EventBean> getIterator() { throw new UnsupportedOperationException("Iterator not supported on named windows that have a context attached and when that context is not the same as the consuming statement's context"); } public void stopped(NamedWindowConsumerView namedWindowConsumerView) { removeConsumer(namedWindowConsumerView); } }; // Construct consumer view, allow a callback to this view to remove the consumer boolean audit = AuditEnum.STREAM.getAudit(consumerDesc.getAgentInstanceContext().getStatementContext().getAnnotations()) != null; NamedWindowConsumerView consumerView = new NamedWindowConsumerView(ExprNodeUtility.getEvaluators(consumerDesc.getFilterList()), consumerDesc.getOptPropertyEvaluator(), eventType, consumerCallback, consumerDesc.getAgentInstanceContext(), audit); // Keep a list of consumer views per statement to accomodate joins and subqueries List<NamedWindowConsumerView> viewsPerStatements = consumersNonContext.get(consumerDesc.getAgentInstanceContext().getEpStatementAgentInstanceHandle()); if (viewsPerStatements == null) { viewsPerStatements = new CopyOnWriteArrayList<NamedWindowConsumerView>(); // avoid concurrent modification as a thread may currently iterate over consumers as its dispatching // without the engine lock Map<EPStatementAgentInstanceHandle, List<NamedWindowConsumerView>> newConsumers = NamedWindowUtil.createConsumerMap(isPrioritized); newConsumers.putAll(consumersNonContext); newConsumers.put(consumerDesc.getAgentInstanceContext().getEpStatementAgentInstanceHandle(), viewsPerStatements); consumersNonContext = newConsumers; } viewsPerStatements.add(consumerView); return consumerView; } /** * Called by the consumer view to indicate it was stopped or destroyed, such that the * consumer can be deregistered and further dispatches disregard this consumer. * * @param namedWindowConsumerView is the consumer representative view */ public void removeConsumer(NamedWindowConsumerView namedWindowConsumerView) { EPStatementAgentInstanceHandle handleRemoved = null; // Find the consumer view for (Map.Entry<EPStatementAgentInstanceHandle, List<NamedWindowConsumerView>> entry : consumersNonContext.entrySet()) { boolean foundAndRemoved = entry.getValue().remove(namedWindowConsumerView); // Remove the consumer view if (foundAndRemoved && (entry.getValue().size() == 0)) { // Remove the handle if this list is now empty handleRemoved = entry.getKey(); break; } } if (handleRemoved != null) { Map<EPStatementAgentInstanceHandle, List<NamedWindowConsumerView>> newConsumers = NamedWindowUtil.createConsumerMap(isPrioritized); newConsumers.putAll(consumersNonContext); newConsumers.remove(handleRemoved); consumersNonContext = newConsumers; } } public void addDispatches(NamedWindowConsumerLatchFactory latchFactory, Map<EPStatementAgentInstanceHandle, List<NamedWindowConsumerView>> consumersInContext, NamedWindowDeltaData delta, AgentInstanceContext agentInstanceContext) { if (!consumersInContext.isEmpty()) { namedWindowDispatchService.addDispatch(latchFactory, delta, consumersInContext); } if (!consumersNonContext.isEmpty()) { namedWindowDispatchService.addDispatch(latchFactory, delta, consumersNonContext); } } public NamedWindowConsumerLatchFactory makeLatchFactory() { return new NamedWindowConsumerLatchFactory(eventType.getName(), threadingConfig.isNamedWindowConsumerDispatchPreserveOrder(), threadingConfig.getNamedWindowConsumerDispatchTimeout(), threadingConfig.getNamedWindowConsumerDispatchLocking(), timeSourceService, true); } }