/************************************************************************************** * 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.pattern; import com.espertech.esper.client.EventBean; import com.espertech.esper.core.service.EPStatementHandleCallback; import com.espertech.esper.filter.FilterHandleCallback; import com.espertech.esper.filter.FilterService; import com.espertech.esper.filter.FilterValueSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.Collection; /** * This class contains the state of a single filter expression in the evaluation state tree. */ public class EvalFilterStateNode extends EvalStateNode implements FilterHandleCallback { protected final EvalFilterNode evalFilterNode; protected boolean isStarted; protected EPStatementHandleCallback handle; protected MatchedEventMap beginState; /** * Constructor. * @param parentNode is the parent evaluator to call to indicate truth value * @param evalFilterNode is the factory node associated to the state */ public EvalFilterStateNode(Evaluator parentNode, EvalFilterNode evalFilterNode) { super(parentNode); this.evalFilterNode = evalFilterNode; } @Override public EvalNode getFactoryNode() { return evalFilterNode; } public String getStatementId() { return evalFilterNode.getContext().getPatternContext().getStatementId(); } public final void start(MatchedEventMap beginState) { this.beginState = beginState; if (isStarted) { throw new IllegalStateException("Filter state node already active"); } // Start the filter isStarted = true; startFiltering(); } public final void quit() { isStarted = false; stopFiltering(); } private void evaluateTrue(MatchedEventMap theEvent, boolean isQuitted) { this.getParentEvaluator().evaluateTrue(theEvent, this, isQuitted); } public EvalFilterNode getEvalFilterNode() { return evalFilterNode; } public void matchFound(EventBean theEvent, Collection<FilterHandleCallback> allStmtMatches) { if (!isStarted) { return; } MatchedEventMap passUp = beginState.shallowCopy(); if (evalFilterNode.getFactoryNode().getFilterSpec().getOptionalPropertyEvaluator() != null) { EventBean[] propertyEvents = evalFilterNode.getFactoryNode().getFilterSpec().getOptionalPropertyEvaluator().getProperty(theEvent, evalFilterNode.getContext().getAgentInstanceContext()); if (propertyEvents == null) { return; // no results, ignore match } // Add event itself to the match event structure if a tag was provided if (evalFilterNode.getFactoryNode().getEventAsName() != null) { passUp.add(evalFilterNode.getFactoryNode().getEventAsTagNumber(), propertyEvents); } } else { // Add event itself to the match event structure if a tag was provided if (evalFilterNode.getFactoryNode().getEventAsName() != null) { passUp.add(evalFilterNode.getFactoryNode().getEventAsTagNumber(), theEvent); } } // Explanation for the type cast... // Each state node stops listening if it resolves to true, and all nodes newState // new listeners again. However this would be a performance drain since // and expression such as "on all b()" would remove the listener for b() for every match // and the all node would newState a new listener. The remove operation and the add operation // therefore don't take place if the EvalEveryStateNode node sits on top of a EvalFilterStateNode node. boolean isQuitted = false; if (!(this.getParentEvaluator().isFilterChildNonQuitting())) { stopFiltering(); isQuitted = true; } this.evaluateTrue(passUp, isQuitted); } public final Object accept(EvalStateNodeVisitor visitor, Object data) { return visitor.visit(this, data); } public final Object childrenAccept(EvalStateNodeVisitor visitor, Object data) { return data; } public boolean isSubSelect() { return false; } public final String toString() { StringBuilder buffer = new StringBuilder(); buffer.append("EvalFilterStateNode"); buffer.append(" tag="); buffer.append(evalFilterNode.getFactoryNode().getFilterSpec()); buffer.append(" spec="); buffer.append(evalFilterNode.getFactoryNode().getFilterSpec()); return buffer.toString(); } public boolean isFilterStateNode() { return true; } public boolean isNotOperator() { return false; } protected void startFiltering() { FilterService filterService = evalFilterNode.getContext().getPatternContext().getFilterService(); handle = new EPStatementHandleCallback(evalFilterNode.getContext().getAgentInstanceContext().getEpStatementAgentInstanceHandle(), this); FilterValueSet filterValues = evalFilterNode.getFactoryNode().getFilterSpec().getValueSet(beginState, evalFilterNode.getContext().getAgentInstanceContext(), evalFilterNode.getAddendumFilters()); filterService.add(filterValues, handle); long filtersVersion = filterService.getFiltersVersion(); evalFilterNode.getContext().getAgentInstanceContext().getEpStatementAgentInstanceHandle().getStatementFilterVersion().setStmtFilterVersion(filtersVersion); } private void stopFiltering() { PatternContext context = evalFilterNode.getContext().getPatternContext(); if (handle != null) { context.getFilterService().remove(handle); } handle = null; isStarted = false; long filtersVersion = context.getFilterService().getFiltersVersion(); evalFilterNode.getContext().getAgentInstanceContext().getEpStatementAgentInstanceHandle().getStatementFilterVersion().setStmtFilterVersion(filtersVersion); } private static final Log log = LogFactory.getLog(EvalFilterStateNode.class); }