/* * ************************************************************************************* * 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.methodbase; import com.espertech.esper.epl.enummethod.dot.ExprLambdaGoesNode; import com.espertech.esper.epl.expression.ExprNode; import com.espertech.esper.epl.expression.ExprStreamUnderlyingNode; import com.espertech.esper.epl.expression.ExprTimePeriod; import com.espertech.esper.epl.expression.ExprValidationException; import com.espertech.esper.util.JavaClassHelper; import java.io.StringWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; public class DotMethodUtil { public static DotMethodFPProvided getProvidedFootprint(List<ExprNode> parameters) { List<DotMethodFPProvidedParam> paramsList = new ArrayList<DotMethodFPProvidedParam>(); for (ExprNode node : parameters) { if (!(node instanceof ExprLambdaGoesNode)) { paramsList.add(new DotMethodFPProvidedParam(0, node.getExprEvaluator().getType(), node)); continue; } ExprLambdaGoesNode goesNode = (ExprLambdaGoesNode) node; paramsList.add(new DotMethodFPProvidedParam(goesNode.getGoesToNames().size(), null, goesNode)); } return new DotMethodFPProvided(paramsList.toArray(new DotMethodFPProvidedParam[paramsList.size()])); } public static DotMethodFP validateParametersDetermineFootprint(DotMethodFP[] footprints, DotMethodTypeEnum methodType, String methodUsedName, DotMethodFPProvided providedFootprint, DotMethodInputTypeMatcher inputTypeMatcher) throws ExprValidationException { boolean isLambdaApplies = DotMethodTypeEnum.ENUM == methodType; // determine footprint candidates strictly based on parameters List<DotMethodFP> candidates = null; DotMethodFP bestMatch = null; for (DotMethodFP footprint : footprints) { DotMethodFPParam[] requiredParams = footprint.getParameters(); if (requiredParams.length != providedFootprint.getParameters().length) { continue; } if (bestMatch == null) { // take first if number of parameters matches bestMatch = footprint; } boolean paramMatch = true; int count = 0; for (DotMethodFPParam requiredParam : requiredParams) { DotMethodFPProvidedParam providedParam = providedFootprint.getParameters()[count++]; if (requiredParam.getLambdaParamNum() != providedParam.getLambdaParamNum()) { paramMatch = false; } } if (paramMatch) { if (candidates == null) { candidates = new ArrayList<DotMethodFP>(2); } candidates.add(footprint); } } // if there are multiple candidates, eliminate by input (event bean collection or component collection) if (candidates != null && candidates.size() > 1) { Iterator<DotMethodFP> candidateIt = candidates.iterator(); for (;candidateIt.hasNext();) { DotMethodFP fp = candidateIt.next(); if (!inputTypeMatcher.matches(fp)) { candidateIt.remove(); } } } // handle single remaining candidate if (candidates != null && candidates.size() == 1) { DotMethodFP found = candidates.get(0); validateSpecificTypes(methodUsedName, methodType, found.getParameters(), providedFootprint.getParameters()); return found; } // check all candidates in detail to see which one matches, take first one if (candidates != null && !candidates.isEmpty()) { bestMatch = candidates.get(0); Iterator<DotMethodFP> candidateIt = candidates.iterator(); ExprValidationException firstException = null; for (;candidateIt.hasNext();) { DotMethodFP fp = candidateIt.next(); try { validateSpecificTypes(methodUsedName, methodType, fp.getParameters(), providedFootprint.getParameters()); return fp; } catch (ExprValidationException ex) { if (firstException == null) { firstException = ex; } } } if (firstException != null) { throw firstException; } } String message = "Parameters mismatch for " + methodType.getTypeName() + " method '" + methodUsedName + "', the method "; if (bestMatch != null) { StringWriter buf = new StringWriter(); buf.append(bestMatch.toStringFootprint(isLambdaApplies)); buf.append(", but receives "); buf.append(DotMethodFP.toStringProvided(providedFootprint, isLambdaApplies)); throw new ExprValidationException(message + "requires " + buf.toString()); } if (footprints.length == 1) { throw new ExprValidationException(message + "requires " + footprints[0].toStringFootprint(isLambdaApplies)); } else { StringWriter buf = new StringWriter(); String delimiter = ""; for (DotMethodFP footprint : footprints) { buf.append(delimiter); buf.append(footprint.toStringFootprint(isLambdaApplies)); delimiter = ", or "; } throw new ExprValidationException(message + "has multiple footprints accepting " + buf + ", but receives " + DotMethodFP.toStringProvided(providedFootprint, isLambdaApplies)); } } private static void validateSpecificTypes(String methodUsedName, DotMethodTypeEnum type, DotMethodFPParam[] foundParams, DotMethodFPProvidedParam[] parameters) throws ExprValidationException { for (int i = 0; i < foundParams.length; i++) { DotMethodFPParam found = foundParams[i]; DotMethodFPProvidedParam provided = parameters[i]; // Lambda-type expressions not validated here if (found.getLambdaParamNum() > 0) { continue; } validateSpecificType(methodUsedName, type, found.getType(), found.getSpecificType(), provided.getReturnType(), i, provided.getExpression()); } } public static void validateSpecificType(String methodUsedName, DotMethodTypeEnum type, DotMethodFPParamTypeEnum expectedTypeEnum, Class expectedTypeClass, Class providedType, int parameterNum, ExprNode parameterExpression) throws ExprValidationException { String message = "Error validating " + type.getTypeName() + " method '" + methodUsedName + "', "; if (expectedTypeEnum == DotMethodFPParamTypeEnum.BOOLEAN && (!JavaClassHelper.isBoolean(providedType))) { throw new ExprValidationException(message + "expected a boolean-type result for expression parameter " + parameterNum + " but received " + JavaClassHelper.getClassNameFullyQualPretty(providedType)); } if (expectedTypeEnum == DotMethodFPParamTypeEnum.NUMERIC && (!JavaClassHelper.isNumeric(providedType))) { throw new ExprValidationException(message + "expected a number-type result for expression parameter " + parameterNum + " but received " + JavaClassHelper.getClassNameFullyQualPretty(providedType)); } if (expectedTypeEnum == DotMethodFPParamTypeEnum.SPECIFIC) { Class boxedExpectedType = JavaClassHelper.getBoxedType(expectedTypeClass); Class boxedProvidedType = JavaClassHelper.getBoxedType(providedType); if (!JavaClassHelper.isSubclassOrImplementsInterface(boxedProvidedType, boxedExpectedType)) { throw new ExprValidationException(message + "expected a " + boxedExpectedType.getSimpleName() + "-type result for expression parameter " + parameterNum + " but received " + JavaClassHelper.getClassNameFullyQualPretty(providedType)); } } if (expectedTypeEnum == DotMethodFPParamTypeEnum.TIME_PERIOD_OR_SEC) { if (parameterExpression instanceof ExprTimePeriod || parameterExpression instanceof ExprStreamUnderlyingNode) { return; } if (!(JavaClassHelper.isNumeric(providedType))) { throw new ExprValidationException(message + "expected a time-period expression or a numeric-type result for expression parameter " + parameterNum + " but received " + JavaClassHelper.getClassNameFullyQualPretty(providedType)); } } if (expectedTypeEnum == DotMethodFPParamTypeEnum.DATETIME) { if (!(JavaClassHelper.isDatetimeClass(providedType))) { throw new ExprValidationException(message + "expected a long-typed, Date-typed or Calendar-typed result for expression parameter " + parameterNum + " but received " + JavaClassHelper.getClassNameFullyQualPretty(providedType)); } } } }