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

com.espertech.esper.epl.expression.ops.ExprEqualsAllAnyNode Maven / Gradle / Ivy

There is a newer version: 7.1.0
Show newest version
/*
 * *************************************************************************************
 *  Copyright (C) 2006-2015 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.expression.ops;

import com.espertech.esper.client.EventBean;
import com.espertech.esper.epl.expression.core.*;
import com.espertech.esper.metrics.instrumentation.InstrumentationHelper;
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.io.StringWriter;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * Represents an equals-for-group (= ANY/ALL/SOME (expression list)) comparator in a expression tree.
 */
public class ExprEqualsAllAnyNode extends ExprNodeBase implements ExprEvaluator
{
    private final boolean isNot;
    private final boolean isAll;

    private boolean mustCoerce;
    private transient SimpleNumberCoercer coercer;
    private boolean hasCollectionOrArray;

    private transient ExprEvaluator[] evaluators;

    private static final long serialVersionUID = -2410457251623137179L;

    /**
     * Ctor.
     * @param isNotEquals - true if this is a (!=) not equals rather then equals, false if its a '=' equals
     * @param isAll - true if all, false for any
     */
    public ExprEqualsAllAnyNode(boolean isNotEquals, boolean isAll)
    {
        this.isNot = isNotEquals;
        this.isAll = isAll;
    }

    public ExprEvaluator getExprEvaluator()
    {
        return this;
    }

    /**
     * Returns true if this is a NOT EQUALS node, false if this is a EQUALS node.
     * @return true for !=, false for =
     */
    public boolean isNot()
    {
        return isNot;
    }

    /**
     * True if all.
     * @return all-flag
     */
    public boolean isAll()
    {
        return isAll;
    }

    public ExprNode validate(ExprValidationContext validationContext) throws ExprValidationException
    {
        // Must have 2 child nodes
        if (this.getChildNodes().length < 1)
        {
            throw new IllegalStateException("Equals group node does not have 1 or more parameters");
        }

        evaluators = ExprNodeUtility.getEvaluators(this.getChildNodes());

        // Must be the same boxed type returned by expressions under this
        Class typeOne = JavaClassHelper.getBoxedType(evaluators[0].getType());

        // collections, array or map not supported
        if ((typeOne.isArray()) || (JavaClassHelper.isImplementsInterface(typeOne, Collection.class)) || (JavaClassHelper.isImplementsInterface(typeOne, Map.class)))
        {
            throw new ExprValidationException("Collection or array comparison is not allowed for the IN, ANY, SOME or ALL keywords");
        }

        List comparedTypes = new ArrayList();
        comparedTypes.add(typeOne);
        hasCollectionOrArray = false;
        for (int i = 0; i < this.getChildNodes().length - 1; i++)
        {
            Class propType = evaluators[i + 1].getType();
            if (propType.isArray())
            {
                hasCollectionOrArray = true;
                if (propType.getComponentType() != Object.class)
                {
                    comparedTypes.add(propType.getComponentType());
                }
            }
            else if (JavaClassHelper.isImplementsInterface(propType, Collection.class))
            {
                hasCollectionOrArray = true;
            }
            else if (JavaClassHelper.isImplementsInterface(propType, Map.class))
            {
                hasCollectionOrArray = true;
            }
            else
            {
                comparedTypes.add(propType);
            }
        }

        // Determine common denominator type
        Class coercionType;
        try {
            coercionType = JavaClassHelper.getCommonCoercionType(comparedTypes.toArray(new Class[comparedTypes.size()]));
        }
        catch (CoercionException ex)
        {
            throw new ExprValidationException("Implicit conversion not allowed: " + ex.getMessage());
        }

        // Check if we need to coerce
        mustCoerce = false;
        if (JavaClassHelper.isNumeric(coercionType))
        {
            for (Class compareType : comparedTypes)
            {
                if (coercionType != JavaClassHelper.getBoxedType(compareType))
                {
                    mustCoerce = true;
                }
            }
            if (mustCoerce)
            {
                coercer = SimpleNumberCoercerFactory.getCoercer(null, JavaClassHelper.getBoxedType(coercionType));
            }
        }
        return null;
    }

