/*
* 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.expression.transformers;
import static org.mule.runtime.core.util.ClassUtils.withContextClassLoader;
import org.mule.runtime.api.metadata.DataType;
import org.mule.runtime.core.api.Event;
import org.mule.runtime.core.api.MuleContext;
import org.mule.runtime.core.api.context.MuleContextAware;
import org.mule.runtime.core.api.expression.ExpressionRuntimeException;
import org.mule.runtime.core.api.transformer.Transformer;
import org.mule.runtime.core.api.transformer.TransformerException;
import org.mule.runtime.core.config.i18n.CoreMessages;
import org.mule.runtime.core.expression.ExpressionConfig;
/**
* TODO
*/
public class ExpressionArgument implements MuleContextAware {
private ExpressionConfig expressionConfig = new ExpressionConfig();
private String name;
private boolean optional;
private Class<?> returnClass;
protected ClassLoader expressionEvaluationClassLoader = ExpressionArgument.class.getClassLoader();
private MuleContext muleContext;
public ExpressionArgument() {
super();
}
public ExpressionArgument(String name, ExpressionConfig expressionConfig, boolean optional) {
this(name, expressionConfig, optional, null);
}
public ExpressionArgument(String name, ExpressionConfig expressionConfig, boolean optional, Class<?> returnClass) {
this.expressionConfig = expressionConfig;
this.name = name;
this.optional = optional;
this.returnClass = returnClass;
}
@Override
public void setMuleContext(MuleContext context) {
this.muleContext = context;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ExpressionConfig getExpressionConfig() {
return expressionConfig;
}
public void setExpressionConfig(ExpressionConfig expressionConfig) {
this.expressionConfig = expressionConfig;
}
public boolean isOptional() {
return optional;
}
public void setOptional(boolean optional) {
this.optional = optional;
}
protected String getFullExpression() {
return expressionConfig.getFullExpression();
}
protected void validate() {
expressionConfig.validate();
}
/**
* Evaluates this Expression against the passed in Message. If a returnClass is set on this Expression Argument it will be
* checked to ensure the Argument returns the correct class type.
*
* @param event the event to execute the expression on
* @return the result of the expression
* @throws ExpressionRuntimeException if the wrong return type is returned from the expression.
*/
public Object evaluate(Event event) throws ExpressionRuntimeException {
// MULE-4797 Because there is no way to specify the class-loader that script
// engines use and because scripts when used for expressions are compiled in
// runtime rather than at initialization the only way to ensure the correct
// class-loader to used is to switch it out here. We may want to consider
// passing the class-loader to the MuleExpressionLanguage and only doing this for
// certain ExpressionEvaluators further in.
Object result =
withContextClassLoader(expressionEvaluationClassLoader,
() -> muleContext.getExpressionManager().evaluate(getExpression(), event).getValue());
if (getReturnClass() != null && result != null) {
if (!getReturnClass().isInstance(result)) {
// If the return type does not match, lets attempt to transform it before throwing an error
try {
Transformer t =
muleContext.getRegistry().lookupTransformer(DataType.fromObject(result), DataType.fromType(getReturnClass()));
result = t.transform(result);
} catch (TransformerException e) {
throw new ExpressionRuntimeException(CoreMessages.transformUnexpectedType(result.getClass(), getReturnClass()), e);
}
}
// if(result instanceof Collection && ((Collection)result).size()==0 && !isOptional())
// {
// throw new ExpressionRuntimeException(CoreMessages.expressionEvaluatorReturnedNull(this.getEvaluator(),
// this.getExpression()));
// }
}
return result;
}
public String getExpression() {
return expressionConfig.getExpression();
}
public void setExpression(String expression) {
expressionConfig.setExpression(expression);
}
public Class<?> getReturnClass() {
return returnClass;
}
public void setReturnDataType(Class<?> returnClass) {
this.returnClass = returnClass;
}
public void setExpressionEvaluationClassLoader(ClassLoader expressionEvaluationClassLoader) {
this.expressionEvaluationClassLoader = expressionEvaluationClassLoader;
}
}