/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.core.util;
import static java.util.Arrays.asList;
import static java.util.regex.Pattern.DOTALL;
import static java.util.regex.Pattern.compile;
import static org.mule.runtime.api.metadata.DataType.OBJECT;
import static org.mule.runtime.api.metadata.DataType.STRING;
import static org.mule.runtime.core.api.el.ExpressionManager.DEFAULT_EXPRESSION_POSTFIX;
import static org.mule.runtime.core.api.el.ExpressionManager.DEFAULT_EXPRESSION_PREFIX;
import org.mule.runtime.api.el.BindingContext;
import org.mule.runtime.api.metadata.DataType;
import org.mule.runtime.api.metadata.TypedValue;
import org.mule.runtime.core.api.Event;
import org.mule.runtime.core.api.el.ExtendedExpressionManager;
import java.io.InputStream;
import java.util.List;
import java.util.function.Function;
import java.util.regex.Pattern;
/**
* This class acts as a wrapper for configuration attributes that support simple text, expression or regular expressions. It can
* be extended to support other cases too.
*/
public class AttributeEvaluator {
private static final Pattern SINGLE_EXPRESSION_REGEX_PATTERN = compile("^#\\[(?:(?!#\\[).)*]$", DOTALL);
private static final BindingContext NULL_BINDING_CONTEXT = BindingContext.builder().build();
private static final List<Class<?>> BLACK_LIST_TYPES = asList(Object.class, InputStream.class);
private String attributeValue;
private ExtendedExpressionManager expressionManager;
private Function<Event, TypedValue> expressionResolver;
/**
* Creates a new Attribute Evaluator instance with a given attribute value
*
* @param attributeValue the value for an attribute, this value can be treated as {@link AttributeType#EXPRESSION},
* {@link AttributeType#PARSE_EXPRESSION} or as a {@link AttributeType#STATIC_VALUE}
*/
public AttributeEvaluator(String attributeValue) {
this(attributeValue, null);
}
/**
* Creates a new Attribute Evaluator instance with a given attribute value and the expected {@link DataType}
*
* @param attributeValue the value for an attribute, this value can be treated as {@link AttributeType#EXPRESSION},
* {@link AttributeType#PARSE_EXPRESSION} or as a {@link AttributeType#STATIC_VALUE}
* @param expectedDataType specifies that the expression should be evaluated a coerced to the given expected {@link DataType}.
* This value will be ignored for {@link AttributeType#PARSE_EXPRESSION} and {@link AttributeType#STATIC_VALUE}
*/
public AttributeEvaluator(String attributeValue, DataType expectedDataType) {
this.attributeValue = sanitize(attributeValue);
switch (resolveAttributeType()) {
case EXPRESSION:
if (!(expectedDataType == null || BLACK_LIST_TYPES.contains(expectedDataType.getType()))) {
expressionResolver =
event -> expressionManager.evaluate(this.attributeValue, expectedDataType, NULL_BINDING_CONTEXT, event);
} else {
expressionResolver = event -> expressionManager.evaluate(this.attributeValue, event);
}
break;
case PARSE_EXPRESSION:
expressionResolver = event -> new TypedValue<>(expressionManager.parse(this.attributeValue, event, null), STRING);
break;
case STATIC_VALUE:
expressionResolver = event -> new TypedValue<>(this.attributeValue, this.attributeValue == null ? OBJECT : STRING);
}
}
public AttributeEvaluator initialize(final ExtendedExpressionManager expressionManager) {
this.expressionManager = expressionManager;
return this;
}
private String sanitize(String attributeValue) {
if (attributeValue != null) {
attributeValue = attributeValue.trim().replaceAll("\r", "").replaceAll("\t", "");
}
return attributeValue;
}
private AttributeType resolveAttributeType() {
if (attributeValue != null && SINGLE_EXPRESSION_REGEX_PATTERN.matcher(attributeValue).matches()) {
return AttributeType.EXPRESSION;
} else if (attributeValue != null && isParseExpression(attributeValue)) {
return AttributeType.PARSE_EXPRESSION;
} else {
return AttributeType.STATIC_VALUE;
}
}
private boolean isParseExpression(String attributeValue) {
final int beginExpression = attributeValue.indexOf(DEFAULT_EXPRESSION_PREFIX);
if (beginExpression == -1) {
return false;
}
String remainingString = attributeValue.substring(beginExpression + DEFAULT_EXPRESSION_PREFIX.length());
return remainingString.contains(DEFAULT_EXPRESSION_POSTFIX);
}
public <T> TypedValue<T> resolveTypedValue(Event event) {
return expressionResolver.apply(event);
}
public <T> T resolveValue(Event event) {
final TypedValue<T> resolveTypedValue = resolveTypedValue(event);
return resolveTypedValue.getValue();
}
public String getRawValue() {
return attributeValue;
}
private enum AttributeType {
EXPRESSION, PARSE_EXPRESSION, STATIC_VALUE
}
}