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

com.espertech.esper.epl.declexpr.ExprDeclaredNodeImpl Maven / Gradle / Ivy

The 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.epl.declexpr;

import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.EventPropertyGetter;
import com.espertech.esper.client.EventType;
import com.espertech.esper.client.PropertyAccessException;
import com.espertech.esper.client.annotation.AuditEnum;
import com.espertech.esper.collection.Pair;
import com.espertech.esper.core.context.util.ContextDescriptor;
import com.espertech.esper.epl.core.streamtype.StreamTypeService;
import com.espertech.esper.epl.core.streamtype.StreamTypeServiceImpl;
import com.espertech.esper.epl.enummethod.dot.ExprDeclaredOrLambdaNode;
import com.espertech.esper.epl.expression.core.*;
import com.espertech.esper.epl.expression.visitor.ExprNodeIdentVisitorWParent;
import com.espertech.esper.epl.expression.visitor.ExprNodeSummaryVisitor;
import com.espertech.esper.epl.expression.visitor.ExprNodeVisitor;
import com.espertech.esper.epl.expression.visitor.ExprNodeVisitorWithParent;
import com.espertech.esper.epl.spec.ExpressionDeclItem;
import com.espertech.esper.epl.util.ExprNodeUtilityRich;
import com.espertech.esper.epl.expression.core.ExprFilterSpecLookupable;
import com.espertech.esper.util.SerializableObjectCopier;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Expression instance as declared elsewhere.
 */
public class ExprDeclaredNodeImpl extends ExprNodeBase implements ExprDeclaredNode, ExprDeclaredOrLambdaNode, ExprFilterOptimizableNode, ExprNodeInnerNodeProvider, ExprConstantNode {
    private static final long serialVersionUID = 9140100131374697808L;

    private final ExpressionDeclItem prototype;
    private List chainParameters;
    private transient ExprForge forge;
    private ExprNode expressionBodyCopy;

    public ExprDeclaredNodeImpl(ExpressionDeclItem prototype, List chainParameters, ContextDescriptor contextDescriptor) {
        this.prototype = prototype;
        this.chainParameters = chainParameters;

        // copy expression - we do it at this time and not later
        try {
            expressionBodyCopy = (ExprNode) SerializableObjectCopier.copy(prototype.getInner());
        } catch (Exception e) {
            throw new RuntimeException("Internal error providing expression tree: " + e.getMessage(), e);
        }

        // replace context-properties where they are currently identifiers
        if (contextDescriptor == null) {
            return;
        }
        ExprNodeIdentVisitorWParent visitorWParent = new ExprNodeIdentVisitorWParent();
        expressionBodyCopy.accept(visitorWParent);
        for (Pair pair : visitorWParent.getIdentNodes()) {
            String streamOrProp = pair.getSecond().getStreamOrPropertyName();
            if (streamOrProp != null && contextDescriptor.getContextPropertyRegistry().isContextPropertyPrefix(streamOrProp)) {
                ExprContextPropertyNodeImpl context = new ExprContextPropertyNodeImpl(pair.getSecond().getUnresolvedPropertyName());
                if (pair.getFirst() == null) {
                    expressionBodyCopy = context;
                } else {
                    ExprNodeUtilityCore.replaceChildNode(pair.getFirst(), pair.getSecond(), context);
                }
            }
        }
    }

    public ExprForge getForge() {
        checkValidated(forge);
        return forge;
    }

    public ExprNode getBody() {
        return expressionBodyCopy;
    }

    public List getAdditionalNodes() {
        return chainParameters;
    }

    public boolean validated() {
        return forge != null;
    }

    public Class getConstantType() {
        checkValidated(forge);
        return forge.getEvaluationType();
    }

    public Object getConstantValue(ExprEvaluatorContext context) {
        return forge.getExprEvaluator().evaluate(null, true, context);
    }

    public boolean isConstantValue() {
        return expressionBodyCopy.isConstantResult();
    }

    public LinkedHashMap getOuterStreamNames(Map outerStreamNames) throws ExprValidationException {
        checkParameterCount();

        // determine stream ids for each parameter
        LinkedHashMap streamParameters = new LinkedHashMap();
        for (int param = 0; param < chainParameters.size(); param++) {
            if (!(chainParameters.get(param) instanceof ExprIdentNode)) {
                throw new ExprValidationException("Sub-selects in an expression declaration require passing only stream names as parameters");
            }
            String parameterName = ((ExprIdentNode) chainParameters.get(param)).getUnresolvedPropertyName();
            Integer streamIdFound = outerStreamNames.get(parameterName);
            if (streamIdFound == null) {
                throw new ExprValidationException("Failed validation of expression declaration '" + prototype.getName() + "': Invalid parameter to expression declaration, parameter " + param + " is not the name of a stream in the query");
            }
            String prototypeName = prototype.getParametersNames().get(param);
            streamParameters.put(prototypeName, streamIdFound);
        }
        return streamParameters;
    }

