/* *************************************************************************************** * 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.epl.agg.access; import com.espertech.esper.client.EventBean; import com.espertech.esper.collection.MultiKeyUntyped; import com.espertech.esper.epl.expression.core.ExprEvaluator; import com.espertech.esper.epl.expression.core.ExprEvaluatorContext; import java.util.*; /** * Implementation of access function for single-stream (not joins). */ public class AggregationStateSortedImpl implements AggregationStateWithSize, AggregationStateSorted { protected final AggregationStateSortedSpec spec; protected final TreeMap<Object, Object> sorted; protected int size; /** * Ctor. * * @param spec aggregation spec */ public AggregationStateSortedImpl(AggregationStateSortedSpec spec) { this.spec = spec; sorted = new TreeMap<Object, Object>(spec.getComparator()); } public void clear() { sorted.clear(); size = 0; } public void applyEnter(EventBean[] eventsPerStream, ExprEvaluatorContext exprEvaluatorContext) { EventBean theEvent = eventsPerStream[spec.getStreamId()]; if (theEvent == null) { return; } referenceAdd(theEvent, eventsPerStream, exprEvaluatorContext); } protected boolean referenceEvent(EventBean theEvent) { // no action return true; } protected boolean dereferenceEvent(EventBean theEvent) { // no action return true; } public void applyLeave(EventBean[] eventsPerStream, ExprEvaluatorContext exprEvaluatorContext) { EventBean theEvent = eventsPerStream[spec.getStreamId()]; if (theEvent == null) { return; } dereferenceRemove(theEvent, eventsPerStream, exprEvaluatorContext); } public EventBean getFirstValue() { if (sorted.isEmpty()) { return null; } Map.Entry<Object, Object> max = sorted.firstEntry(); return checkedPayload(max.getValue()); } public EventBean getLastValue() { if (sorted.isEmpty()) { return null; } Map.Entry<Object, Object> min = sorted.lastEntry(); return checkedPayload(min.getValue()); } public Iterator<EventBean> iterator() { return new AggregationStateSortedIterator(sorted, false); } public Iterator<EventBean> getReverseIterator() { return new AggregationStateSortedIterator(sorted, true); } public Collection<EventBean> collectionReadOnly() { return new AggregationStateSortedWrappingCollection(sorted, size); } public int size() { return size; } public static Object getComparable(ExprEvaluator[] criteria, EventBean[] eventsPerStream, boolean istream, ExprEvaluatorContext exprEvaluatorContext) { if (criteria.length == 1) { return criteria[0].evaluate(eventsPerStream, istream, exprEvaluatorContext); } else { Object[] result = new Object[criteria.length]; int count = 0; for (ExprEvaluator expr : criteria) { result[count++] = expr.evaluate(eventsPerStream, true, exprEvaluatorContext); } return new MultiKeyUntyped(result); } } protected void referenceAdd(EventBean theEvent, EventBean[] eventsPerStream, ExprEvaluatorContext exprEvaluatorContext) { if (referenceEvent(theEvent)) { Object comparable = getComparable(spec.getCriteria(), eventsPerStream, true, exprEvaluatorContext); Object existing = sorted.get(comparable); if (existing == null) { sorted.put(comparable, theEvent); } else if (existing instanceof EventBean) { ArrayDeque coll = new ArrayDeque(2); coll.add(existing); coll.add(theEvent); sorted.put(comparable, coll); } else { ArrayDeque q = (ArrayDeque) existing; q.add(theEvent); } size++; } } protected void dereferenceRemove(EventBean theEvent, EventBean[] eventsPerStream, ExprEvaluatorContext exprEvaluatorContext) { if (dereferenceEvent(theEvent)) { Object comparable = getComparable(spec.getCriteria(), eventsPerStream, false, exprEvaluatorContext); Object existing = sorted.get(comparable); if (existing != null) { if (existing.equals(theEvent)) { sorted.remove(comparable); size--; } else if (existing instanceof ArrayDeque) { ArrayDeque q = (ArrayDeque) existing; q.remove(theEvent); if (q.isEmpty()) { sorted.remove(comparable); } size--; } } } } private EventBean checkedPayload(Object value) { if (value instanceof EventBean) { return (EventBean) value; } ArrayDeque<EventBean> q = (ArrayDeque<EventBean>) value; return q.getFirst(); } }