/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.nifi.attribute.expression.language.evaluation.functions; import org.apache.nifi.attribute.expression.language.evaluation.Evaluator; import org.apache.nifi.attribute.expression.language.evaluation.NumberEvaluator; import org.apache.nifi.attribute.expression.language.evaluation.NumberQueryResult; import org.apache.nifi.attribute.expression.language.evaluation.QueryResult; import org.apache.nifi.attribute.expression.language.exception.AttributeExpressionLanguageException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; public class MathEvaluator extends NumberEvaluator { private final Evaluator<Number> subject; private final Evaluator<String> methodName; private final Evaluator<Number> optionalArg; public MathEvaluator(final Evaluator<Number> subject, final Evaluator<String> methodName, final Evaluator<Number> optionalArg) { this.subject = subject; this.methodName = methodName; this.optionalArg = optionalArg; } @Override public QueryResult<Number> evaluate(final Map<String, String> attributes) { final String methodNamedValue = methodName.evaluate(attributes).getValue(); if (methodNamedValue == null) { return new NumberQueryResult(null); } final Number subjectValue; if(subject != null) { subjectValue = subject.evaluate(attributes).getValue(); if(subjectValue == null){ return new NumberQueryResult(null); } } else { subjectValue = null; } final Number optionalArgValue; if(optionalArg != null) { optionalArgValue = optionalArg.evaluate(attributes).getValue(); if(optionalArgValue == null) { return new NumberQueryResult(null); } } else { optionalArgValue = null; } try { Number executionValue = null; if (subjectValue == null){ Method method; try { method = Math.class.getMethod(methodNamedValue); } catch (NoSuchMethodException subjectlessNoMethodException) { throw new AttributeExpressionLanguageException("Cannot evaluate 'math' function because no subjectless method was found with the name:'" + methodNamedValue + "'", subjectlessNoMethodException); } if(method == null) { throw new AttributeExpressionLanguageException("Cannot evaluate 'math' function because no subjectless method was found with the name:'" + methodNamedValue + "'"); } executionValue = (Number) method.invoke(null); } else if(optionalArg == null) { boolean subjectIsDecimal = subjectValue instanceof Double; Method method; try { method = Math.class.getMethod(methodNamedValue, subjectIsDecimal ? double.class : long.class); } catch (NoSuchMethodException noOptionalNoMethodException){ throw new AttributeExpressionLanguageException("Cannot evaluate 'math' function because no method was found matching the passed parameters:" + " name:'" + methodNamedValue + "', one argument of type: '" + (subjectIsDecimal ? "double" : "long")+"'", noOptionalNoMethodException); } if(method == null) { throw new AttributeExpressionLanguageException("Cannot evaluate 'math' function because no method was found matching the passed parameters:" + " name:'" + methodNamedValue + "', one argument of type: '" + (subjectIsDecimal ? "double" : "long")+"'"); } if (subjectIsDecimal){ executionValue = (Number) method.invoke(null, subjectValue.doubleValue()); } else { executionValue = (Number) method.invoke(null, subjectValue.longValue()); } } else { boolean subjectIsDecimal = subjectValue instanceof Double; boolean optionalArgIsDecimal = optionalArgValue instanceof Double; Method method; boolean convertOptionalToInt = false; try { method = Math.class.getMethod(methodNamedValue, subjectIsDecimal ? double.class : long.class, optionalArgIsDecimal ? double.class : long.class); } catch (NoSuchMethodException withOptionalNoMethodException) { if (!optionalArgIsDecimal) { try { method = Math.class.getMethod(methodNamedValue, subjectIsDecimal ? double.class : long.class, int.class); } catch (NoSuchMethodException withOptionalInnerNoMethodException) { throw new AttributeExpressionLanguageException("Cannot evaluate 'math' function because no method was found matching the passed parameters: " + "name:'" + methodNamedValue + "', first argument type: '" + (subjectIsDecimal ? "double" : "long") + "', second argument type: 'long'", withOptionalInnerNoMethodException); } convertOptionalToInt = true; } else { throw new AttributeExpressionLanguageException("Cannot evaluate 'math' function because no method was found matching the passed parameters: " + "name:'" + methodNamedValue + "', first argument type: '" + (subjectIsDecimal ? "double" : "long") + "', second argument type: 'double'", withOptionalNoMethodException); } } if(method == null) { throw new AttributeExpressionLanguageException("Cannot evaluate 'math' function because no method was found matching the passed parameters: " + "name:'" + methodNamedValue + "', first argument type: '" + (subjectIsDecimal ? "double" : "long") + "', second argument type: '" + (optionalArgIsDecimal ? "double" : "long") + "'"); } if (optionalArgIsDecimal) { executionValue = (Number) method.invoke(null, subjectValue, optionalArgValue.doubleValue()); } else { if (convertOptionalToInt) { executionValue = (Number) method.invoke(null, subjectValue, optionalArgValue.intValue()); } else { executionValue = (Number) method.invoke(null, subjectValue, optionalArgValue.longValue()); } } } return new NumberQueryResult(executionValue); } catch (IllegalAccessException | InvocationTargetException e) { throw new AttributeExpressionLanguageException("Unable to calculate math function value", e); } } @Override public Evaluator<?> getSubjectEvaluator() { return subject; } }