/*
* 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.el;
import static java.lang.Boolean.valueOf;
import static java.lang.System.getProperty;
import static java.util.regex.Pattern.compile;
import static org.apache.commons.lang.StringUtils.isEmpty;
import static org.mule.runtime.core.api.config.MuleProperties.MULE_MEL_AS_DEFAULT;
import static org.mule.runtime.core.el.DefaultExpressionManager.DW_PREFIX;
import static org.mule.runtime.core.el.DefaultExpressionManager.MEL_PREFIX;
import org.mule.runtime.api.el.BindingContext;
import org.mule.runtime.api.el.ValidationResult;
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.construct.FlowConstruct;
import org.mule.runtime.core.api.el.ExtendedExpressionLanguageAdaptor;
import org.mule.runtime.core.api.expression.ExpressionRuntimeException;
import org.mule.runtime.core.el.mvel.MVELExpressionLanguage;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Implementation of an {@link ExtendedExpressionLanguageAdaptor} which adapts MVEL and DW together, deciding via a prefix whether one or
* the other should be call. It will allow MVEL and DW to be used together in compatibility mode.
*
* @since 4.0
*/
public class ExpressionLanguageAdaptorHandler implements ExtendedExpressionLanguageAdaptor {
private final Pattern EXPR_PREFIX_PATTERN = compile("^\\s*(?:(?:#\\[)?\\s*(\\w+):|\\%(\\w+) \\d).*");
private Map<String, ExtendedExpressionLanguageAdaptor> expressionLanguages;
private boolean melDefault = false;
public ExpressionLanguageAdaptorHandler(DataWeaveExpressionLanguageAdaptor defaultExtendedExpressionLanguage,
MVELExpressionLanguage mvelExpressionLanguage) {
expressionLanguages = new HashMap<>();
expressionLanguages.put(DW_PREFIX, defaultExtendedExpressionLanguage);
expressionLanguages.put(MEL_PREFIX, mvelExpressionLanguage);
melDefault = valueOf(getProperty(MULE_MEL_AS_DEFAULT, "false"));
}
public boolean isMelDefault() {
return melDefault;
}
@Override
public void addGlobalBindings(BindingContext bindingContext) {
expressionLanguages.get(DW_PREFIX).addGlobalBindings(bindingContext);
}
@Override
public TypedValue evaluate(String expression, Event event, BindingContext context)
throws ExpressionRuntimeException {
return selectExpressionLanguage(expression).evaluate(expression, event, context);
}
@Override
public TypedValue evaluate(String expression, DataType expectedOutputType, Event event, BindingContext context)
throws ExpressionRuntimeException {
return selectExpressionLanguage(expression).evaluate(expression, expectedOutputType, event, context);
}
@Override
public TypedValue evaluate(String expression, DataType expectedOutputType, Event event, FlowConstruct flowConstruct,
BindingContext context, boolean failOnNull)
throws ExpressionRuntimeException {
return selectExpressionLanguage(expression).evaluate(expression, expectedOutputType, event, flowConstruct, context,
failOnNull);
}
@Override
public TypedValue evaluate(String expression, Event event, FlowConstruct flowConstruct, BindingContext bindingContext)
throws ExpressionRuntimeException {
return selectExpressionLanguage(expression).evaluate(expression, event, flowConstruct, bindingContext);
}
@Override
public ValidationResult validate(String expression) {
return selectExpressionLanguage(expression).validate(expression);
}
@Override
public TypedValue evaluate(String expression, Event event, Event.Builder eventBuilder, FlowConstruct flowConstruct,
BindingContext bindingContext)
throws ExpressionRuntimeException {
return selectExpressionLanguage(expression).evaluate(expression, event, eventBuilder, flowConstruct, bindingContext);
}
@Override
public void enrich(String expression, Event event, Event.Builder eventBuilder, FlowConstruct flowConstruct, Object object) {
selectExpressionLanguage(expression).enrich(expression, event, eventBuilder, flowConstruct, object);
}
@Override
public void enrich(String expression, Event event, Event.Builder eventBuilder, FlowConstruct flowConstruct,
TypedValue value) {
selectExpressionLanguage(expression).enrich(expression, event, eventBuilder, flowConstruct, value);
}
@Override
public Iterator<TypedValue<?>> split(String expression, int bachSize, Event event, FlowConstruct flowConstruct,
BindingContext bindingContext)
throws ExpressionRuntimeException {
return selectExpressionLanguage(expression).split(expression, bachSize, event, flowConstruct, bindingContext);
}
@Override
public Iterator<TypedValue<?>> split(String expression, int bachSize, Event event, BindingContext bindingContext)
throws ExpressionRuntimeException {
return selectExpressionLanguage(expression).split(expression, bachSize, event, bindingContext);
}
private ExtendedExpressionLanguageAdaptor selectExpressionLanguage(String expression) {
final String languagePrefix = getLanguagePrefix(expression);
if (isEmpty(languagePrefix)) {
if (melDefault) {
return expressionLanguages.get(MEL_PREFIX);
} else {
return expressionLanguages.get(DW_PREFIX);
}
} else {
return expressionLanguages.get(languagePrefix);
}
}
private String getLanguagePrefix(String expression) {
final Matcher matcher = EXPR_PREFIX_PATTERN.matcher(expression);
if (matcher.find()) {
int i = 1;
String currentGroup = null;
while (currentGroup == null) {
currentGroup = matcher.group(i++);
}
return currentGroup;
} else {
return null;
}
}
}