/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.model.language;
import java.util.List;
import java.util.Map;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyAttribute;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlID;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.namespace.QName;
import org.apache.camel.AfterPropertiesConfigured;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.Expression;
import org.apache.camel.NoSuchLanguageException;
import org.apache.camel.Predicate;
import org.apache.camel.model.OtherAttributesAware;
import org.apache.camel.spi.Language;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.RouteContext;
import org.apache.camel.util.CollectionStringBuffer;
import org.apache.camel.util.ExpressionToPredicateAdapter;
import org.apache.camel.util.IntrospectionSupport;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.ResourceHelper;
/**
* A useful base class for an expression
*/
@Metadata(label = "language", title = "Expression")
@XmlRootElement
@XmlType(name = "expression") // must be named expression
@XmlAccessorType(XmlAccessType.FIELD)
public class ExpressionDefinition implements Expression, Predicate, OtherAttributesAware {
@XmlAttribute
@XmlID
private String id;
@XmlValue @Metadata(required = "true")
private String expression;
@XmlAttribute @Metadata(defaultValue = "true")
private Boolean trim;
@XmlTransient
private Predicate predicate;
@XmlTransient
private Expression expressionValue;
@XmlTransient
private ExpressionDefinition expressionType;
// use xs:any to support optional property placeholders
@XmlAnyAttribute
private Map<QName, Object> otherAttributes;
public ExpressionDefinition() {
}
public ExpressionDefinition(String expression) {
this.expression = expression;
}
public ExpressionDefinition(Predicate predicate) {
this.predicate = predicate;
}
public ExpressionDefinition(Expression expression) {
this.expressionValue = expression;
}
public static String getLabel(List<ExpressionDefinition> expressions) {
CollectionStringBuffer buffer = new CollectionStringBuffer();
for (ExpressionDefinition expression : expressions) {
buffer.append(expression.getLabel());
}
return buffer.toString();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (getLanguage() != null) {
sb.append(getLanguage()).append("{");
}
if (getPredicate() != null) {
sb.append(getPredicate().toString());
}
if (getExpressionValue() != null) {
sb.append(getExpressionValue().toString());
}
if (getPredicate() == null && getExpressionValue() == null && getExpression() != null) {
sb.append(getExpression());
}
if (getLanguage() != null) {
sb.append("}");
}
return sb.toString();
}
public Object evaluate(Exchange exchange) {
return evaluate(exchange, Object.class);
}
public <T> T evaluate(Exchange exchange, Class<T> type) {
if (expressionValue == null) {
expressionValue = createExpression(exchange.getContext());
}
ObjectHelper.notNull(expressionValue, "expressionValue");
return expressionValue.evaluate(exchange, type);
}
public void assertMatches(String text, Exchange exchange) throws AssertionError {
if (!matches(exchange)) {
throw new AssertionError(text + getExpression() + " for exchange: " + exchange);
}
}
public boolean matches(Exchange exchange) {
if (predicate == null) {
predicate = createPredicate(exchange.getContext());
}
ObjectHelper.notNull(predicate, "predicate");
return predicate.matches(exchange);
}
public String getLanguage() {
return "";
}
public final Predicate createPredicate(RouteContext routeContext) {
return createPredicate(routeContext.getCamelContext());
}
public Predicate createPredicate(CamelContext camelContext) {
if (predicate == null) {
if (getExpressionType() != null) {
predicate = getExpressionType().createPredicate(camelContext);
} else if (getExpressionValue() != null) {
predicate = new ExpressionToPredicateAdapter(getExpressionValue());
} else if (getExpression() != null) {
ObjectHelper.notNull("language", getLanguage());
Language language = camelContext.resolveLanguage(getLanguage());
if (language == null) {
throw new NoSuchLanguageException(getLanguage());
}
String exp = getExpression();
// should be true by default
boolean isTrim = getTrim() == null || getTrim();
// trim if configured to trim
if (exp != null && isTrim) {
exp = exp.trim();
}
// resolve the expression as it may be an external script from the classpath/file etc
exp = ResourceHelper.resolveOptionalExternalScript(camelContext, exp);
predicate = language.createPredicate(exp);
configurePredicate(camelContext, predicate);
}
}
return predicate;
}
public final Expression createExpression(RouteContext routeContext) {
return createExpression(routeContext.getCamelContext());
}
public Expression createExpression(CamelContext camelContext) {
if (getExpressionValue() == null) {
if (getExpressionType() != null) {
setExpressionValue(getExpressionType().createExpression(camelContext));
} else if (getExpression() != null) {
ObjectHelper.notNull("language", getLanguage());
Language language = camelContext.resolveLanguage(getLanguage());
if (language == null) {
throw new NoSuchLanguageException(getLanguage());
}
String exp = getExpression();
// should be true by default
boolean isTrim = getTrim() == null || getTrim();
// trim if configured to trim
if (exp != null && isTrim) {
exp = exp.trim();
}
// resolve the expression as it may be an external script from the classpath/file etc
exp = ResourceHelper.resolveOptionalExternalScript(camelContext, exp);
setExpressionValue(language.createExpression(exp));
configureExpression(camelContext, getExpressionValue());
}
}
return getExpressionValue();
}
public String getExpression() {
return expression;
}
/**
* The expression value in your chosen language syntax
*/
public void setExpression(String expression) {
this.expression = expression;
}
public String getId() {
return id;
}
/**
* Sets the id of this node
*/
public void setId(String value) {
this.id = value;
}
public Predicate getPredicate() {
return predicate;
}
public Expression getExpressionValue() {
return expressionValue;
}
protected void setExpressionValue(Expression expressionValue) {
this.expressionValue = expressionValue;
}
public ExpressionDefinition getExpressionType() {
return expressionType;
}
public Boolean getTrim() {
return trim;
}
/**
* Whether to trim the value to remove leading and trailing whitespaces and line breaks
*/
public void setTrim(Boolean trim) {
this.trim = trim;
}
@Override
public Map<QName, Object> getOtherAttributes() {
return otherAttributes;
}
@Override
public void setOtherAttributes(Map<QName, Object> otherAttributes) {
this.otherAttributes = otherAttributes;
}
/**
* Returns some descriptive text to describe this node
*/
public String getLabel() {
Predicate predicate = getPredicate();
if (predicate != null) {
return predicate.toString();
}
Expression expressionValue = getExpressionValue();
if (expressionValue != null) {
return expressionValue.toString();
}
String exp = getExpression();
return exp != null ? exp : "";
}
/**
* Allows derived classes to set a lazily created expressionType instance
* such as if using the {@link org.apache.camel.builder.ExpressionClause}
*/
protected void setExpressionType(ExpressionDefinition expressionType) {
this.expressionType = expressionType;
}
protected void configurePredicate(CamelContext camelContext, Predicate predicate) {
// allows to perform additional logic after the properties has been configured which may be needed
// in the various camel components outside camel-core
if (predicate instanceof AfterPropertiesConfigured) {
((AfterPropertiesConfigured) predicate).afterPropertiesConfigured(camelContext);
}
}
protected void configureExpression(CamelContext camelContext, Expression expression) {
// allows to perform additional logic after the properties has been configured which may be needed
// in the various camel components outside camel-core
if (expression instanceof AfterPropertiesConfigured) {
((AfterPropertiesConfigured) expression).afterPropertiesConfigured(camelContext);
}
}
/**
* Sets a named property on the object instance using introspection
*/
protected void setProperty(Object bean, String name, Object value) {
try {
IntrospectionSupport.setProperty(bean, name, value);
} catch (Exception e) {
throw new IllegalArgumentException("Failed to set property " + name + " on " + bean
+ ". Reason: " + e, e);
}
}
}