/************************************************************************************** * 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.core; import com.espertech.esper.client.EventBean; import com.espertech.esper.client.EventType; import com.espertech.esper.collection.*; import com.espertech.esper.core.context.util.AgentInstanceContext; import com.espertech.esper.epl.agg.service.AggregationService; import com.espertech.esper.epl.expression.ExprEvaluatorContext; import com.espertech.esper.epl.spec.OutputLimitLimitType; import com.espertech.esper.util.CollectionUtil; import com.espertech.esper.view.Viewable; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; /** * Result set processor for the case: aggregation functions used in the select clause, and no group-by, * and all properties in the select clause are under an aggregation function. * <p> * This processor does not perform grouping, every event entering and leaving is in the same group. * Produces one old event and one new event row every time either at least one old or new event is received. * Aggregation state is simply one row holding all the state. */ public class ResultSetProcessorRowForAll implements ResultSetProcessor { private final ResultSetProcessorRowForAllFactory prototype; private final SelectExprProcessor selectExprProcessor; private final OrderByProcessor orderByProcessor; private final AggregationService aggregationService; private ExprEvaluatorContext exprEvaluatorContext; public ResultSetProcessorRowForAll(ResultSetProcessorRowForAllFactory prototype, SelectExprProcessor selectExprProcessor, OrderByProcessor orderByProcessor, AggregationService aggregationService, ExprEvaluatorContext exprEvaluatorContext) { this.prototype = prototype; this.selectExprProcessor = selectExprProcessor; this.orderByProcessor = orderByProcessor; this.aggregationService = aggregationService; this.exprEvaluatorContext = exprEvaluatorContext; } public void setAgentInstanceContext(AgentInstanceContext context) { this.exprEvaluatorContext = context; } public EventType getResultEventType() { return prototype.getResultEventType(); } public UniformPair<EventBean[]> processJoinResult(Set<MultiKey<EventBean>> newEvents, Set<MultiKey<EventBean>> oldEvents, boolean isSynthesize) { EventBean[] selectOldEvents = null; EventBean[] selectNewEvents; if (prototype.isUnidirectional()) { this.clear(); } if (prototype.isSelectRStream()) { selectOldEvents = getSelectListEvents(false, isSynthesize); } if (!newEvents.isEmpty()) { // apply new data to aggregates for (MultiKey<EventBean> events : newEvents) { aggregationService.applyEnter(events.getArray(), null, exprEvaluatorContext); } } if (!oldEvents.isEmpty()) { // apply old data to aggregates for (MultiKey<EventBean> events : oldEvents) { aggregationService.applyLeave(events.getArray(), null, exprEvaluatorContext); } } selectNewEvents = getSelectListEvents(true, isSynthesize); if ((selectNewEvents == null) && (selectOldEvents == null)) { return null; } return new UniformPair<EventBean[]>(selectNewEvents, selectOldEvents); } public UniformPair<EventBean[]> processViewResult(EventBean[] newData, EventBean[] oldData, boolean isSynthesize) { EventBean[] selectOldEvents = null; EventBean[] selectNewEvents; if (prototype.isSelectRStream()) { selectOldEvents = getSelectListEvents(false, isSynthesize); } EventBean[] eventsPerStream = new EventBean[1]; if (newData != null) { // apply new data to aggregates for (int i = 0; i < newData.length; i++) { eventsPerStream[0] = newData[i]; aggregationService.applyEnter(eventsPerStream, null, exprEvaluatorContext); } } if (oldData != null) { // apply old data to aggregates for (int i = 0; i < oldData.length; i++) { eventsPerStream[0] = oldData[i]; aggregationService.applyLeave(eventsPerStream, null, exprEvaluatorContext); } } // generate new events using select expressions selectNewEvents = getSelectListEvents(true, isSynthesize); if ((selectNewEvents == null) && (selectOldEvents == null)) { return null; } return new UniformPair<EventBean[]>(selectNewEvents, selectOldEvents); } private EventBean[] getSelectListEvents(boolean isNewData, boolean isSynthesize) { // Since we are dealing with strictly aggregation nodes, there are no events required for evaluating EventBean theEvent = selectExprProcessor.process(CollectionUtil.EVENT_PER_STREAM_EMPTY, isNewData, isSynthesize, exprEvaluatorContext); if (prototype.getOptionalHavingNode() != null) { Boolean result = (Boolean) prototype.getOptionalHavingNode().evaluate(null, isNewData, exprEvaluatorContext); if ((result == null) || (!result)) { return null; } } // The result is always a single row return new EventBean[] {theEvent}; } private EventBean getSelectListEvent(boolean isNewData, boolean isSynthesize) { // Since we are dealing with strictly aggregation nodes, there are no events required for evaluating EventBean theEvent = selectExprProcessor.process(CollectionUtil.EVENT_PER_STREAM_EMPTY, isNewData, isSynthesize, exprEvaluatorContext); if (prototype.getOptionalHavingNode() != null) { Boolean result = (Boolean) prototype.getOptionalHavingNode().evaluate(null, isNewData, exprEvaluatorContext); if ((result == null) || (!result)) { return null; } } // The result is always a single row return theEvent; } public Iterator<EventBean> getIterator(Viewable parent) { EventBean[] selectNewEvents = getSelectListEvents(true, true); if (selectNewEvents == null) { return CollectionUtil.NULL_EVENT_ITERATOR; } return new SingleEventIterator(selectNewEvents[0]); } public Iterator<EventBean> getIterator(Set<MultiKey<EventBean>> joinSet) { EventBean[] result = getSelectListEvents(true, true); return new ArrayEventIterator(result); } public void clear() { aggregationService.clearResults(exprEvaluatorContext); } public UniformPair<EventBean[]> processOutputLimitedJoin(List<UniformPair<Set<MultiKey<EventBean>>>> joinEventsSet, boolean generateSynthetic, OutputLimitLimitType outputLimitLimitType) { if (outputLimitLimitType == OutputLimitLimitType.LAST) { EventBean lastOldEvent = null; EventBean lastNewEvent = null; // if empty (nothing to post) if (joinEventsSet.isEmpty()) { if (prototype.isSelectRStream()) { lastOldEvent = getSelectListEvent(false, generateSynthetic); lastNewEvent = lastOldEvent; } else { lastNewEvent = getSelectListEvent(false, generateSynthetic); } } for (UniformPair<Set<MultiKey<EventBean>>> pair : joinEventsSet) { if (prototype.isUnidirectional()) { this.clear(); } Set<MultiKey<EventBean>> newData = pair.getFirst(); Set<MultiKey<EventBean>> oldData = pair.getSecond(); if ((lastOldEvent == null) && (prototype.isSelectRStream())) { lastOldEvent = getSelectListEvent(false, generateSynthetic); } if (newData != null) { // apply new data to aggregates for (MultiKey<EventBean> eventsPerStream : newData) { aggregationService.applyEnter(eventsPerStream.getArray(), null, exprEvaluatorContext); } } if (oldData != null) { // apply old data to aggregates for (MultiKey<EventBean> eventsPerStream : oldData) { aggregationService.applyLeave(eventsPerStream.getArray(), null, exprEvaluatorContext); } } lastNewEvent = getSelectListEvent(true, generateSynthetic); } EventBean[] lastNew = (lastNewEvent != null) ? new EventBean[] {lastNewEvent} : null; EventBean[] lastOld = (lastOldEvent != null) ? new EventBean[] {lastOldEvent} : null; if ((lastNew == null) && (lastOld == null)) { return null; } return new UniformPair<EventBean[]>(lastNew, lastOld); } else { List<EventBean> newEvents = new LinkedList<EventBean>(); List<EventBean> oldEvents = null; if (prototype.isSelectRStream()) { oldEvents = new LinkedList<EventBean>(); } List<Object> newEventsSortKey = null; List<Object> oldEventsSortKey = null; if (orderByProcessor != null) { newEventsSortKey = new LinkedList<Object>(); if (prototype.isSelectRStream()) { oldEventsSortKey = new LinkedList<Object>(); } } for (UniformPair<Set<MultiKey<EventBean>>> pair : joinEventsSet) { if (prototype.isUnidirectional()) { this.clear(); } Set<MultiKey<EventBean>> newData = pair.getFirst(); Set<MultiKey<EventBean>> oldData = pair.getSecond(); if (prototype.isSelectRStream()) { getSelectListEvent(false, generateSynthetic, oldEvents); } if (newData != null) { // apply new data to aggregates for (MultiKey<EventBean> row : newData) { aggregationService.applyEnter(row.getArray(), null, exprEvaluatorContext); } } if (oldData != null) { // apply old data to aggregates for (MultiKey<EventBean> row : oldData) { aggregationService.applyLeave(row.getArray(), null, exprEvaluatorContext); } } getSelectListEvent(false, generateSynthetic, newEvents); } EventBean[] newEventsArr = (newEvents.isEmpty()) ? null : newEvents.toArray(new EventBean[newEvents.size()]); EventBean[] oldEventsArr = null; if (prototype.isSelectRStream()) { oldEventsArr = (oldEvents.isEmpty()) ? null : oldEvents.toArray(new EventBean[oldEvents.size()]); } if (orderByProcessor != null) { Object[] sortKeysNew = (newEventsSortKey.isEmpty()) ? null : newEventsSortKey.toArray(new Object[newEventsSortKey.size()]); newEventsArr = orderByProcessor.sort(newEventsArr, sortKeysNew, exprEvaluatorContext); if (prototype.isSelectRStream()) { Object[] sortKeysOld = (oldEventsSortKey.isEmpty()) ? null : oldEventsSortKey.toArray(new Object[oldEventsSortKey.size()]); oldEventsArr = orderByProcessor.sort(oldEventsArr, sortKeysOld, exprEvaluatorContext); } } if (joinEventsSet.isEmpty()) { if (prototype.isSelectRStream()) { oldEventsArr = getSelectListEvents(false, generateSynthetic); } newEventsArr = getSelectListEvents(true, generateSynthetic); } if ((newEventsArr == null) && (oldEventsArr == null)) { return null; } return new UniformPair<EventBean[]>(newEventsArr, oldEventsArr); } } public UniformPair<EventBean[]> processOutputLimitedView(List<UniformPair<EventBean[]>> viewEventsList, boolean generateSynthetic, OutputLimitLimitType outputLimitLimitType) { if (outputLimitLimitType == OutputLimitLimitType.LAST) { // For last, if there are no events: // As insert stream, return the current value, if matching the having clause // As remove stream, return the current value, if matching the having clause // For last, if there are events in the batch: // As insert stream, return the newest value that is matching the having clause // As remove stream, return the oldest value that is matching the having clause EventBean lastOldEvent = null; EventBean lastNewEvent = null; EventBean[] eventsPerStream = new EventBean[1]; // if empty (nothing to post) if (viewEventsList.isEmpty()) { if (prototype.isSelectRStream()) { lastOldEvent = getSelectListEvent(false, generateSynthetic); lastNewEvent = lastOldEvent; } else { lastNewEvent = getSelectListEvent(false, generateSynthetic); } } for (UniformPair<EventBean[]> pair : viewEventsList) { EventBean[] newData = pair.getFirst(); EventBean[] oldData = pair.getSecond(); if ((lastOldEvent == null) && (prototype.isSelectRStream())) { lastOldEvent = getSelectListEvent(false, generateSynthetic); } if (newData != null) { // apply new data to aggregates for (EventBean aNewData : newData) { eventsPerStream[0] = aNewData; aggregationService.applyEnter(eventsPerStream, null, exprEvaluatorContext); } } if (oldData != null) { // apply old data to aggregates for (EventBean anOldData : oldData) { eventsPerStream[0] = anOldData; aggregationService.applyLeave(eventsPerStream, null, exprEvaluatorContext); } } lastNewEvent = getSelectListEvent(false, generateSynthetic); } EventBean[] lastNew = (lastNewEvent != null) ? new EventBean[] {lastNewEvent} : null; EventBean[] lastOld = (lastOldEvent != null) ? new EventBean[] {lastOldEvent} : null; if ((lastNew == null) && (lastOld == null)) { return null; } return new UniformPair<EventBean[]>(lastNew, lastOld); } else { List<EventBean> newEvents = new LinkedList<EventBean>(); List<EventBean> oldEvents = null; if (prototype.isSelectRStream()) { oldEvents = new LinkedList<EventBean>(); } List<Object> newEventsSortKey = null; List<Object> oldEventsSortKey = null; if (orderByProcessor != null) { newEventsSortKey = new LinkedList<Object>(); if (prototype.isSelectRStream()) { oldEventsSortKey = new LinkedList<Object>(); } } for (UniformPair<EventBean[]> pair : viewEventsList) { EventBean[] newData = pair.getFirst(); EventBean[] oldData = pair.getSecond(); if (prototype.isSelectRStream()) { getSelectListEvent(false, generateSynthetic, oldEvents); } EventBean[] eventsPerStream = new EventBean[1]; if (newData != null) { // apply new data to aggregates for (EventBean aNewData : newData) { eventsPerStream[0] = aNewData; aggregationService.applyEnter(eventsPerStream, null, exprEvaluatorContext); } } if (oldData != null) { // apply old data to aggregates for (EventBean anOldData : oldData) { eventsPerStream[0] = anOldData; aggregationService.applyLeave(eventsPerStream, null, exprEvaluatorContext); } } getSelectListEvent(true, generateSynthetic, newEvents); } EventBean[] newEventsArr = (newEvents.isEmpty()) ? null : newEvents.toArray(new EventBean[newEvents.size()]); EventBean[] oldEventsArr = null; if (prototype.isSelectRStream()) { oldEventsArr = (oldEvents.isEmpty()) ? null : oldEvents.toArray(new EventBean[oldEvents.size()]); } if (orderByProcessor != null) { Object[] sortKeysNew = (newEventsSortKey.isEmpty()) ? null : newEventsSortKey.toArray(new Object[newEventsSortKey.size()]); newEventsArr = orderByProcessor.sort(newEventsArr, sortKeysNew, exprEvaluatorContext); if (prototype.isSelectRStream()) { Object[] sortKeysOld = (oldEventsSortKey.isEmpty()) ? null : oldEventsSortKey.toArray(new Object[oldEventsSortKey.size()]); oldEventsArr = orderByProcessor.sort(oldEventsArr, sortKeysOld, exprEvaluatorContext); } } if (viewEventsList.isEmpty()) { if (prototype.isSelectRStream()) { oldEventsArr = getSelectListEvents(false, generateSynthetic); } newEventsArr = getSelectListEvents(true, generateSynthetic); } if ((newEventsArr == null) && (oldEventsArr == null)) { return null; } return new UniformPair<EventBean[]>(newEventsArr, oldEventsArr); } } private void getSelectListEvent(boolean isNewData, boolean isSynthesize, List<EventBean> resultEvents) { // Since we are dealing with strictly aggregation nodes, there are no events required for evaluating EventBean theEvent = selectExprProcessor.process(CollectionUtil.EVENT_PER_STREAM_EMPTY, isNewData, isSynthesize, exprEvaluatorContext); if (prototype.getOptionalHavingNode() != null) { Boolean result = (Boolean) prototype.getOptionalHavingNode().evaluate(null, isNewData, exprEvaluatorContext); if ((result == null) || (!result)) { return; } } resultEvents.add(theEvent); } public boolean hasAggregation() { return true; } }