    public ExprNode validate(ExprValidationContext validationContext) throws ExprValidationException {
        if (prototype.isAlias()) {
            try {
                expressionBodyCopy = ExprNodeUtilityRich.getValidatedSubtree(ExprNodeOrigin.ALIASEXPRBODY, expressionBodyCopy, validationContext);
            } catch (ExprValidationException ex) {
                String message = "Error validating expression alias '" + prototype.getName() + "': " + ex.getMessage();
                throw new ExprValidationException(message, ex);
            }

            forge = expressionBodyCopy.getForge();
            return null;
        }

        if (forge != null) {
            return null; // already evaluated
        }

        if (this.getChildNodes().length > 0) {
            throw new IllegalStateException("Execution node has its own child nodes");
        }

        // validate chain
        List validated = new ArrayList();
        for (ExprNode expr : chainParameters) {
            validated.add(ExprNodeUtilityRich.getValidatedSubtree(ExprNodeOrigin.DECLAREDEXPRPARAM, expr, validationContext));
        }
        chainParameters = validated;

        // validate parameter count
        checkParameterCount();

        // create context for expression body
        EventType[] eventTypes = new EventType[prototype.getParametersNames().size()];
        String[] streamNames = new String[prototype.getParametersNames().size()];
        boolean[] isIStreamOnly = new boolean[prototype.getParametersNames().size()];
        int[] streamsIdsPerStream = new int[prototype.getParametersNames().size()];
        boolean allStreamIdsMatch = true;

        for (int i = 0; i < prototype.getParametersNames().size(); i++) {
            ExprNode parameter = chainParameters.get(i);
            streamNames[i] = prototype.getParametersNames().get(i);

            if (parameter instanceof ExprStreamUnderlyingNode) {
                ExprStreamUnderlyingNode und = (ExprStreamUnderlyingNode) parameter;
                eventTypes[i] = validationContext.getStreamTypeService().getEventTypes()[und.getStreamId()];
                isIStreamOnly[i] = validationContext.getStreamTypeService().getIStreamOnly()[und.getStreamId()];
                streamsIdsPerStream[i] = und.getStreamId();
            } else if (parameter instanceof ExprWildcard) {
                if (validationContext.getStreamTypeService().getEventTypes().length != 1) {
                    throw new ExprValidationException("Expression '" + prototype.getName() + "' only allows a wildcard parameter if there is a single stream available, please use a stream or tag name instead");
                }
                eventTypes[i] = validationContext.getStreamTypeService().getEventTypes()[0];
                isIStreamOnly[i] = validationContext.getStreamTypeService().getIStreamOnly()[0];
                streamsIdsPerStream[i] = 0;
            } else {
                throw new ExprValidationException("Expression '" + prototype.getName() + "' requires a stream name as a parameter");
            }

            if (streamsIdsPerStream[i] != i) {
                allStreamIdsMatch = false;
            }
        }

        StreamTypeService streamTypeService = validationContext.getStreamTypeService();
        StreamTypeServiceImpl copyTypes = new StreamTypeServiceImpl(eventTypes, streamNames, isIStreamOnly, streamTypeService.getEngineURIQualifier(), streamTypeService.isOnDemandStreams(), streamTypeService.isOptionalStreams());
        copyTypes.setRequireStreamNames(true);

        // validate expression body in this context
        try {
            ExprValidationContext expressionBodyContext = new ExprValidationContext(copyTypes, validationContext);
            expressionBodyCopy = ExprNodeUtilityRich.getValidatedSubtree(ExprNodeOrigin.DECLAREDEXPRBODY, expressionBodyCopy, expressionBodyContext);
        } catch (ExprValidationException ex) {
            String message = "Error validating expression declaration '" + prototype.getName() + "': " + ex.getMessage();
            throw new ExprValidationException(message, ex);
        }

        // analyze child node
        ExprNodeSummaryVisitor summaryVisitor = new ExprNodeSummaryVisitor();
        expressionBodyCopy.accept(summaryVisitor);
        boolean isCache = !(summaryVisitor.isHasAggregation() || summaryVisitor.isHasPreviousPrior());
        isCache &= validationContext.getExprEvaluatorContext().getExpressionResultCacheService().isDeclaredExprCacheEnabled();

        // determine a suitable evaluation
        boolean audit = AuditEnum.EXPRDEF.getAudit(validationContext.getAnnotations()) != null;
        String engineURI = validationContext.getStreamTypeService().getEngineURIQualifier();
        String statementName = validationContext.getStatementName();
        if (expressionBodyCopy.isConstantResult()) {
            // pre-evaluated
            forge = new ExprDeclaredForgeConstant(this, expressionBodyCopy.getForge().getEvaluationType(), prototype, expressionBodyCopy.getForge().getExprEvaluator().evaluate(null, true, null), audit, engineURI, statementName);
        } else if (prototype.getParametersNames().isEmpty() ||
                (allStreamIdsMatch && prototype.getParametersNames().size() == streamTypeService.getEventTypes().length)) {
            forge = new ExprDeclaredForgeNoRewrite(this, expressionBodyCopy.getForge(), isCache, audit, engineURI, statementName);
        } else {
            forge = new ExprDeclaredForgeRewrite(this, expressionBodyCopy.getForge(), isCache, streamsIdsPerStream, audit, engineURI, statementName);
        }
        return null;
    }

