Package com.espertech.esper.view.window

Source Code of com.espertech.esper.view.window.ExpressionWindowView

/**************************************************************************************
* 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.view.window;

import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.EventType;
import com.espertech.esper.collection.OneEventCollection;
import com.espertech.esper.collection.ViewUpdatedCollection;
import com.espertech.esper.core.context.util.AgentInstanceViewFactoryChainContext;
import com.espertech.esper.core.service.EPStatementHandleCallback;
import com.espertech.esper.core.service.ExtensionServicesContext;
import com.espertech.esper.epl.expression.ExprEvaluator;
import com.espertech.esper.epl.variable.VariableChangeCallback;
import com.espertech.esper.epl.variable.VariableReader;
import com.espertech.esper.epl.variable.VariableService;
import com.espertech.esper.event.map.MapEventBean;
import com.espertech.esper.schedule.ScheduleHandleCallback;
import com.espertech.esper.schedule.ScheduleSlot;
import com.espertech.esper.util.StopCallback;
import com.espertech.esper.view.*;

import java.util.ArrayDeque;
import java.util.Iterator;
import java.util.Set;

/**
* This view is a moving window extending the into the past until the expression passed to it returns false.
*/
public final class ExpressionWindowView extends ViewSupport implements DataWindowView, CloneableView, StoppableView, VariableChangeCallback, StopCallback {
    public final static String CURRENT_COUNT = "current_count";
    public final static String OLDEST_TIMESTAMP = "oldest_timestamp";
    public final static String NEWEST_TIMESTAMP = "newest_timestamp";
    public final static String EXPIRED_COUNT = "expired_count";
    public final static String VIEW_REFERENCE = "view_reference";

    private final ExpressionWindowViewFactory dataWindowViewFactory;
    private final ViewUpdatedCollection viewUpdatedCollection;
    private final ArrayDeque<TimestampEventPair> window = new ArrayDeque<TimestampEventPair>();
    private final ExprEvaluator expiryExpression;
    private final MapEventBean builtinEventProps;
    private final EventBean[] eventsPerStream;
    private final Set<String> variableNames;
    private final AgentInstanceViewFactoryChainContext agentInstanceContext;
    private final ScheduleSlot scheduleSlot;
    private final EPStatementHandleCallback scheduleHandle;

    /**
     * Constructor creates a moving window extending the specified number of elements into the past.
     * @param dataWindowViewFactory for copying this view in a group-by
     * @param viewUpdatedCollection is a collection that the view must update when receiving events
     * @param variableNames variable names
     */
    public ExpressionWindowView(ExpressionWindowViewFactory dataWindowViewFactory,
                                ViewUpdatedCollection viewUpdatedCollection,
                                ExprEvaluator expiryExpression,
                                MapEventBean builtinEventProps,
                                Set<String> variableNames,
                                AgentInstanceViewFactoryChainContext agentInstanceContext)
    {
        this.dataWindowViewFactory = dataWindowViewFactory;
        this.viewUpdatedCollection = viewUpdatedCollection;
        this.expiryExpression = expiryExpression;
        this.builtinEventProps = builtinEventProps;
        this.eventsPerStream = new EventBean[] {null, builtinEventProps};
        this.variableNames = variableNames;
        this.agentInstanceContext = agentInstanceContext;

        if (variableNames != null && !variableNames.isEmpty()) {
            for (String variable : variableNames) {
                final VariableService variableService = agentInstanceContext.getStatementContext().getVariableService();
                final VariableReader reader = variableService.getReader(variable);
                agentInstanceContext.getStatementContext().getVariableService().registerCallback(reader.getVariableNumber(), this);
                agentInstanceContext.getTerminationCallbacks().add(new StopCallback() {
                    public void stop() {
                        variableService.unregisterCallback(reader.getVariableNumber(), ExpressionWindowView.this);
                    }
                });
            }

            ScheduleHandleCallback callback = new ScheduleHandleCallback() {
                public void scheduledTrigger(ExtensionServicesContext extensionServicesContext)
                {
                    ExpressionWindowView.this.expire(null, null);
                }
            };
            scheduleSlot = agentInstanceContext.getStatementContext().getScheduleBucket().allocateSlot();
            scheduleHandle = new EPStatementHandleCallback(agentInstanceContext.getEpStatementAgentInstanceHandle(), callback);
            agentInstanceContext.getTerminationCallbacks().add(this);
        }
        else {
            scheduleSlot = null;
            scheduleHandle = null;
        }
    }

    public View cloneView()
    {
        return dataWindowViewFactory.makeView(agentInstanceContext);
    }

    /**
     * Returns true if the window is empty, or false if not empty.
     * @return true if empty
     */
    public boolean isEmpty()
    {
        return window.isEmpty();
    }

    /**
     * Returns the (optional) collection handling random access to window contents for prior or previous events.
     * @return buffer for events
     */
    public ViewUpdatedCollection getViewUpdatedCollection()
    {
        return viewUpdatedCollection;
    }

