Package com.espertech.esper.view.std

Source Code of com.espertech.esper.view.std.UniqueByPropertyView

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

import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.EventType;
import com.espertech.esper.collection.MultiKeyUntyped;
import com.espertech.esper.collection.OneEventCollection;
import com.espertech.esper.core.context.util.AgentInstanceViewFactoryChainContext;
import com.espertech.esper.epl.expression.ExprEvaluator;
import com.espertech.esper.epl.expression.ExprNode;
import com.espertech.esper.epl.expression.ExprNodeUtility;
import com.espertech.esper.view.CloneableView;
import com.espertech.esper.view.View;
import com.espertech.esper.view.ViewSupport;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

/**
* This view includes only the most recent among events having the same value for the specified field or fields.
* The view accepts the field name as parameter from which the unique values are obtained.
* For example, a trade's symbol could be used as a unique value.
* In this example, the first trade for symbol IBM would be posted as new data to child views.
* When the second trade for symbol IBM arrives the second trade is posted as new data to child views,
* and the first trade is posted as old data.
* Should more than one trades for symbol IBM arrive at the same time (like when batched)
* then the child view will get all new events in newData and all new events in oldData minus the most recent event.
* When the current new event arrives as old data, the the current unique event gets thrown away and
* posted as old data to child views.
* Iteration through the views data shows only the most recent events received for the unique value in the order
* that events arrived in.
* The type of the field returning the unique value can be any type but should override equals and hashCode()
* as the type plays the role of a key in a map storing unique values.
*/
public final class UniqueByPropertyView extends ViewSupport implements CloneableView
{
    private final ExprNode[] criteriaExpressions;
    private final ExprEvaluator[] criteriaExpressionsEvals;
    private final int numKeys;
    private final Map<Object, EventBean> mostRecentEvents = new LinkedHashMap<Object, EventBean>();
    private final EventBean[] eventsPerStream = new EventBean[1];
    private final AgentInstanceViewFactoryChainContext agentInstanceViewFactoryContext;

    /**
     * Constructor.
     * @param criteriaExpressions is the expressions from which to pull the unique value
     * @param agentInstanceViewFactoryContext context for expression evaluation
     */
    public UniqueByPropertyView(ExprNode[] criteriaExpressions, AgentInstanceViewFactoryChainContext agentInstanceViewFactoryContext)
    {
        this.criteriaExpressions = criteriaExpressions;
        this.criteriaExpressionsEvals = ExprNodeUtility.getEvaluators(criteriaExpressions);
        this.agentInstanceViewFactoryContext = agentInstanceViewFactoryContext;
        numKeys = criteriaExpressions.length;
    }

    public View cloneView()
    {
        return new UniqueByPropertyView(criteriaExpressions, agentInstanceViewFactoryContext);
    }

    /**
     * Returns the name of the field supplying the unique value to keep the most recent record for.
     * @return expressions for unique value
     */
    public final ExprNode[] getCriteriaExpressions()
    {
        return criteriaExpressions;
    }

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

    public final void update(EventBean[] newData, EventBean[] oldData)
    {
        OneEventCollection postOldData = null;

        if (this.hasViews())
        {
            postOldData = new OneEventCollection();
        }

        if (newData != null)
        {
            for (int i = 0; i < newData.length; i++)
            {
                // Obtain unique value
                Object key = getUniqueKey(newData[i]);

                // If there are no child views, just update the own collection
                if (!this.hasViews())
                {
                    mostRecentEvents.put(key, newData[i]);
                    continue;
                }

                // Post the last value as old data
                EventBean lastValue = mostRecentEvents.get(key);
                if (lastValue != null)
                {
                    postOldData.add(lastValue);
                }

                // Override with recent event
                mostRecentEvents.put(key, newData[i]);
            }
        }

        if (oldData != null)
        {
            for (int i = 0; i < oldData.length; i++)
            {
                // Obtain unique value
                Object key = getUniqueKey(oldData[i]);

                // If the old event is the current unique event, remove and post as old data
                EventBean lastValue = mostRecentEvents.get(key);
                if (lastValue != oldData[i])
                {
                    continue;
                }

                postOldData.add(lastValue);
                mostRecentEvents.remove(key);
            }
        }


        // If there are child views, fireStatementStopped update method
        if (this.hasViews())
        {
            if (postOldData.isEmpty())
            {
                updateChildren(newData, null);
            }
            else
            {
                updateChildren(newData, postOldData.toArray());
            }
        }
    }

    /**
     * Returns true if the view is empty.
     * @return true if empty
     */
    public boolean isEmpty()
    {
        return mostRecentEvents.isEmpty();
    }

    public final Iterator<EventBean> iterator()
    {
        return mostRecentEvents.values().iterator();
    }

    public final String toString()
    {
        return this.getClass().getName() + " uniqueFieldNames=" + Arrays.toString(criteriaExpressions);
    }

    private Object getUniqueKey(EventBean theEvent)
    {
        eventsPerStream[0] = theEvent;
        if (criteriaExpressionsEvals.length == 1) {
            return criteriaExpressionsEvals[0].evaluate(eventsPerStream, true, agentInstanceViewFactoryContext);
        }

        Object[] values = new Object[numKeys];
        for (int i = 0; i < numKeys; i++)
        {
            values[i] = criteriaExpressionsEvals[i].evaluate(eventsPerStream, true, agentInstanceViewFactoryContext);
        }
        return new MultiKeyUntyped(values);
    }

    private static final Log log = LogFactory.getLog(UniqueByPropertyView.class);
}
TOP

Related Classes of com.espertech.esper.view.std.UniqueByPropertyView

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.