    public boolean getFilterLookupEligible() {
        return true;
    }

    public ExprFilterSpecLookupable getFilterLookupable() {
        if (!(forge instanceof ExprDeclaredForgeBase)) {
            return null;
        }
        ExprDeclaredForgeBase declaredForge = (ExprDeclaredForgeBase) forge;
        ExprEvaluator evaluator = declaredForge.getInnerForge().getExprEvaluator();
        return new ExprFilterSpecLookupable(ExprNodeUtilityCore.toExpressionStringMinPrecedenceSafe(this), new DeclaredNodeEventPropertyGetter(evaluator), forge.getEvaluationType(), true);
    }

    public boolean isConstantResult() {
        return false;
    }

    public boolean equalsNode(ExprNode node, boolean ignoreStreamPrefix) {
        if (!(node instanceof ExprDeclaredNodeImpl)) {
            return false;
        }

        ExprDeclaredNodeImpl otherExprCaseNode = (ExprDeclaredNodeImpl) node;
        return ExprNodeUtilityCore.deepEquals(expressionBodyCopy, otherExprCaseNode, false);
    }

    public void accept(ExprNodeVisitor visitor) {
        super.accept(visitor);
        if (this.getChildNodes().length == 0) {
            expressionBodyCopy.accept(visitor);
        }
    }

    public void accept(ExprNodeVisitorWithParent visitor) {
        super.accept(visitor);
        if (this.getChildNodes().length == 0) {
            expressionBodyCopy.accept(visitor);
        }
    }

    public void acceptChildnodes(ExprNodeVisitorWithParent visitor, ExprNode parent) {
        super.acceptChildnodes(visitor, parent);
        if (visitor.isVisit(this) && this.getChildNodes().length == 0) {
            expressionBodyCopy.accept(visitor);
        }
    }

    public ExprNode getExpressionBodyCopy() {
        return expressionBodyCopy;
    }

    public ExpressionDeclItem getPrototype() {
        return prototype;
    }

    public List getChainParameters() {
        return chainParameters;
    }

    public ExprEvaluator getExprEvaluator() {
        checkValidated(forge);
        return forge.getExprEvaluator();
    }

    private void checkParameterCount() throws ExprValidationException {
        if (chainParameters.size() != prototype.getParametersNames().size()) {
            throw new ExprValidationException("Parameter count mismatches for declared expression '" + prototype.getName() + "', expected " +
                    prototype.getParametersNames().size() + " parameters but received " + chainParameters.size() + " parameters");
        }
    }

    public void toPrecedenceFreeEPL(StringWriter writer) {
        writer.append(prototype.getName());

        if (prototype.isAlias()) {
            return;
        }

        writer.append("(");
        String delimiter = "";
        for (ExprNode parameter : chainParameters) {
            writer.append(delimiter);
            parameter.toEPL(writer, ExprPrecedenceEnum.MINIMUM);
            delimiter = ",";
        }
        writer.append(")");
    }

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

    private final static class DeclaredNodeEventPropertyGetter implements EventPropertyGetter {
        private final ExprEvaluator exprEvaluator;

        private DeclaredNodeEventPropertyGetter(ExprEvaluator exprEvaluator) {
            this.exprEvaluator = exprEvaluator;
        }

        public Object get(EventBean eventBean) throws PropertyAccessException {
            EventBean[] events = new EventBean[1];
            events[0] = eventBean;
            return exprEvaluator.evaluate(events, true, null);
        }

        public boolean isExistsProperty(EventBean eventBean) {
            return false;
        }

        public Object getFragment(EventBean eventBean) throws PropertyAccessException {
            return null;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy