001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.model.language;
018
019import java.util.List;
020import javax.xml.bind.annotation.XmlAccessType;
021import javax.xml.bind.annotation.XmlAccessorType;
022import javax.xml.bind.annotation.XmlAttribute;
023import javax.xml.bind.annotation.XmlID;
024import javax.xml.bind.annotation.XmlRootElement;
025import javax.xml.bind.annotation.XmlTransient;
026import javax.xml.bind.annotation.XmlType;
027import javax.xml.bind.annotation.XmlValue;
028import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
029import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
030
031import org.apache.camel.CamelContext;
032import org.apache.camel.Exchange;
033import org.apache.camel.Expression;
034import org.apache.camel.Predicate;
035import org.apache.camel.spi.Language;
036import org.apache.camel.spi.Metadata;
037import org.apache.camel.spi.Required;
038import org.apache.camel.spi.RouteContext;
039import org.apache.camel.util.CollectionStringBuffer;
040import org.apache.camel.util.ExpressionToPredicateAdapter;
041import org.apache.camel.util.IntrospectionSupport;
042import org.apache.camel.util.ObjectHelper;
043
044/**
045 * A useful base class for an expression
046 */
047@Metadata(label = "language", title = "Expression")
048@XmlRootElement
049@XmlType(name = "expression") // must be named expression
050@XmlAccessorType(XmlAccessType.FIELD)
051public class ExpressionDefinition implements Expression, Predicate {
052    @XmlAttribute
053    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
054    @XmlID
055    private String id;
056    @XmlValue
057    private String expression;
058    @XmlAttribute @Metadata(defaultValue = "true")
059    private Boolean trim;
060    @XmlTransient
061    private Predicate predicate;
062    @XmlTransient
063    private Expression expressionValue;
064    @XmlTransient
065    private ExpressionDefinition expressionType;
066
067    public ExpressionDefinition() {
068    }
069
070    public ExpressionDefinition(String expression) {
071        this.expression = expression;
072    }
073
074    public ExpressionDefinition(Predicate predicate) {
075        this.predicate = predicate;
076    }
077
078    public ExpressionDefinition(Expression expression) {
079        this.expressionValue = expression;
080    }
081
082    public static String getLabel(List<ExpressionDefinition> expressions) {
083        CollectionStringBuffer buffer = new CollectionStringBuffer();
084        for (ExpressionDefinition expression : expressions) {
085            buffer.append(expression.getLabel());
086        }
087        return buffer.toString();
088    }
089
090    @Override
091    public String toString() {
092        StringBuilder sb = new StringBuilder();
093        if (getLanguage() != null) {
094            sb.append(getLanguage()).append("{");
095        }
096        if (getPredicate() != null) {
097            sb.append(getPredicate().toString());
098        }
099        if (getExpressionValue() != null) {
100            sb.append(getExpressionValue().toString());
101        }
102        if (getPredicate() == null && getExpressionValue() == null && getExpression() != null) {
103            sb.append(getExpression());
104        }
105        if (getLanguage() != null) {
106            sb.append("}");
107        }
108        return sb.toString();
109    }
110
111    public Object evaluate(Exchange exchange) {
112        return evaluate(exchange, Object.class);
113    }
114
115    public <T> T evaluate(Exchange exchange, Class<T> type) {
116        if (expressionValue == null) {
117            expressionValue = createExpression(exchange.getContext());
118        }
119        ObjectHelper.notNull(expressionValue, "expressionValue");
120        return expressionValue.evaluate(exchange, type);
121    }
122
123    public void assertMatches(String text, Exchange exchange) throws AssertionError {
124        if (!matches(exchange)) {
125            throw new AssertionError(text + getExpression() + " for exchange: " + exchange);
126        }
127    }
128
129    public boolean matches(Exchange exchange) {
130        if (predicate == null) {
131            predicate = createPredicate(exchange.getContext());
132        }
133        ObjectHelper.notNull(predicate, "predicate");
134        return predicate.matches(exchange);
135    }
136
137    public String getLanguage() {
138        return "";
139    }
140
141    public final Predicate createPredicate(RouteContext routeContext) {
142        return createPredicate(routeContext.getCamelContext());
143    }
144
145    public Predicate createPredicate(CamelContext camelContext) {
146        if (predicate == null) {
147            if (getExpressionType() != null) {
148                predicate = getExpressionType().createPredicate(camelContext);
149            } else if (getExpressionValue() != null) {
150                predicate = new ExpressionToPredicateAdapter(getExpressionValue());
151            } else if (getExpression() != null) {
152                ObjectHelper.notNull("language", getLanguage());
153                Language language = camelContext.resolveLanguage(getLanguage());
154                String exp = getExpression();
155                // should be true by default
156                boolean isTrim = getTrim() == null || getTrim();
157                // trim if configured to trim
158                if (exp != null && isTrim) {
159                    exp = exp.trim();
160                }
161                predicate = language.createPredicate(exp);
162                configurePredicate(camelContext, predicate);
163            }
164        }
165        return predicate;
166    }
167
168    public final Expression createExpression(RouteContext routeContext) {
169        return createExpression(routeContext.getCamelContext());
170    }
171
172    public Expression createExpression(CamelContext camelContext) {
173        if (getExpressionValue() == null) {
174            if (getExpressionType() != null) {
175                setExpressionValue(getExpressionType().createExpression(camelContext));
176            } else if (getExpression() != null) {
177                ObjectHelper.notNull("language", getLanguage());
178                Language language = camelContext.resolveLanguage(getLanguage());
179                String exp = getExpression();
180                // should be true by default
181                boolean isTrim = getTrim() == null || getTrim();
182                // trim if configured to trim
183                if (exp != null && isTrim) {
184                    exp = exp.trim();
185                }
186                setExpressionValue(language.createExpression(exp));
187                configureExpression(camelContext, getExpressionValue());
188            }
189        }
190        return getExpressionValue();
191    }
192
193    public String getExpression() {
194        return expression;
195    }
196
197    /**
198     * The expression value in your chosen language syntax
199     */
200    @Required
201    public void setExpression(String expression) {
202        this.expression = expression;
203    }
204
205    public String getId() {
206        return id;
207    }
208
209    /**
210     * Sets the id of this node
211     */
212    public void setId(String value) {
213        this.id = value;
214    }
215
216    public Predicate getPredicate() {
217        return predicate;
218    }
219
220    public Expression getExpressionValue() {
221        return expressionValue;
222    }
223
224    protected void setExpressionValue(Expression expressionValue) {
225        this.expressionValue = expressionValue;
226    }
227
228    public ExpressionDefinition getExpressionType() {
229        return expressionType;
230    }
231
232    public Boolean getTrim() {
233        return trim;
234    }
235
236    /**
237     * Whether to trim the value to remove leading and trailing whitespaces and line breaks
238     */
239    public void setTrim(Boolean trim) {
240        this.trim = trim;
241    }
242
243    /**
244     * Returns some descriptive text to describe this node
245     */
246    public String getLabel() {
247        Predicate predicate = getPredicate();
248        if (predicate != null) {
249            return predicate.toString();
250        }
251        Expression expressionValue = getExpressionValue();
252        if (expressionValue != null) {
253            return expressionValue.toString();
254        }
255
256        String exp = getExpression();
257        return exp != null ? exp : "";
258    }
259
260    /**
261     * Allows derived classes to set a lazily created expressionType instance
262     * such as if using the {@link org.apache.camel.builder.ExpressionClause}
263     */
264    protected void setExpressionType(ExpressionDefinition expressionType) {
265        this.expressionType = expressionType;
266    }
267
268    protected void configurePredicate(CamelContext camelContext, Predicate predicate) {
269    }
270
271    protected void configureExpression(CamelContext camelContext, Expression expression) {
272    }
273
274    /**
275     * Sets a named property on the object instance using introspection
276     */
277    protected void setProperty(Object bean, String name, Object value) {
278        try {
279            IntrospectionSupport.setProperty(bean, name, value);
280        } catch (Exception e) {
281            throw new IllegalArgumentException("Failed to set property " + name + " on " + bean
282                                               + ". Reason: " + e, e);
283        }
284    }
285}