    public boolean isConstantResult()
    {
        return false;
    }

    public Class getType()
    {
        return Boolean.class;
    }

    public Object evaluate(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
    {
        if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().qExprEqualsAnyOrAll(this);}
        Object result = evaluateInternal(eventsPerStream, isNewData, exprEvaluatorContext);
        if (InstrumentationHelper.ENABLED) { InstrumentationHelper.get().aExprEqualsAnyOrAll((Boolean) result);}
        return result;
    }

    private Object evaluateInternal(EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext) {

        Object leftResult = evaluators[0].evaluate(eventsPerStream, isNewData, exprEvaluatorContext);

        if (hasCollectionOrArray)
        {
            if (isAll)
            {
                return compareAllColl(leftResult, eventsPerStream, isNewData, exprEvaluatorContext);
            }
            else
            {
                return compareAnyColl(leftResult, eventsPerStream, isNewData, exprEvaluatorContext);
            }
        }
        else
        {
            // coerce early if testing without collections
            if ((mustCoerce) && (leftResult != null))
            {
                leftResult = coercer.coerceBoxed((Number) leftResult);
            }

            if (isAll)
            {
                return compareAll(leftResult, eventsPerStream, isNewData, exprEvaluatorContext);
            }
            else
            {
                return compareAny(leftResult, eventsPerStream, isNewData, exprEvaluatorContext);
            }
        }
    }

