use of com.dexels.navajo.script.api.Access 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.script.api.Access 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.script.api.Access in project navajo by Dexels.
the class SimpleNode method lazyFunction.
public ContextExpression lazyFunction(List<String> problems, String expression, UnaryOperator<Operand> func, Optional<String> requiredReturnType, Function<String, FunctionClassification> functionClassifier, Function<String, Optional<Node>> mapResolver) {
ContextExpression expA = jjtGetChild(0).interpretToLambda(problems, expression, functionClassifier, mapResolver);
if (requiredReturnType.isPresent() && expA.returnType().isPresent()) {
String expectedType = requiredReturnType.get();
String foundType = expA.returnType().get();
if (!expectedType.equals(foundType)) {
problems.add("Error (static) type checking. Type: " + foundType + " does not match expected type: " + expectedType);
}
}
return new ContextExpression() {
@Override
public Operand apply(Navajo doc, Message parentMsg, Message parentParamMsg, Selection parentSel, MappableTreeNode mapNode, TipiLink tipiLink, Access access, Optional<ImmutableMessage> immutableMessage, Optional<ImmutableMessage> paramMessage) {
Operand a = expA.apply(doc, parentMsg, parentParamMsg, parentSel, mapNode, tipiLink, access, immutableMessage, paramMessage);
return func.apply(a);
}
@Override
public boolean isLiteral() {
return expA.isLiteral();
}
@Override
public Optional<String> returnType() {
return requiredReturnType;
}
@Override
public String expression() {
return expression;
}
};
}
use of com.dexels.navajo.script.api.Access 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.script.api.Access in project navajo by Dexels.
the class ASTListNode method interpretToLambda.
@Override
public ContextExpression interpretToLambda(List<String> problems, String expression, Function<String, FunctionClassification> functionClassifier, Function<String, Optional<Node>> mapResolver) {
final List<ContextExpression> exprs = new ArrayList<>();
boolean onlyImmutable = true;
for (int i = 0; i < jjtGetNumChildren(); i++) {
ContextExpression lmb = jjtGetChild(i).interpretToLambda(problems, expression, functionClassifier, mapResolver);
exprs.add(lmb);
if (!onlyImmutable && !lmb.isLiteral()) {
onlyImmutable = false;
}
}
final boolean onlyImm = onlyImmutable;
return new ContextExpression() {
@Override
public boolean isLiteral() {
return onlyImm;
}
@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<Operand> result = new ArrayList<>();
for (ContextExpression contextExpression : exprs) {
result.add(contextExpression.apply(doc, parentMsg, parentParamMsg, parentSel, mapNode, tipiLink, access, immutableMessage, paramMessage));
}
return Operand.ofList(result.stream().map(e -> e.value).collect(Collectors.toList()));
}
@Override
public Optional<String> returnType() {
return Optional.of(Property.LIST_PROPERTY);
}
@Override
public String expression() {
return expression;
}
};
}
Aggregations