/**************************************************************************************
* 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.epl.core;
import com.espertech.esper.collection.MultiKeyUntyped;
import com.espertech.esper.epl.agg.AggregationService;
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.epl.expression.ExprValidationException;
import com.espertech.esper.epl.spec.OrderByItem;
import com.espertech.esper.util.MultiKeyCollatingComparator;
import com.espertech.esper.util.MultiKeyComparator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Comparator;
import java.util.List;
/**
* An order-by processor that sorts events according to the expressions
* in the order_by clause.
*/
public class OrderByProcessorFactoryImpl implements OrderByProcessorFactory {
private static final Log log = LogFactory.getLog(OrderByProcessorFactoryImpl.class);
private final OrderByElement[] orderBy;
private final ExprEvaluator[] groupByNodes;
private final boolean needsGroupByKeys;
private final Comparator<MultiKeyUntyped> comparator;
/**
* Ctor.
*
* @param orderByList -
* the nodes that generate the keys to sort events on
* @param groupByNodes -
* generate the keys for determining aggregation groups
* @param needsGroupByKeys -
* indicates whether this processor needs to have individual
* group by keys to evaluate the sort condition successfully
* @param isSortUsingCollator for string value sorting using compare or Collator
* @throws com.espertech.esper.epl.expression.ExprValidationException when order-by items don't divulge a type
*/
public OrderByProcessorFactoryImpl(final List<OrderByItem> orderByList,
List<ExprNode> groupByNodes,
boolean needsGroupByKeys,
boolean isSortUsingCollator)
throws ExprValidationException
{
this.orderBy = toElementArray(orderByList);
this.groupByNodes = ExprNodeUtility.getEvaluators(groupByNodes);
this.needsGroupByKeys = needsGroupByKeys;
comparator = getComparator(orderBy, isSortUsingCollator);
}
public OrderByProcessor instantiate(AggregationService aggregationService) {
return new OrderByProcessorImpl(this, aggregationService);
}
public OrderByElement[] getOrderBy() {
return orderBy;
}
public ExprEvaluator[] getGroupByNodes() {
return groupByNodes;
}
public boolean isNeedsGroupByKeys() {
return needsGroupByKeys;
}
public Comparator<MultiKeyUntyped> getComparator() {
return comparator;
}
/**
* Returns a comparator for order items that may sort string values using Collator.
* @param orderBy order-by items
* @param isSortUsingCollator true for Collator string sorting
* @return comparator
* @throws com.espertech.esper.epl.expression.ExprValidationException if the return type of order items cannot be determined
*/
protected static Comparator<MultiKeyUntyped> getComparator(OrderByElement[] orderBy, boolean isSortUsingCollator) throws ExprValidationException
{
Comparator<MultiKeyUntyped> comparator;
if (isSortUsingCollator)
{
// determine String types
boolean hasStringTypes = false;
boolean stringTypes[] = new boolean[orderBy.length];
int count = 0;
for (OrderByElement item : orderBy)
{
if (item.getExpr().getType() == String.class)
{
hasStringTypes = true;
stringTypes[count] = true;
}
count++;
}
if (!hasStringTypes)
{
comparator = new MultiKeyComparator(getIsDescendingValues(orderBy));
}
else
{
comparator = new MultiKeyCollatingComparator(getIsDescendingValues(orderBy), stringTypes);
}
}
else
{
comparator = new MultiKeyComparator(getIsDescendingValues(orderBy));
}
return comparator;
}
private static boolean[] getIsDescendingValues(OrderByElement[] orderBy)
{
boolean[] isDescendingValues = new boolean[orderBy.length];
int count = 0;
for(OrderByElement pair : orderBy)
{
isDescendingValues[count++] = pair.isDescending();
}
return isDescendingValues;
}
private OrderByElement[] toElementArray(List<OrderByItem> orderByList) {
OrderByElement[] elements = new OrderByElement[orderByList.size()];
int count = 0;
for (OrderByItem item : orderByList) {
elements[count++] = new OrderByElement(item.getExprNode().getExprEvaluator(), item.isDescending());
}
return elements;
}
}