    private Object compareAll(Object leftResult, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
    {
        if (isNot)
        {
            int len = this.getChildNodes().length - 1;
            if ((len > 0) && (leftResult == null))
            {
                return null;
            }
            boolean hasNonNullRow = false;
            boolean hasNullRow = false;
            for (int i = 1; i <= len; i++)
            {
                Object rightResult = evaluators[i].evaluate(eventsPerStream, isNewData, exprEvaluatorContext);

                if (rightResult != null)
                {
                    hasNonNullRow = true;
                    if (!mustCoerce)
                    {
                        if (leftResult.equals(rightResult))
                        {
                            return false;
                        }
                    }
                    else
                    {
                        Number right = coercer.coerceBoxed((Number) rightResult);
                        if (leftResult.equals(right))
                        {
                            return false;
                        }
                    }
                }
                else
                {
                    hasNullRow = true;
                }
            }

            if ((!hasNonNullRow) || (hasNullRow))
            {
                return null;
            }
            return true;
        }
        else
        {
            int len = this.getChildNodes().length - 1;
            if ((len > 0) && (leftResult == null))
            {
                return null;
            }
            boolean hasNonNullRow = false;
            boolean hasNullRow = false;
            for (int i = 1; i <= len; i++)
            {
                Object rightResult = evaluators[i].evaluate(eventsPerStream, isNewData, exprEvaluatorContext);

                if (rightResult != null)
                {
                    hasNonNullRow = true;
                    if (!mustCoerce)
                    {
                        if (!leftResult.equals(rightResult))
                        {
                            return false;
                        }
                    }
                    else
                    {
                        Number right = coercer.coerceBoxed((Number) rightResult);
                        if (!leftResult.equals(right))
                        {
                            return false;
                        }
                    }
                }
                else
                {
                    hasNullRow = true;
                }
            }

            if ((!hasNonNullRow) || (hasNullRow))
            {
                return null;
            }
            return true;
        }
    }

    private Object compareAllColl(Object leftResult, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
    {
        if (isNot)
        {
            int len = this.getChildNodes().length - 1;
            boolean hasNonNullRow = false;
            boolean hasNullRow = false;
            for (int i = 1; i <= len; i++)
            {
                Object rightResult = evaluators[i].evaluate(eventsPerStream, isNewData, exprEvaluatorContext);

                if (rightResult == null)
                {
                    hasNullRow = true;
                    continue;
                }

                if (rightResult instanceof Collection)
                {
                    if (leftResult == null)
                    {
                        return null;
                    }
                    Collection coll = (Collection) rightResult;
                    if (coll.contains(leftResult))
                    {
                        return false;
                    }
                    hasNonNullRow = true;
                }
                else if (rightResult instanceof Map)
                {
                    if (leftResult == null)
                    {
                        return null;
                    }
                    Map coll = (Map) rightResult;
                    if (coll.containsKey(leftResult))
                    {
                        return false;
                    }
                    hasNonNullRow = true;
                }
                else if (rightResult.getClass().isArray())
                {
                    int arrayLength = Array.getLength(rightResult);
                    for (int index = 0; index < arrayLength; index++)
                    {
                        Object item = Array.get(rightResult, index);
                        if (item == null)
                        {
                            hasNullRow = true;
                            continue;
                        }
                        if (leftResult == null)
                        {
                            return null;
                        }
                        hasNonNullRow = true;
                        if (!mustCoerce)
                        {
                            if (leftResult.equals(item))
                            {
                                return false;
                            }
                        }
                        else
                        {
                            if (!(item instanceof Number))
                            {
                                continue;
                            }
                            Number left = coercer.coerceBoxed((Number) leftResult);
                            Number right = coercer.coerceBoxed((Number) item);
                            if (left.equals(right))
                            {
                                return false;
                            }
                        }
                    }
                }
                else
                {
                    if (leftResult == null)
                    {
                        return null;
                    }
                    if (!mustCoerce)
                    {
                        if (leftResult.equals(rightResult))
                        {
                            return false;
                        }
                    }
                    else
                    {
                        Number left = coercer.coerceBoxed((Number) leftResult);
                        Number right = coercer.coerceBoxed((Number) rightResult);
                        if (left.equals(right))
                        {
                            return false;
                        }
                    }
                }
            }

            if ((!hasNonNullRow) || (hasNullRow))
            {
                return null;
            }
            return true;
        }
        else
        {
            int len = this.getChildNodes().length - 1;
            boolean hasNonNullRow = false;
            boolean hasNullRow = false;
            for (int i = 1; i <= len; i++)
            {
                Object rightResult = evaluators[i].evaluate(eventsPerStream, isNewData, exprEvaluatorContext);

                if (rightResult == null)
                {
                    hasNullRow = true;
                    continue;
                }

                if (rightResult instanceof Collection)
                {
                    hasNonNullRow = true;
                    if (leftResult == null)
                    {
                        return null;
                    }
                    Collection coll = (Collection) rightResult;
                    if (!coll.contains(leftResult))
                    {
                        return false;
                    }
                }
                else if (rightResult instanceof Map)
                {
                    if (leftResult == null)
                    {
                        return null;
                    }
                    Map coll = (Map) rightResult;
                    if (!coll.containsKey(leftResult))
                    {
                        return false;
                    }
                    hasNonNullRow = true;
                }
                else if (rightResult.getClass().isArray())
                {
                    int arrayLength = Array.getLength(rightResult);
                    for (int index = 0; index < arrayLength; index++)
                    {
                        Object item = Array.get(rightResult, index);
                        if (item == null)
                        {
                            hasNullRow = true;
                            continue;
                        }
                        if (leftResult == null)
                        {
                            return null;
                        }
                        hasNonNullRow = true;
                        if (!mustCoerce)
                        {
                            if (!leftResult.equals(item))
                            {
                                return false;
                            }
                        }
                        else
                        {
                            if (!(item instanceof Number))
                            {
                                continue;
                            }
                            Number left = coercer.coerceBoxed((Number) leftResult);
                            Number right = coercer.coerceBoxed((Number) item);
                            if (!left.equals(right))
                            {
                                return false;
                            }
                        }
                    }
                }
                else
                {
                    if (leftResult == null)
                    {
                        return null;
                    }
                    if (!mustCoerce)
                    {
                        if (!leftResult.equals(rightResult))
                        {
                            return false;
                        }
                    }
                    else
                    {
                        Number left = coercer.coerceBoxed((Number) leftResult);
                        Number right = coercer.coerceBoxed((Number) rightResult);
                        if (!left.equals(right))
                        {
                            return false;
                        }
                    }
                }
            }

            if ((!hasNonNullRow) || (hasNullRow))
            {
                return null;
            }
            return true;
        }
    }

    private Object compareAny(Object leftResult, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
    {
        // Return true on the first not-equal.
        if (isNot)
        {
            boolean hasNonNullRow = false;
            boolean hasNullRow = false;
            int len = this.getChildNodes().length - 1;
            for (int i = 1; i <= len; i++)
            {
                Object rightResult = evaluators[i].evaluate(eventsPerStream, isNewData, exprEvaluatorContext);

                if (leftResult == null)
                {
                    return null;
                }
                if (rightResult == null)
                {
                    hasNullRow = true;
                    continue;
                }

                hasNonNullRow = true;
                if (!mustCoerce)
                {
                    if (!leftResult.equals(rightResult))
                    {
                        return true;
                    }
                }
                else
                {
                    Number right = coercer.coerceBoxed((Number) rightResult);
                    if (!leftResult.equals(right))
                    {
                        return true;
                    }
                }
            }

            if ((!hasNonNullRow) || (hasNullRow))
            {
                return null;
            }
            return false;
        }
        // Return true on the first equal.
        else
        {
            int len = this.getChildNodes().length - 1;
            if ((len > 0) && (leftResult == null))
            {
                return null;
            }
            boolean hasNonNullRow = false;
            boolean hasNullRow = false;
            for (int i = 1; i <= len; i++)
            {
                Object rightResult = evaluators[i].evaluate(eventsPerStream, isNewData, exprEvaluatorContext);

                if (rightResult == null)
                {
                    hasNullRow = true;
                    continue;
                }

                hasNonNullRow = true;
                if (!mustCoerce)
                {
                    if (leftResult.equals(rightResult))
                    {
                        return true;
                    }
                }
                else
                {
                    Number right = coercer.coerceBoxed((Number) rightResult);
                    if (leftResult.equals(right))
                    {
                        return true;
                    }
                }
            }

            if ((!hasNonNullRow) || (hasNullRow))
            {
                return null;
            }
            return false;
        }
    }

    private Object compareAnyColl(Object leftResult, EventBean[] eventsPerStream, boolean isNewData, ExprEvaluatorContext exprEvaluatorContext)
    {
        // Return true on the first not-equal.
        if (isNot)
        {
            int len = this.getChildNodes().length - 1;
            boolean hasNonNullRow = false;
            boolean hasNullRow = false;
            for (int i = 1; i <= len; i++)
            {
                Object rightResult = evaluators[i].evaluate(eventsPerStream, isNewData, exprEvaluatorContext);

                if (rightResult == null)
                {
                    hasNullRow = true;
                    continue;
                }

                if (rightResult instanceof Collection)
                {
                    if (leftResult == null)
                    {
                        return null;
                    }
                    Collection coll = (Collection) rightResult;
                    if (!coll.contains(leftResult))
                    {
                        return true;
                    }
                    hasNonNullRow = true;
                }
                else if (rightResult instanceof Map)
                {
                    if (leftResult == null)
                    {
                        return null;
                    }
                    Map coll = (Map) rightResult;
                    if (!coll.containsKey(leftResult))
                    {
                        return true;
                    }
                    hasNonNullRow = true;
                }
                else if (rightResult.getClass().isArray())
                {
                    int arrayLength = Array.getLength(rightResult);
                    if ((arrayLength > 0) && (leftResult == null))
                    {
                        return null;
                    }

                    for (int index = 0; index < arrayLength; index++)
                    {
                        Object item = Array.get(rightResult, index);
                        if (item == null)
                        {
                            hasNullRow = true;
                            continue;
                        }
                        hasNonNullRow = true;
                        if (!mustCoerce)
                        {
                            if (!leftResult.equals(item))
                            {
                                return true;
                            }
                        }
                        else
                        {
                            if (!(item instanceof Number))
                            {
                                continue;
                            }
                            Number left = coercer.coerceBoxed((Number) leftResult);
                            Number right = coercer.coerceBoxed((Number) item);
                            if (!left.equals(right))
                            {
                                return true;
                            }
                        }
                    }
                }
                else
                {
                    if (leftResult == null)
                    {
                        return null;
                    }
                    hasNonNullRow = true;
                    if (!mustCoerce)
                    {
                        if (!leftResult.equals(rightResult))
                        {
                            return true;
                        }
                    }
                    else
                    {
                        Number left = coercer.coerceBoxed((Number) leftResult);
                        Number right = coercer.coerceBoxed((Number) rightResult);
                        if (!left.equals(right))
                        {
                            return true;
                        }
                    }
                }
            }

            if ((!hasNonNullRow) || (hasNullRow))
            {
                return null;
            }
            return false;
        }
        // Return true on the first equal.
        else
        {
            int len = this.getChildNodes().length - 1;
            boolean hasNonNullRow = false;
            boolean hasNullRow = false;
            for (int i = 1; i <= len; i++)
            {
                Object rightResult = evaluators[i].evaluate(eventsPerStream, isNewData, exprEvaluatorContext);

                if (rightResult == null)
                {
                    hasNonNullRow = true;
                    continue;
                }
                if (rightResult instanceof Collection)
                {
                    if (leftResult == null)
                    {
                        return null;
                    }
                    hasNonNullRow = true;
                    Collection coll = (Collection) rightResult;
                    if (coll.contains(leftResult))
                    {
                        return true;
                    }
                }
                else if (rightResult instanceof Map)
                {
                    if (leftResult == null)
                    {
                        return null;
                    }
                    Map coll = (Map) rightResult;
                    if (coll.containsKey(leftResult))
                    {
                        return true;
                    }
                    hasNonNullRow = true;
                }
                else if (rightResult.getClass().isArray())
                {
                    int arrayLength = Array.getLength(rightResult);
                    if ((arrayLength > 0) && (leftResult == null))
                    {
                        return null;
                    }
                    for (int index = 0; index < arrayLength; index++)
                    {
                        Object item = Array.get(rightResult, index);
                        if (item == null)
                        {
                            hasNullRow = true;
                            continue;
                        }
                        hasNonNullRow = true;
                        if (!mustCoerce)
                        {
                            if (leftResult.equals(item))
                            {
                                return true;
                            }
                        }
                        else
                        {
                            if (!(item instanceof Number))
                            {
                                continue;
                            }
                            Number left = coercer.coerceBoxed((Number) leftResult);
                            Number right = coercer.coerceBoxed((Number) item);
                            if (left.equals(right))
                            {
                                return true;
                            }
                        }
                    }
                }
                else
                {
                    if (leftResult == null)
                    {
                        return null;
                    }
                    hasNonNullRow = true;
                    if (!mustCoerce)
                    {
                        if (leftResult.equals(rightResult))
                        {
                            return true;
                        }
                    }
                    else
                    {
                        Number left = coercer.coerceBoxed((Number) leftResult);
                        Number right = coercer.coerceBoxed((Number) rightResult);
                        if (left.equals(right))
                        {
                            return true;
                        }
                    }
                }
            }

            if ((!hasNonNullRow) || (hasNullRow))
            {
                return null;
            }
            return false;
        }
    }

    public void toPrecedenceFreeEPL(StringWriter writer) {
        this.getChildNodes()[0].toEPL(writer, getPrecedence());
        if (isAll) {
            if (isNot) {
                writer.append("!=all");
            }
            else {
                writer.append("=all");
            }
        }
        else {
            if (isNot) {
                writer.append("!=any");
            }
            else {
                writer.append("=any");
            }
        }
        writer.append("(");

        String delimiter = "";
        for (int i = 0; i < this.getChildNodes().length-1; i++)
        {
            writer.append(delimiter);
            this.getChildNodes()[i + 1].toEPL(writer, getPrecedence());
            delimiter = ",";
        }
        writer.append(")");
    }

    public ExprPrecedenceEnum getPrecedence() {
        return ExprPrecedenceEnum.EQUALS;
    }

    public boolean equalsNode(ExprNode node)
    {
        if (!(node instanceof ExprEqualsAllAnyNode))
        {
            return false;
        }

        ExprEqualsAllAnyNode other = (ExprEqualsAllAnyNode) node;
        return (other.isNot == this.isNot) && (other.isAll == this.isAll);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy