/**************************************************************************************
* 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.epl.named;
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.EPStatementAgentInstanceHandle;
import com.espertech.esper.core.service.StatementResultService;
import com.espertech.esper.epl.expression.ExprNodeUtility;
import com.espertech.esper.event.vaevent.ValueAddEventProcessor;
import java.util.Iterator;
import java.util.LinkedHashMap;
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 NamedWindowService} to consuming statements.
*/
public class NamedWindowTailView
{
private final EventType eventType;
private final NamedWindowService namedWindowService;
private final StatementResultService statementResultService;
private final ValueAddEventProcessor revisionProcessor;
private final boolean isPrioritized;
private final boolean isParentBatchWindow;
private volatile Map<EPStatementAgentInstanceHandle, List<NamedWindowConsumerView>> consumersNonContext; // handles as copy-on-write
public NamedWindowTailView(EventType eventType, NamedWindowService namedWindowService, StatementResultService statementResultService, ValueAddEventProcessor revisionProcessor, boolean prioritized, boolean parentBatchWindow) {
this.eventType = eventType;
this.namedWindowService = namedWindowService;
this.statementResultService = statementResultService;
this.revisionProcessor = revisionProcessor;
isPrioritized = prioritized;
isParentBatchWindow = parentBatchWindow;
this.consumersNonContext = NamedWindowUtil.createConsumerMap(isPrioritized);
}
/**
* 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 NamedWindowService getNamedWindowService() {
return namedWindowService;
}
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;
}
}
}