    public final EventType getEventType()
    {
        // The event type is the parent view's event type
        return parent.getEventType();
    }

    public final void update(EventBean[] newData, EventBean[] oldData)
    {
        // add data points to the window
        if (newData != null)
        {
            for (EventBean newEvent : newData) {
                window.add(new TimestampEventPair(agentInstanceContext.getTimeProvider().getTime(), newEvent));
            }
        }

        if (oldData != null) {
            Iterator<TimestampEventPair> it = window.iterator();
            for (;it.hasNext();) {
                TimestampEventPair pair = it.next();
                for (EventBean anOldData : oldData) {
                    if (pair.getEvent() == anOldData) {
                        it.remove();
                        break;
                    }
                }
            }
        }

        // expire events
        expire(newData, oldData);
    }

    // Called based on schedule evaluation registered when a variable changes (new data is null).
    // Called when new data arrives.
    private void expire(EventBean[] newData, EventBean[] oldData) {

        OneEventCollection expired = null;
        if (oldData != null) {
            expired = new OneEventCollection();
            expired.add(oldData);
        }
        int expiredCount = 0;
        if (!window.isEmpty()) {
            TimestampEventPair newest = window.getLast();

            while (true) {
                TimestampEventPair first = window.getFirst();

                boolean pass = checkEvent(first, newest, expiredCount);
                if (!pass) {
                    if (expired == null) {
                         expired = new OneEventCollection();
                    }
                    expired.add(window.removeFirst().getEvent());
                    expiredCount++;
                }
                else {
                    break;
                }

                if (window.isEmpty()) {
                    break;
                }
            }
        }

        // Check for any events that get pushed out of the window
        EventBean[] expiredArr = null;
        if (expired != null)
        {
            expiredArr = expired.toArray();
        }

        // update event buffer for access by expressions, if any
        if (viewUpdatedCollection != null)
        {
            viewUpdatedCollection.update(newData, expiredArr);
        }

        // If there are child views, call update method
        if (this.hasViews())
        {
            updateChildren(newData, expiredArr);
        }
    }

    private boolean checkEvent(TimestampEventPair pair, TimestampEventPair newest, int numExpired) {

        builtinEventProps.getProperties().put(CURRENT_COUNT, window.size());
        builtinEventProps.getProperties().put(OLDEST_TIMESTAMP, pair.getTimestamp());
        builtinEventProps.getProperties().put(NEWEST_TIMESTAMP, newest.getTimestamp());
        builtinEventProps.getProperties().put(VIEW_REFERENCE, this);
        builtinEventProps.getProperties().put(EXPIRED_COUNT, numExpired);
        eventsPerStream[0] = pair.getEvent();

        Boolean result = (Boolean) expiryExpression.evaluate(eventsPerStream, true, agentInstanceContext);
        if (result == null) {
            return false;
        }
        return result;
    }

    public final Iterator<EventBean> iterator()
    {
        return new TimestampEventPairIterator(window.iterator());
    }

    public final String toString()
    {
        return this.getClass().getName();
    }

    public void stopView() {
        stopScheduleAndVar();
        agentInstanceContext.getTerminationCallbacks().remove(this);
    }

    public void stop() {
        stopScheduleAndVar();
    }

    public void stopScheduleAndVar() {
        if (variableNames != null && !variableNames.isEmpty()) {
            for (String variable : variableNames) {
                VariableReader reader = agentInstanceContext.getStatementContext().getVariableService().getReader(variable);
                if (reader != null) {
                    agentInstanceContext.getStatementContext().getVariableService().unregisterCallback(reader.getVariableNumber(), this);
                }
            }

            if (agentInstanceContext.getStatementContext().getSchedulingService().isScheduled(scheduleHandle)) {
                agentInstanceContext.getStatementContext().getSchedulingService().remove(scheduleHandle, scheduleSlot);
            }
        }
    }


    // Handle variable updates by scheduling a re-evaluation with timers
    public void update(Object newValue, Object oldValue) {
        if (!agentInstanceContext.getStatementContext().getSchedulingService().isScheduled(scheduleHandle)) {
            agentInstanceContext.getStatementContext().getSchedulingService().add(0, scheduleHandle, scheduleSlot);
        }
    }

    private static class TimestampEventPair {
        private final long timestamp;
        private final EventBean event;

        private TimestampEventPair(long timestamp, EventBean event) {
            this.timestamp = timestamp;
            this.event = event;
        }

        public long getTimestamp() {
            return timestamp;
        }

        public EventBean getEvent() {
            return event;
        }
    }

    private static class TimestampEventPairIterator implements Iterator<EventBean> {
        private final Iterator<TimestampEventPair> events;

        private TimestampEventPairIterator(Iterator<TimestampEventPair> events) {
            this.events = events;
        }

        public boolean hasNext() {
            return events.hasNext();
        }

        public EventBean next() {
            return events.next().getEvent();
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}
TOP

Related Classes of com.espertech.esper.view.window.ExpressionWindowView

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.