All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.espertech.esper.view.std.UniqueByPropertyView Maven / Gradle / Ivy

There is a newer version: 7.1.0
Show newest version
/*
 ***************************************************************************************
 *  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.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.core.ExprEvaluator;
import com.espertech.esper.epl.expression.core.ExprNode;
import com.espertech.esper.epl.expression.core.ExprNodeUtility;
import com.espertech.esper.metrics.instrumentation.InstrumentationHelper;
import com.espertech.esper.view.*;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
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 class UniqueByPropertyView extends ViewSupport implements CloneableView, DataWindowView {
    private final UniqueByPropertyViewFactory viewFactory;
    protected final ExprEvaluator[] criteriaExpressionsEvals;
    protected final Map mostRecentEvents = new HashMap();
    private final EventBean[] eventsPerStream = new EventBean[1];
    protected final AgentInstanceViewFactoryChainContext agentInstanceViewFactoryContext;

    public UniqueByPropertyView(UniqueByPropertyViewFactory viewFactory, AgentInstanceViewFactoryChainContext agentInstanceViewFactoryContext) {
        this.viewFactory = viewFactory;
        this.criteriaExpressionsEvals = ExprNodeUtility.getEvaluators(viewFactory.criteriaExpressions);
        this.agentInstanceViewFactoryContext = agentInstanceViewFactoryContext;
    }

    public View cloneView() {
        return new UniqueByPropertyView(viewFactory, 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 viewFactory.criteriaExpressions;
    }

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

    public final void update(EventBean[] newData, EventBean[] oldData) {
        if (InstrumentationHelper.ENABLED) {
            InstrumentationHelper.get().qViewProcessIRStream(this, UniqueByPropertyViewFactory.NAME, newData, 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 == null || !lastValue.equals(oldData[i])) {
                    continue;
                }

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


        // If there are child views, fireStatementStopped update method
        if (this.hasViews()) {
            if (postOldData.isEmpty()) {
                if (InstrumentationHelper.ENABLED) {
                    InstrumentationHelper.get().qViewIndicate(this, UniqueByPropertyViewFactory.NAME, newData, null);
                }
                updateChildren(newData, null);
                if (InstrumentationHelper.ENABLED) {
                    InstrumentationHelper.get().aViewIndicate();
                }
            } else {
                EventBean[] postOldDataArray = postOldData.toArray();
                if (InstrumentationHelper.ENABLED) {
                    InstrumentationHelper.get().qViewIndicate(this, UniqueByPropertyViewFactory.NAME, newData, postOldDataArray);
                }
                updateChildren(newData, postOldDataArray);
                if (InstrumentationHelper.ENABLED) {
                    InstrumentationHelper.get().aViewIndicate();
                }
            }
        }
        if (InstrumentationHelper.ENABLED) {
            InstrumentationHelper.get().aViewProcessIRStream();
        }
    }

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

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

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

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

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

    public void visitView(ViewDataVisitor viewDataVisitor) {
        viewDataVisitor.visitPrimary(mostRecentEvents, true, UniqueByPropertyViewFactory.NAME, mostRecentEvents.size(), mostRecentEvents.size());
    }

    public ViewFactory getViewFactory() {
        return viewFactory;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy