
org.apache.eagle.log.expression.ExpressionParser Maven / Gradle / Ivy
The newest version!
/*
* 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.eagle.log.expression;
import org.apache.eagle.log.base.taggedlog.TaggedLogAPIEntity;
import org.apache.eagle.log.entity.EntityQualifierUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import parsii.eval.Expression;
import parsii.eval.Parser;
import parsii.eval.Scope;
import parsii.eval.Variable;
import parsii.tokenizer.ParseException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* Expression Evaluation
*
* Given expression in string and set context variables, return value in double
*
*
*
* For example:
* EXP{(max(a, b)* min(a, b)) / abs(a-b+c-d)} => 600.0
*
*
*
* NOTE: Expression variable must be in format: fieldName
instead of @fieldName
*
*
*
* Dependencies:
*
* -
* scireum/parsii
* Super fast and simple evaluator for mathematical expressions written in Java
*
*
*
*/
public class ExpressionParser{
private final static Logger LOG = LoggerFactory.getLogger(ExpressionParser.class);
private String exprStr;
private Expression expression;
private Scope scope;
@SuppressWarnings("unused")
public Scope getScope() {
return scope;
}
private List dependentFields;
/**
* @param exprStr expression string in format like: (max(a, b)* min(a, b)) / abs(a-b+c-d)
*
* @throws ParseException
* @throws ParsiiInvalidException
*/
public ExpressionParser(String exprStr) throws ParseException, ParsiiInvalidException{
this.exprStr = exprStr;
scope = Scope.create();
expression = Parser.parse(this.exprStr,scope);
}
@SuppressWarnings("unused")
public ExpressionParser(String exprStr, Map context) throws ParsiiInvalidException, ParseException, ParsiiUnknowVariableException {
this(exprStr);
setVariables(context);
}
public ExpressionParser setVariables(Map tuple) throws ParsiiUnknowVariableException{
// for(String valName : tuple.keySet()) {
// Double value = tuple.get(valName);
for(Map.Entry entry : tuple.entrySet()) {
String valName = entry.getKey();
Double value = entry.getValue();
Variable variable = scope.getVariable(valName);
if(variable!=null && value !=null) {
variable.setValue(value);
}else{
if(LOG.isDebugEnabled()) LOG.warn("Variable for "+valName+" is null in scope of expression: "+this.exprStr);
}
}
return this;
}
@SuppressWarnings("unused")
public ExpressionParser setVariable(Entry tuple) throws ParsiiUnknowVariableException{
if (getDependentFields().contains(tuple.getKey())) {
scope.getVariable(tuple.getKey()).setValue(tuple.getValue());
}
else {
throw new ParsiiUnknowVariableException("unknown variable: " + tuple.getKey());
}
return this;
}
public ExpressionParser setVariable(String key, Double value) throws ParsiiUnknowVariableException{
scope.getVariable(key).setValue(value);
return this;
}
public double eval() throws Exception{
return expression.evaluate();
}
/**
* Thread safe
*
* @param tuple
* @return
* @throws ParsiiUnknowVariableException
*/
public double eval(Map tuple) throws Exception {
synchronized (this){
this.setVariables(tuple);
return this.eval();
}
}
public List getDependentFields() {
if (dependentFields == null) {
dependentFields = new ArrayList();
for (String variable : scope.getNames()) {
if (!variable.equals("pi") && !variable.equals("E") && !variable.equals("euler"))
dependentFields.add(variable);
}
}
return dependentFields;
}
private final static Map _exprParserCache = new HashMap();
/**
* Thread safe
*
* @param expr
* @return
* @throws ParsiiInvalidException
* @throws ParseException
*/
public static ExpressionParser parse(String expr) throws ParsiiInvalidException, ParseException {
if(expr == null) throw new IllegalStateException("Expression to parse is null");
synchronized (_exprParserCache) {
ExpressionParser parser = _exprParserCache.get(expr);
if (parser == null) {
parser = new ExpressionParser(expr);
_exprParserCache.put(expr, parser);
}
return parser;
}
}
public static double eval(String expression,Map context) throws Exception {
ExpressionParser parser = parse(expression);
return parser.eval(context);
}
private static final Map _entityMethodCache = new HashMap();
public static double eval(String expression,TaggedLogAPIEntity entity) throws Exception {
ExpressionParser parser = parse(expression);
List dependencies = parser.getDependentFields();
Map context = new HashMap();
for(String field:dependencies){
String methodName = "get"+field.substring(0, 1).toUpperCase() + field.substring(1);
String methodUID = entity.getClass().getName()+"."+methodName;
Method m;
synchronized (_entityMethodCache) {
m = _entityMethodCache.get(methodUID);
if (m == null) {
m = entity.getClass().getMethod(methodName);
_entityMethodCache.put(methodUID, m);
}
}
Object obj = m.invoke(entity);
Double doubleValue = EntityQualifierUtils.convertObjToDouble(obj);
// if(doubleValue == Double.NaN) throw new IllegalArgumentException("Field "+field+": "+obj+" in expression "+expression+" is not number");
context.put(field,doubleValue);
}
return parser.eval(context);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy