/* *************************************************************************************** * 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.view.internal; import com.espertech.esper.client.EventBean; import com.espertech.esper.collection.RollingEventBuffer; import com.espertech.esper.collection.ViewUpdatedCollection; import com.espertech.esper.view.window.RelativeAccessByEventNIndex; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * Buffers view-posted insert stream (new data) and remove stream (old data) events for * use with serving prior results in these streams, for a single prior event. * <p> * Buffers only exactly those events in new data and old data that are being asked for via the * 2 or more 'prior' functions that specify different indexes. For example "select prior(2, price), prior(1, price)" * results in on buffer instance handling both the need to the immediatly prior (1) and the 2-events-ago * event (2). * <p> * As all views are required to post new data and post old data that removes the new data to subsequent views, * this buffer can be attached to all views and should not result in a memory leak. * <p> * When the buffer receives old data (rstream) events it removes the prior events to the rstream events * from the buffer the next time it receives a post (not immediatly) to allow queries to the buffer. */ public class PriorEventBufferSingle implements ViewUpdatedCollection, RelativeAccessByEventNIndex { private final int priorEventIndex; private final Map<EventBean, EventBean> priorEventMap; private final RollingEventBuffer newEvents; private EventBean[] lastOldData; /** * Ctor. * * @param priorEventIndex is the number-of-events prior to the current event we are interested in */ public PriorEventBufferSingle(int priorEventIndex) { this.priorEventIndex = priorEventIndex; // Construct a rolling buffer of new data for holding max index + 1 (position 1 requires 2 events to keep) newEvents = new RollingEventBuffer(priorEventIndex + 1); priorEventMap = new HashMap<EventBean, EventBean>(); } public void update(EventBean[] newData, EventBean[] oldData) { // Remove last old data posted in previous post if (lastOldData != null) { for (int i = 0; i < lastOldData.length; i++) { priorEventMap.remove(lastOldData[i]); } } // Post new data to rolling buffer starting with the oldest if (newData != null) { for (int i = 0; i < newData.length; i++) { EventBean newEvent = newData[i]; // Add new event newEvents.add(newEvent); EventBean priorEvent = newEvents.get(priorEventIndex); priorEventMap.put(newEvent, priorEvent); } } // Save old data to be removed next time we get posted results lastOldData = oldData; } public void update(EventBean[] newData, EventBean[] oldData, PriorEventBufferChangeCaptureSingle captureSingle) { // Remove last old data posted in previous post if (lastOldData != null) { for (int i = 0; i < lastOldData.length; i++) { EventBean oldDataItem = lastOldData[i]; priorEventMap.remove(oldDataItem); captureSingle.removed(oldDataItem); } } // Post new data to rolling buffer starting with the oldest if (newData != null) { for (int i = 0; i < newData.length; i++) { EventBean newEvent = newData[i]; // Add new event newEvents.add(newEvent); EventBean priorEvent = newEvents.get(priorEventIndex); priorEventMap.put(newEvent, priorEvent); captureSingle.added(newEvent, priorEvent); } } // Save old data to be removed next time we get posted results lastOldData = oldData; } // Users are assigned an index public EventBean getRelativeToEvent(EventBean theEvent, int priorToIndex) { if (priorToIndex != 0) { throw new IllegalArgumentException("Single prior event buffer takes only a given index of zero"); } return priorEventMap.get(theEvent); } public EventBean getRelativeToEnd(int index) { // No requirement to index from end of current buffer return null; } public Iterator<EventBean> getWindowToEvent() { // no requirement for window iterator support return null; } public int getWindowToEventCount() { // no requirement for count support return 0; } public Collection<EventBean> getWindowToEventCollReadOnly() { return null; } public Map<EventBean, EventBean> getPriorEventMap() { return priorEventMap; } public RollingEventBuffer getNewEvents() { return newEvents; } public void destroy() { // No action required } public int getNumEventsInsertBuf() { return newEvents.getSize(); } }