fr.ird.observe.dto.referential.FormulaHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of common-dto Show documentation
Show all versions of common-dto Show documentation
ObServe Toolkit Common Dto module
package fr.ird.observe.dto.referential;
/*-
* #%L
* ObServe Toolkit :: Common Dto
* %%
* Copyright (C) 2017 - 2020 IRD, Ultreia.io
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* .
* #L%
*/
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.nuiton.util.NumberUtil;
import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created on 05/11/16.
*
* @author Tony Chemit - [email protected]
* @since 6.0
*/
public class FormulaHelper {
/** Logger */
private static final Logger log = LogManager.getLogger(FormulaHelper.class);
private static final Pattern COEFFICIENTS_PATTERN = Pattern.compile("(.+)=(.+)");
/** variable weight à utiliser dans la relation taille */
public static final String VARIABLE_WEIGHT = "P";
/** variable taille à utiliser dans la relation weight */
public static final String VARIABLE_LENGTH = "L";
private static final String VARIABLE_X = "x";
public static final String VARIABLE_INPUT = "I";
public static final String VARIABLE_OUTPUT = "O";
public static final String COEFFICIENT_A = "a";
public static final String COEFFICIENT_B = "b";
/** moteur d'évaluation d'expression */
private static ScriptEngine scriptEngine;
private static ScriptEngine getScriptEngine() {
if (scriptEngine == null) {
ScriptEngineManager factory = new ScriptEngineManager();
scriptEngine = factory.getEngineByExtension("js");
}
return scriptEngine;
}
public static Map getCoefficientValues(WithFormula parametrage) {
Map result = new TreeMap<>();
String coefficients = parametrage.getCoefficients();
if (coefficients != null) {
for (String coefficientDef : coefficients.split(":")) {
Matcher matcher = COEFFICIENTS_PATTERN.matcher(coefficientDef.trim());
if (log.isDebugEnabled()) {
log.debug("constant to test = " + coefficientDef);
}
if (matcher.matches()) {
String key = matcher.group(1);
String val = matcher.group(2);
try {
Double d = Double.valueOf(val);
result.put(key, d);
if (log.isDebugEnabled()) {
log.debug("detects coefficient " + key + '=' + val);
}
} catch (NumberFormatException e) {
// pas pu recupere le count...
if (log.isWarnEnabled()) {
log.warn("could not parse double " + val + " for coefficient " + key);
}
}
}
}
}
return result;
}
public static boolean validateRelation(WithFormula parametrage, String relation, String variable) {
boolean result = false;
if (!StringUtils.isEmpty(relation)) {
Map coeffs = parametrage.getCoefficientValues();
ScriptEngine engine = getScriptEngine();
Bindings bindings = engine.createBindings();
addBindings(coeffs, bindings, variable, 1);
try {
engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
Double o = (Double) engine.eval("parseFloat(" + relation + ")");
if (log.isDebugEnabled()) {
log.debug("evaluation ok : " + relation + " (" + variable + "=1) = " + o);
}
result = true;
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug("evaluation ko : " + relation + ", reason : " + e.getMessage());
}
}
}
return result;
}
public static boolean validateObjectMaterialValidation(String relation, Object value) {
boolean result = false;
if (!StringUtils.isEmpty(relation)) {
ScriptEngine engine = getScriptEngine();
Bindings bindings = engine.createBindings();
bindings.put(FormulaHelper.VARIABLE_X, value);
try {
engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
Boolean o = (Boolean) engine.eval(relation);
if (log.isDebugEnabled()) {
log.debug(String.format("evaluation ok : %s (%s=%s) = %s", relation, FormulaHelper.VARIABLE_X, value, o));
}
result = o != null && o;
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug("evaluation ko : " + relation + ", reason : " + e.getMessage());
}
}
}
return result;
}
public static boolean validateObjectMaterialValidationSyntax(String relation, Object value) {
if (!StringUtils.isEmpty(relation)) {
ScriptEngine engine = getScriptEngine();
Bindings bindings = engine.createBindings();
bindings.put(FormulaHelper.VARIABLE_X, value);
try {
engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
Boolean o = (Boolean) engine.eval(relation);
log.debug(String.format("evaluation ok : %s (%s=%s) = %s", relation, FormulaHelper.VARIABLE_X, value, o));
return true;
} catch (Exception e) {
log.debug(String.format("evaluation ko : %s, reason : %s", relation, e.getMessage()));
return false;
}
}
return false;
}
public static Float computeValue(WithFormula parametrage, String formula, String coefficientName, String variableName, float data) {
if (coefficientName != null) {
Double b = parametrage.getCoefficientValue(coefficientName);
if (b == 0) {
// ce cas limite ne permet pas de calculer la taille a partir du weight
return null;
}
}
Float o = computeValue(parametrage, formula, variableName, data);
if (o != null) {
o = NumberUtil.roundOneDigit(o);
}
return o;
}
private static Float computeValue(WithFormula parametrage, String relation, String variable, float taille) {
Map coeffs = parametrage.getCoefficientValues();
ScriptEngine engine = getScriptEngine();
Bindings bindings = engine.createBindings();
addBindings(coeffs, bindings, variable, taille);
engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
Double o = null;
try {
o = (Double) engine.eval("parseFloat(" + relation + ")");
} catch (ScriptException e) {
if (log.isErrorEnabled()) {
log.error("Could not compute value from " + relation);
}
}
return o == null ? null : o.floatValue();
}
private static void addBindings(Map coeffs, Bindings bindings, String variable, float taille) {
for (Map.Entry entry : coeffs.entrySet()) {
String key = entry.getKey();
Double value = entry.getValue();
bindings.put(key, value);
if (log.isDebugEnabled()) {
log.debug("add constant " + key + '=' + value);
}
}
bindings.put(variable, taille);
}
}