/************************************************************************************** * 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.expression; import com.espertech.esper.client.EventBean; import com.espertech.esper.client.EventType; import com.espertech.esper.event.EventAdapterService; import com.espertech.esper.util.CoercionException; import com.espertech.esper.util.JavaClassHelper; import com.espertech.esper.util.SimpleNumberCoercer; import com.espertech.esper.util.SimpleNumberCoercerFactory; import java.lang.reflect.Array; import java.util.*; /** * Represents an array in a filter expressiun tree. */ public class ExprArrayNode extends ExprNodeBase implements ExprEvaluator, ExprEvaluatorEnumeration { private Class arrayReturnType; private boolean mustCoerce; private int length; private transient SimpleNumberCoercer coercer; private transient Object constantResult; private transient ExprEvaluator[] evaluators; private volatile transient Collection constantResultList; private static final long serialVersionUID = 5533223915923867651L; /** * Ctor. */ public ExprArrayNode() { } public ExprEvaluator getExprEvaluator() { return this; } public void validate(ExprValidationContext validationContext) throws ExprValidationException { length = this.getChildNodes().size(); evaluators = ExprNodeUtility.getEvaluators(this.getChildNodes()); // Can be an empty array with no content if (this.getChildNodes().size() == 0) { arrayReturnType = Object.class; constantResult = new Object[0]; return; } List<Class> comparedTypes = new LinkedList<Class>(); for (int i = 0; i < length; i++) { comparedTypes.add(evaluators[i].getType()); } // Determine common denominator type try { arrayReturnType = JavaClassHelper.getCommonCoercionType(comparedTypes.toArray(new Class[comparedTypes.size()])); // Determine if we need to coerce numbers when one type doesn't match any other type if (JavaClassHelper.isNumeric(arrayReturnType)) { mustCoerce = false; for (Class comparedType : comparedTypes) { if (comparedType != arrayReturnType) { mustCoerce = true; } } if (mustCoerce) { coercer = SimpleNumberCoercerFactory.getCoercer(null, arrayReturnType); } } } catch (CoercionException ex) { // expected, such as mixing String and int values, or Java classes (not boxed) and primitives // use Object[] in such cases } if (arrayReturnType == null) { arrayReturnType = Object.class; } // Determine if we are dealing with constants only Object[] results = new Object[length]; int index = 0; for (ExprNode child : this.getChildNodes()) { if (!child.isConstantResult()) { results = null; // not using a constant result break; } results[index] = evaluators[index].evaluate(null, false, validationContext.getExprEvaluatorContext()); index++; } // Copy constants into array and coerce, if required if (results != null) { constantResult = Array.newInstance(arrayReturnType, length); for (int i = 0; i < length; i++) { if (mustCoerce) { Number boxed = (Number) results[i]; if (boxed != null) { Object coercedResult = coercer.coerceBoxed(boxed); Array.set(constantResult, i, coercedResult); } } else { Array.set(constantResult, i, results[i]); } } } } public boolean isConstantResult() { return constantResult != null; } public Class getType() { return Array.newInstance(arrayReturnType, 0).getClass(); } public Map<String, Object> getEventType() { return null; } public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) { if (constantResult != null) { if (constantResultList != null) { } return constantResult; } Object array = Array.newInstance(arrayReturnType, length); if (length == 0) { return array; } int index = 0; for (ExprEvaluator child : evaluators) { Object result = child.evaluate(eventsPerStream, isNewData, exprEvaluatorContext); if (result != null) { if (mustCoerce) { Number boxed = (Number) result; Object coercedResult = coercer.coerceBoxed(boxed); Array.set(array, index, coercedResult); } else { Array.set(array, index, result); } } index++; } return array; } public String toExpressionString() { StringBuilder buffer = new StringBuilder(); String delimiter = ""; buffer.append("{"); for (ExprNode expr : this.getChildNodes()) { buffer.append(delimiter); buffer.append(expr.toExpressionString()); delimiter = ","; } buffer.append('}'); return buffer.toString(); } public Class getComponentTypeCollection() throws ExprValidationException { return arrayReturnType; } public Collection evaluateGetROCollectionScalar(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { if (constantResult != null) { if (constantResultList != null) { return constantResultList; } ArrayList list = new ArrayList(); for (int i = 0; i < length; i++) { list.add(Array.get(constantResult, i)); } constantResultList = list; return list; } if (length == 0) { return Collections.emptyList(); } List resultList = new ArrayList(); int index = 0; for (ExprEvaluator child : evaluators) { Object result = child.evaluate(eventsPerStream, isNewData, context); if (result != null) { if (mustCoerce) { Number boxed = (Number) result; Object coercedResult = coercer.coerceBoxed(boxed); resultList.add(coercedResult); } else { resultList.add(result); } } index++; } return resultList; } public EventType getEventTypeCollection(EventAdapterService eventAdapterService) throws ExprValidationException { return null; } public Collection<EventBean> evaluateGetROCollectionEvents(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { return null; } public EventType getEventTypeSingle(EventAdapterService eventAdapterService, String statementId) throws ExprValidationException { return null; } public EventBean evaluateGetEventBean(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext context) { return null; } public boolean equalsNode(ExprNode node) { if (!(node instanceof ExprArrayNode)) { return false; } return true; } }