/* *************************************************************************************** * 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.view; import com.espertech.esper.client.EPException; import com.espertech.esper.client.EventType; import com.espertech.esper.core.context.util.AgentInstanceContext; import com.espertech.esper.core.service.ExprEvaluatorContextStatement; import com.espertech.esper.core.service.StatementContext; import com.espertech.esper.epl.core.StreamTypeService; import com.espertech.esper.epl.core.StreamTypeServiceImpl; import com.espertech.esper.epl.expression.core.*; import com.espertech.esper.epl.expression.visitor.ExprNodeSummaryVisitor; import com.espertech.esper.util.JavaClassHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; /** * Abstract base class for view factories that do not make re-useable views and that do * not share view resources with expression nodes. */ public abstract class ViewFactorySupport implements ViewFactory { private static Logger log = LoggerFactory.getLogger(ViewFactorySupport.class); public boolean canReuse(View view, AgentInstanceContext agentInstanceContext) { return false; } /** * Validate the view parameter expression and evaluate the expression returning the result object. * * @param viewName textual name of view * @param statementContext context with statement services * @param expression view expression parameter to validate * @return object result value of parameter expression * @throws ViewParameterException if the expressions fail to validate */ public static Object validateAndEvaluate(String viewName, StatementContext statementContext, ExprNode expression) throws ViewParameterException { return validateAndEvaluateExpr(viewName, statementContext, expression, new StreamTypeServiceImpl(statementContext.getEngineURI(), false), 0); } public static ExprNode[] validate(String viewName, StatementContext statementContext, List<ExprNode> expressions) throws ViewParameterException { ExprNode[] results = new ExprNode[expressions.size()]; int expressionNumber = 0; StreamTypeService streamTypeService = new StreamTypeServiceImpl(statementContext.getEngineURI(), false); for (ExprNode expr : expressions) { results[expressionNumber] = validateExpr(viewName, statementContext, expr, streamTypeService, expressionNumber); expressionNumber++; } return results; } /** * Validate the view parameter expressions and return the validated expression for later execution. * <p> * Does not evaluate the expression. * * @param viewName textual name of view * @param eventType is the event type of the parent view or stream attached. * @param statementContext context with statement services * @param expressions view expression parameter to validate * @param allowConstantResult true to indicate whether expressions that return a constant * result should be allowed; false to indicate that if an expression is known to return a constant result * the expression is considered invalid * @return object result value of parameter expressions * @throws ViewParameterException if the expressions fail to validate */ public static ExprNode[] validate(String viewName, EventType eventType, StatementContext statementContext, List<ExprNode> expressions, boolean allowConstantResult) throws ViewParameterException { List<ExprNode> results = new ArrayList<ExprNode>(); int expressionNumber = 0; StreamTypeService streamTypeService = new StreamTypeServiceImpl(eventType, null, false, statementContext.getEngineURI()); for (ExprNode expr : expressions) { ExprNode validated = validateExpr(viewName, statementContext, expr, streamTypeService, expressionNumber); results.add(validated); if ((!allowConstantResult) && (validated.isConstantResult())) { String message = "Invalid view parameter expression " + expressionNumber + getViewDesc(viewName) + ", the expression returns a constant result value, are you sure?"; log.error(message); throw new ViewParameterException(message); } expressionNumber++; } return results.toArray(new ExprNode[results.size()]); } /** * Assert and throws an exception if the expression passed returns a non-constant value. * * @param viewName textual name of view * @param expression expression to check * @param index number offset of expression in view parameters * @throws ViewParameterException if assertion fails */ public static void assertReturnsNonConstant(String viewName, ExprNode expression, int index) throws ViewParameterException { if (expression.isConstantResult()) { String message = "Invalid view parameter expression " + index + getViewDesc(viewName) + ", the expression returns a constant result value, are you sure?"; log.error(message); throw new ViewParameterException(message); } } public static Object evaluateAssertNoProperties(String viewName, ExprNode expression, int index, ExprEvaluatorContext exprEvaluatorContext) throws ViewParameterException { validateNoProperties(viewName, expression, index); return expression.getExprEvaluator().evaluate(null, false, exprEvaluatorContext); } public static void validateNoProperties(String viewName, ExprNode expression, int index) throws ViewParameterException { ExprNodeSummaryVisitor visitor = new ExprNodeSummaryVisitor(); expression.accept(visitor); if (!visitor.isPlain()) { String message = "Invalid view parameter expression " + index + getViewDesc(viewName) + ", " + visitor.getMessage() + " are not allowed within the expression"; throw new ViewParameterException(message); } } public static Object validateAndEvaluateExpr(String viewName, StatementContext statementContext, ExprNode expression, StreamTypeService streamTypeService, int expressionNumber) throws ViewParameterException { ExprNode validated = validateExpr(viewName, statementContext, expression, streamTypeService, expressionNumber); try { return validated.getExprEvaluator().evaluate(null, true, new ExprEvaluatorContextStatement(statementContext, false)); } catch (RuntimeException ex) { String message = "Failed to evaluate parameter expression " + expressionNumber + getViewDesc(viewName); if (ex.getMessage() != null) { message += ": " + ex.getMessage(); } log.error(message, ex); throw new ViewParameterException(message, ex); } } public static Object evaluate(ExprEvaluator evaluator, int expressionNumber, String viewName, StatementContext statementContext) throws ViewParameterException { try { return evaluator.evaluate(null, true, new ExprEvaluatorContextStatement(statementContext, false)); } catch (RuntimeException ex) { String message = "Failed to evaluate parameter expression " + expressionNumber + getViewDesc(viewName); if (ex.getMessage() != null) { message += ": " + ex.getMessage(); } log.error(message, ex); throw new ViewParameterException(message, ex); } } public static ExprNode validateExpr(String viewName, StatementContext statementContext, ExprNode expression, StreamTypeService streamTypeService, int expressionNumber) throws ViewParameterException { ExprNode validated; try { ExprEvaluatorContextStatement exprEvaluatorContext = new ExprEvaluatorContextStatement(statementContext, false); ExprValidationContext validationContext = new ExprValidationContext(streamTypeService, statementContext.getEngineImportService(), statementContext.getStatementExtensionServicesContext(), null, statementContext.getSchedulingService(), statementContext.getVariableService(), statementContext.getTableService(), exprEvaluatorContext, statementContext.getEventAdapterService(), statementContext.getStatementName(), statementContext.getStatementId(), statementContext.getAnnotations(), statementContext.getContextDescriptor(), false, false, false, false, null, false); validated = ExprNodeUtility.getValidatedSubtree(ExprNodeOrigin.VIEWPARAMETER, expression, validationContext); } catch (ExprValidationException ex) { String message = "Invalid parameter expression " + expressionNumber + getViewDesc(viewName); if (ex.getMessage() != null) { message += ": " + ex.getMessage(); } log.error(message, ex); throw new ViewParameterException(message, ex); } return validated; } private static String getViewDesc(String viewName) { return " for " + viewName + " view"; } public static ExprEvaluator validateSizeSingleParam(String viewName, ViewFactoryContext viewFactoryContext, List<ExprNode> expressionParameters) throws ViewParameterException { ExprNode[] validated = ViewFactorySupport.validate(viewName, viewFactoryContext.getStatementContext(), expressionParameters); if (validated.length != 1) { throw new ViewParameterException(getViewParamMessage(viewName)); } return validateSizeParam(viewName, viewFactoryContext.getStatementContext(), validated[0], 0); } public static ExprEvaluator validateSizeParam(String viewName, StatementContext statementContext, ExprNode sizeNode, int expressionNumber) throws ViewParameterException { ExprEvaluator sizeEvaluator = sizeNode.getExprEvaluator(); Class returnType = JavaClassHelper.getBoxedType(sizeEvaluator.getType()); if (!JavaClassHelper.isNumeric(returnType) || JavaClassHelper.isFloatingPointClass(returnType) || returnType == Long.class) { throw new ViewParameterException(getViewParamMessage(viewName)); } if (sizeNode.isConstantResult()) { Number size = (Number) ViewFactorySupport.evaluate(sizeEvaluator, expressionNumber, viewName, statementContext); if (!validateSize(size)) { throw new ViewParameterException(getSizeValidationMsg(viewName, size)); } } return sizeEvaluator; } public static int evaluateSizeParam(String viewName, ExprEvaluator sizeEvaluator, AgentInstanceContext context) { Number size = (Number) sizeEvaluator.evaluate(null, true, context); if (!validateSize(size)) { throw new EPException(getSizeValidationMsg(viewName, size)); } return size.intValue(); } private static boolean validateSize(Number size) { return !(size == null || size.intValue() <= 0); } private static String getViewParamMessage(String viewName) { return viewName + " view requires a single integer-type parameter"; } private static String getSizeValidationMsg(String viewName, Number size) { return viewName + " view requires a positive integer for size but received " + size; } public static void validateNoParameters(String viewName, List<ExprNode> expressionParameters) throws ViewParameterException { if (!expressionParameters.isEmpty()) { String errorMessage = viewName + " view requires an empty parameter list"; throw new ViewParameterException(errorMessage); } } }