use of com.dexels.navajo.expression.api.TMLExpressionException in project navajo by Dexels.
the class ASTTmlNode method interpretToLambda.
@Override
public final ContextExpression interpretToLambda(List<String> problems, String expression, Function<String, FunctionClassification> functionClassifier, Function<String, Optional<Node>> mapResolver) {
return new ContextExpression() {
@Override
public boolean isLiteral() {
return false;
}
@Override
public Operand apply(Navajo doc, Message parentMsg, Message parentParamMsg, Selection parentSel, MappableTreeNode mapNode, TipiLink tipiLink, Access access, Optional<ImmutableMessage> immutableMessage, Optional<ImmutableMessage> paramMessage) {
List<Property> match = null;
List<Object> resultList = new ArrayList<>();
boolean singleMatch = true;
if (val.equals("[") || val.equals("[/")) {
return immutableMessage.map(msg -> Operand.ofImmutable(msg)).orElse(parentMsg != null ? Operand.ofMessage(parentMsg) : Operand.NULL);
}
String[] parts = val.split("\\|");
String text = parts.length > 1 ? parts[1] : val;
boolean isParam = false;
Property prop = null;
if (parentSel != null) {
String dum = text;
if (dum.length() > 1 && dum.startsWith("[")) {
dum = dum.substring(1, dum.length());
}
if (dum.equals("name") || selectionOption.equals("name")) {
return Operand.ofString(parentSel.getName());
} else if (dum.equals("value") || selectionOption.equals("value")) {
return Operand.ofString(parentSel.getValue());
} else if (dum.equals("selected") || selectionOption.equals("selected")) {
return Operand.ofBoolean(parentSel.isSelected());
}
}
if (!exists) {
if (text.startsWith("[")) {
text = text.substring(1, text.length());
}
} else {
if (text.startsWith("?[")) {
text = text.substring(2, text.length());
}
}
if (text.length() > 0 && text.charAt(0) == '@') {
// relative param property.
isParam = true;
text = text.substring(1);
}
if (text.startsWith("/@")) {
// Absolute param property, exclude the '[/@]' expression
isParam = true;
if (!text.equals("/@")) {
parentParamMsg = doc.getMessage("__parms__");
text = text.substring(2);
}
}
if (text.contains("__globals__")) {
// Absolute globals property.
parentMsg = doc.getMessage("__globals__");
int length = "__globals__".length();
if (text.startsWith("/")) {
length += 1;
}
// trailing /
length += 1;
text = text.substring(length);
}
if (Util.isRegularExpression(text))
singleMatch = false;
else
singleMatch = true;
try {
if (!isParam && immutableMessage != null && immutableMessage.isPresent()) {
ImmutableMessage rm = immutableMessage.get();
return parseImmutablePath(text, rm);
}
if (isParam && paramMessage != null && paramMessage.isPresent()) {
ImmutableMessage rm = paramMessage.get();
return parseImmutablePath(text, rm);
}
if (parentMsg == null && !isParam) {
if (text.indexOf(Navajo.MESSAGE_SEPARATOR) != -1) {
if (doc == null) {
throw new NullPointerException("Can't evaluate TML node: No parent message and no document found.");
}
match = doc.getProperties(text);
if (match.size() > 1) {
singleMatch = false;
}
} else {
throw new TMLExpressionException("No parent message present for property: " + text + " -> " + ImmutableFactory.getInstance().describe(immutableMessage.orElse(ImmutableFactory.empty())));
}
} else if (parentParamMsg == null && isParam) {
parentParamMsg = doc.getMessage("__parms__");
if (text.indexOf(Navajo.MESSAGE_SEPARATOR) != -1) {
match = doc.getProperties(text);
if (match.size() > 1) {
singleMatch = false;
}
} else
throw new TMLExpressionException("No parent message present for param: " + text);
} else {
if (text.indexOf(Navajo.MESSAGE_SEPARATOR) != -1) {
match = (!isParam ? parentMsg.getProperties(text) : parentParamMsg.getProperties(text));
if (match.size() > 1)
singleMatch = false;
} else {
match = new ArrayList<>();
match.add((!isParam ? parentMsg.getProperty(text) : parentParamMsg.getProperty(text)));
}
}
} catch (NavajoException te) {
throw new TMLExpressionException(te.getMessage(), te);
}
for (int j = 0; j < match.size(); j++) {
prop = (Property) match.get(j);
if (!exists && (prop == null))
if (parentMsg != null) {
throw new TMLExpressionException("TML property does not exist: " + text + " parent message: " + parentMsg.getFullMessageName());
} else {
throw new TMLExpressionException("TML property does not exist: " + text + " exists? " + exists);
}
else if (exists) {
// Check for existence and datatype validity.
if (prop != null) {
// Check type. If integer, float or date type and if is empty
String type = prop.getType();
// of binary properties. Should be equivalent, and MUCH faster.
if (prop.getTypedValue() == null && !type.equals(Property.SELECTION_PROPERTY)) {
return Operand.FALSE;
}
if (type.equals(Property.INTEGER_PROPERTY)) {
try {
Integer.parseInt(prop.getValue());
return Operand.TRUE;
} catch (Exception e) {
return Operand.FALSE;
}
} else if (type.equals(Property.FLOAT_PROPERTY)) {
try {
Double.parseDouble(prop.getValue());
return Operand.TRUE;
} catch (Exception e) {
return Operand.FALSE;
}
} else if (type.equals(Property.DATE_PROPERTY)) {
try {
if (prop.getTypedValue() instanceof Date) {
return Operand.TRUE;
} else {
return Operand.FALSE;
}
} catch (Exception e) {
return Operand.FALSE;
}
} else if (type.equals(Property.CLOCKTIME_PROPERTY)) {
try {
ClockTime ct = new ClockTime(prop.getValue());
if (ct.calendarValue() == null) {
return Operand.FALSE;
}
return Operand.TRUE;
} catch (Exception e) {
return Operand.FALSE;
}
} else
return Operand.TRUE;
} else
return Operand.FALSE;
}
String type = prop.getType();
Object value = prop.getTypedValue();
/**
* LEGACY MODE!
*/
if (value instanceof NavajoType && ((NavajoType) value).isEmpty()) {
value = null;
}
if (value == null && !type.equals(Property.SELECTION_PROPERTY)) {
// If value attribute does not exist AND property is not selection property assume null value
resultList.add(null);
} else if (type.equals(Property.SELECTION_PROPERTY)) {
if (!prop.getCardinality().equals("+")) {
// Uni-selection property.
try {
List<Selection> list = prop.getAllSelectedSelections();
if (!list.isEmpty()) {
Selection sel = list.get(0);
resultList.add((selectionOption.equals("name") ? sel.getName() : sel.getValue()));
} else {
return Operand.NULL;
}
} catch (com.dexels.navajo.document.NavajoException te) {
throw new TMLExpressionException(te.getMessage());
}
} else {
// Multi-selection property.
try {
List<Selection> list = prop.getAllSelectedSelections();
List<Object> result = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
Selection sel = list.get(i);
Object o = (selectionOption.equals("name")) ? sel.getName() : sel.getValue();
result.add(o);
}
resultList.add(result);
} catch (NavajoException te) {
throw new TMLExpressionException(te.getMessage(), te);
}
}
} else if (type.equals(Property.DATE_PROPERTY)) {
if (value == null)
resultList.add(null);
else {
if (!option.equals("")) {
try {
Date a = (Date) prop.getTypedValue();
Calendar cal = Calendar.getInstance();
cal.setTime(a);
int altA = 0;
if (option.equals("month")) {
altA = cal.get(Calendar.MONTH) + 1;
} else if (option.equals("day")) {
altA = cal.get(Calendar.DAY_OF_MONTH);
} else if (option.equals("year")) {
altA = cal.get(Calendar.YEAR);
} else if (option.equals("hour")) {
altA = cal.get(Calendar.HOUR_OF_DAY);
} else if (option.equals("minute")) {
altA = cal.get(Calendar.MINUTE);
} else if (option.equals("second")) {
altA = cal.get(Calendar.SECOND);
} else {
throw new TMLExpressionException("Option not supported: " + option + ", for type: " + type);
}
resultList.add(altA);
} catch (Exception ue) {
throw new TMLExpressionException("Invalid date: " + prop.getValue(), ue);
}
} else {
try {
Date a = (Date) prop.getTypedValue();
resultList.add(a);
} catch (java.lang.Exception pe) {
resultList.add(null);
}
}
}
} else if (type.equals(Property.EXPRESSION_PROPERTY)) {
resultList.add(prop.getTypedValue());
} else {
try {
resultList.add(value);
} catch (Exception e) {
throw new TMLExpressionException(e.getMessage(), e);
}
}
}
if (!singleMatch)
return Operand.ofList(resultList);
else if (!resultList.isEmpty())
return Operand.ofDynamic(resultList.get(0));
else if (!exists)
throw new TMLExpressionException("Property does not exist: " + text);
else
return Operand.FALSE;
}
private Operand parseImmutablePath(String text, ImmutableMessage rm) {
if ("".equals(text) || "/@".equals(text)) {
return Operand.ofImmutable(rm);
}
if (text.endsWith("/")) {
String trunc = text.substring(0, text.length() - 1);
List<String> parts = Arrays.asList(trunc.split("/"));
return parseImmutableMessagePath(parts, rm);
}
List<String> parts = Arrays.asList(text.split("/"));
return parseImmutablePath(parts, rm);
}
private Operand parseImmutableMessagePath(List<String> path, ImmutableMessage rm) {
if (path.isEmpty()) {
return Operand.ofImmutable(rm);
}
String first = path.get(0);
Optional<ImmutableMessage> sub = rm.subMessage(first);
if (!sub.isPresent()) {
throw new TMLExpressionException("Missing submessage: " + first);
}
List<String> copy = new ArrayList<>(path);
copy.remove(0);
return parseImmutableMessagePath(copy, sub.get());
}
private Operand parseImmutablePath(List<String> path, ImmutableMessage rm) {
if (path.size() > 1) {
Optional<ImmutableMessage> imm = rm.subMessage(path.get(0));
if (imm.isPresent()) {
List<String> parts = new LinkedList<>(path);
parts.remove(0);
return parseImmutablePath(parts, imm.get());
}
return null;
}
String type = rm.columnType(path.get(0));
if (type != null) {
return Operand.ofCustom(rm.value(path.get(0)).orElse(null), type);
}
return Operand.ofDynamic(rm.value(path.get(0)).orElse(null));
}
@Override
public Optional<String> returnType() {
return Optional.empty();
}
@Override
public String expression() {
return expression;
}
};
}
use of com.dexels.navajo.expression.api.TMLExpressionException in project navajo by Dexels.
the class ComparisonNode method compare.
private static final Boolean compare(ComparisonOperator compOp, Operand ao, Operand bo, String expression) {
Object a = ao.value;
Object b = bo.value;
if (a == null || b == null) {
throw new TMLExpressionException("Illegal arguement for " + compOp.getDescription() + ";. Cannot compare " + a + " " + compOp.getOperator() + " " + b + ". No null values are allowed. Expression: " + expression);
}
if (a instanceof Integer && b instanceof Integer)
return Utils.compare((Integer) a, (Integer) b, compOp.getOperator());
else if (a instanceof Integer && b instanceof Double)
return Utils.compare(((Integer) a).doubleValue(), (Double) b, compOp.getOperator());
else if (a instanceof Double && b instanceof Integer)
return Utils.compare((Double) a, ((Integer) b).doubleValue(), compOp.getOperator());
else if (a instanceof Double && b instanceof Double)
return Utils.compare((Double) a, (Double) b, compOp.getOperator());
else if (a instanceof Date)
return Boolean.valueOf(Utils.compareDates(a, b, compOp.getOperator()));
else if (a instanceof Money || b instanceof Money)
return Utils.compare(Utils.getDoubleValue(a), Utils.getDoubleValue(b), compOp.getOperator());
else if (a instanceof Percentage || b instanceof Percentage)
return Utils.compare(Utils.getDoubleValue(a), Utils.getDoubleValue(b), compOp.getOperator());
else if (a instanceof ClockTime && b instanceof ClockTime)
return Boolean.valueOf(Utils.compareDates(a, b, compOp.getOperator()));
else if (a instanceof String && b instanceof String)
return Utils.compare((String) a, (String) b, compOp.getOperator());
else
throw new TMLExpressionException("Illegal comparison for " + compOp.getDescription() + "; " + a.getClass().getName() + " " + b.getClass().getName());
}
use of com.dexels.navajo.expression.api.TMLExpressionException in project navajo by Dexels.
the class ExpressionCache method parse.
public ContextExpression parse(List<String> problems, String expression, Function<String, FunctionClassification> functionClassifier, Function<String, Optional<Node>> mapResolver) {
Optional<ContextExpression> cachedParsedExpression = exprCache.getUnchecked(expression);
if (cachedParsedExpression.isPresent()) {
hitCount.incrementAndGet();
return cachedParsedExpression.get();
}
CompiledParser cp;
try {
StringReader sr = new StringReader(expression);
cp = new CompiledParser(sr);
cp.Expression();
ContextExpression parsed = cp.getJJTree().rootNode().interpretToLambda(problems, expression, functionClassifier, mapResolver);
parsedCount.incrementAndGet();
if (parsed.isLiteral()) {
Operand result = parsed.apply();
exprCache.put(expression, Optional.ofNullable(parsed));
if (result != null) {
expressionValueCache.put(expression, Optional.of(result));
}
return new ContextExpression() {
@Override
public boolean isLiteral() {
return true;
}
@Override
public Operand apply(Navajo doc, Message parentMsg, Message parentParamMsg, Selection parentSel, MappableTreeNode mapNode, TipiLink tipiLink, Access access, Optional<ImmutableMessage> immutableMessage, Optional<ImmutableMessage> paramMessage) {
return result;
}
@Override
public Optional<String> returnType() {
return Optional.ofNullable(result.type);
}
@Override
public String expression() {
return expression;
}
};
} else {
exprCache.put(expression, Optional.ofNullable(parsed));
return parsed;
}
} catch (ParseException e) {
throw new TMLExpressionException("Error parsing expression: " + expression, e);
} catch (Throwable e) {
throw new TMLExpressionException("Unexpected error parsing expression: " + expression, e);
}
}
use of com.dexels.navajo.expression.api.TMLExpressionException in project navajo by Dexels.
the class CachedExpressionEvaluator method evaluate.
@Override
public Operand evaluate(String clause, Navajo inMessage, Object mappableTreeNode, Message parent, Message currentParam, Selection selection, Object tipiLink, Map<String, Object> params, Optional<ImmutableMessage> immutableMessage, Optional<ImmutableMessage> paramMessage) {
try {
ExpressionCache ce = ExpressionCache.getInstance();
Access access = params == null ? null : (Access) params.get(Expression.ACCESS);
Operand val = ce.evaluate(clause, inMessage, parent, currentParam, selection, (MappableTreeNode) mappableTreeNode, (TipiLink) tipiLink, access, immutableMessage, paramMessage);
if (val == null) {
throw new TMLExpressionException("Clause resolved to null, shouldnt happen: expression: " + clause);
}
return val;
} catch (TMLExpressionException e) {
if (inMessage != null) {
// Only log if we have useful context
logger.error("TML parsing issue with expression: {} exception", clause, e);
}
throw new TMLExpressionException(e.getMessage(), e);
}
}
use of com.dexels.navajo.expression.api.TMLExpressionException in project navajo by Dexels.
the class Utils method subtract.
/**
* Generic method to subtract two objects.
*/
public static final Object subtract(Object a, Object b, String expression) {
if (a == null || b == null) {
return null;
}
if ((a instanceof String) || (b instanceof String)) {
throw new TMLExpressionException("Subtraction not defined for Strings");
} else if ((a instanceof Money) || (b instanceof Money)) {
if (!(a instanceof Money || a instanceof Integer || a instanceof Long || a instanceof Double))
throw new TMLExpressionException("Invalid argument for operation: " + a.getClass() + ", expression: " + expression);
if (!(b instanceof Money || b instanceof Integer || b instanceof Long || b instanceof Double))
throw new TMLExpressionException("Invalid argument for operation: " + b.getClass() + ", expression: " + expression);
Money arg1 = (a instanceof Money ? (Money) a : new Money(a));
Money arg2 = (b instanceof Money ? (Money) b : new Money(b));
return new Money(arg1.doubleValue() - arg2.doubleValue());
} else if ((a instanceof Percentage) || (b instanceof Percentage)) {
if (!(a instanceof Percentage || a instanceof Integer || a instanceof Long || a instanceof Double))
throw new TMLExpressionException("Invalid argument for operation: " + a.getClass() + ", expression: " + expression);
if (!(b instanceof Percentage || b instanceof Integer || b instanceof Long || b instanceof Double))
throw new TMLExpressionException("Invalid argument for operation: " + b.getClass() + ", expression: " + expression);
Percentage arg1 = (a instanceof Percentage ? (Percentage) a : new Percentage(a));
Percentage arg2 = (b instanceof Percentage ? (Percentage) b : new Percentage(b));
return new Percentage(arg1.doubleValue() - arg2.doubleValue());
} else if (a instanceof Date && b instanceof Date) {
// Correct dates for daylight savings time.
Calendar ca = Calendar.getInstance();
ca.setTime((Date) a);
ca.add(Calendar.MILLISECOND, ca.get(Calendar.DST_OFFSET));
Calendar cb = Calendar.getInstance();
cb.setTime((Date) b);
cb.add(Calendar.MILLISECOND, cb.get(Calendar.DST_OFFSET));
return Integer.valueOf((int) ((ca.getTimeInMillis() - cb.getTimeInMillis()) / (double) MILLIS_IN_DAY));
} else if ((a instanceof DatePattern || a instanceof Date) && (b instanceof DatePattern || b instanceof Date)) {
DatePattern dp1 = null;
DatePattern dp2 = null;
if (a instanceof Date) {
dp1 = DatePattern.parseDatePattern((Date) a);
} else {
dp1 = (DatePattern) a;
}
if (b instanceof Date) {
dp2 = DatePattern.parseDatePattern((Date) b);
} else {
dp2 = (DatePattern) b;
}
dp1.subtract(dp2);
return dp1.getDate();
} else if ((a instanceof ClockTime || a instanceof Date || a instanceof StopwatchTime) && (b instanceof ClockTime || b instanceof Date || b instanceof StopwatchTime)) {
long myMillis = (a instanceof ClockTime ? ((ClockTime) a).dateValue().getTime() : (a instanceof Date ? ((Date) a).getTime() : ((StopwatchTime) a).getMillis()));
long otherMillis = (b instanceof ClockTime ? ((ClockTime) b).dateValue().getTime() : (b instanceof Date ? ((Date) b).getTime() : ((StopwatchTime) b).getMillis()));
return new StopwatchTime((int) (myMillis - otherMillis));
} else if (a instanceof Integer) {
int inta = (Integer) a;
if (b instanceof Integer) {
return inta - (Integer) b;
} else if (b instanceof Long) {
return inta - (Long) b;
} else if (b instanceof Double) {
return inta - (Double) b;
}
} else if (a instanceof Long) {
long longa = (Long) a;
if (b instanceof Integer) {
return longa - (Integer) b;
} else if (b instanceof Long) {
return longa - (Long) b;
} else if (b instanceof Double) {
return longa - (Double) b;
}
} else if (a instanceof Double) {
double doublea = (Double) a;
if (b instanceof Integer) {
return doublea - (Integer) b;
} else if (b instanceof Long) {
return doublea - (Long) b;
} else if (b instanceof Double) {
return doublea - (Double) b;
}
}
throw new TMLExpressionException("Subtraction: Unknown type. " + " expression: " + expression);
}
Aggregations