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.builder;
018
019import org.apache.camel.CamelContext;
020import org.apache.camel.CamelExecutionException;
021import org.apache.camel.Exchange;
022import org.apache.camel.Expression;
023import org.apache.camel.Predicate;
024import org.apache.camel.spi.ExpressionResultTypeAware;
025import org.apache.camel.spi.Language;
026import org.apache.camel.spi.PropertyConfigurer;
027import org.apache.camel.support.PredicateToExpressionAdapter;
028import org.apache.camel.support.ScriptHelper;
029import org.apache.camel.support.component.PropertyConfigurerSupport;
030
031/**
032 * Creates an {@link org.apache.camel.language.simple.Simple} language builder.
033 * <p/>
034 * This builder is available in the Java DSL from the {@link RouteBuilder} which
035 * means that using simple language for {@link Expression}s or
036 * {@link Predicate}s is very easy with the help of this builder.
037 */
038public class SimpleBuilder implements Predicate, Expression, ExpressionResultTypeAware, PropertyConfigurer {
039
040    private final String text;
041    private Class<?> resultType;
042    // cache the expression/predicate
043    private volatile Expression expression;
044    private volatile Predicate predicate;
045
046    public SimpleBuilder(String text) {
047        this.text = text;
048    }
049
050    public static SimpleBuilder simple(String text) {
051        return new SimpleBuilder(text);
052    }
053
054    public static SimpleBuilder simple(String text, Class<?> resultType) {
055        SimpleBuilder answer = simple(text);
056        answer.setResultType(resultType);
057        return answer;
058    }
059
060    public static SimpleBuilder simpleF(String formatText, Object... values) {
061        return simple(String.format(formatText, values));
062    }
063
064    public static SimpleBuilder simpleF(String formatText, Class<?> resultType, Object... values) {
065        return simple(String.format(formatText, values), resultType);
066    }
067
068    @Override
069    public boolean configure(CamelContext camelContext, Object target, String name, Object value, boolean ignoreCase) {
070        if (target != this) {
071            throw new IllegalStateException("Can only configure our own instance !");
072        }
073        switch (ignoreCase ? name.toLowerCase() : name) {
074            case "resulttype":
075            case "resultType":
076                setResultType(PropertyConfigurerSupport.property(camelContext, Class.class, value)); return true;
077            default:
078                return false;
079        }
080    }
081
082    public String getText() {
083        return text;
084    }
085
086    @Override
087    public String getExpressionText() {
088        return getText();
089    }
090
091    @Override
092    public Class<?> getResultType() {
093        return resultType;
094    }
095
096    public void setResultType(Class<?> resultType) {
097        this.resultType = resultType;
098    }
099
100    public SimpleBuilder resultType(Class<?> resultType) {
101        setResultType(resultType);
102        return this;
103    }
104
105    @Override
106    public void init(CamelContext context) {
107    }
108
109    @Override
110    public boolean matches(Exchange exchange) {
111        if (predicate == null) {
112            predicate = createPredicate(exchange.getContext());
113        }
114        return predicate.matches(exchange);
115    }
116
117    @Override
118    public <T> T evaluate(Exchange exchange, Class<T> type) {
119        if (expression == null) {
120            expression = createExpression(exchange.getContext());
121        }
122        return expression.evaluate(exchange, type);
123    }
124
125    public Predicate createPredicate(CamelContext context) {
126        try {
127            Language simple = context.resolveLanguage("simple");
128            // resolve property placeholders
129            String resolve = context.resolvePropertyPlaceholders(text);
130            // and optional it be refer to an external script on the file/classpath
131            if (ScriptHelper.hasExternalScript(resolve)) {
132                return new Predicate() {
133                    @Override
134                    public boolean matches(Exchange exchange) {
135                        String r = ScriptHelper.resolveOptionalExternalScript(context, exchange, resolve);
136                        return simple.createPredicate(r).matches(exchange);
137                    }
138                    @Override
139                    public String toString() {
140                        return text;
141                    }
142                };
143            } else {
144                Predicate pred = simple.createPredicate(resolve);
145                pred.init(context);
146                return pred;
147            }
148        } catch (Exception e) {
149            throw CamelExecutionException.wrapCamelExecutionException(null, e);
150        }
151    }
152
153    public Expression createExpression(CamelContext context) {
154        if (resultType == Boolean.class || resultType == boolean.class) {
155            // if its a boolean as result then its a predicate
156            Predicate predicate = createPredicate(context);
157            return PredicateToExpressionAdapter.toExpression(predicate);
158        }
159        try {
160            // resolve property placeholders
161            Language simple = context.resolveLanguage("simple");
162            String resolve = context.resolvePropertyPlaceholders(text);
163            Expression exp;
164            // and optional it be refer to an external script on the file/classpath
165            if (ScriptHelper.hasExternalScript(resolve)) {
166                exp = new Expression() {
167                    @Override
168                    public <T> T evaluate(Exchange exchange, Class<T> type) {
169                        String r = ScriptHelper.resolveOptionalExternalScript(context, exchange, resolve);
170                        Expression exp = simple.createExpression(r);
171                        return exp.evaluate(exchange, type);
172                    }
173                    @Override
174                    public String toString() {
175                        return text;
176                    }
177                };
178            } else {
179                exp = simple.createExpression(resolve);
180                exp.init(context);
181            }
182            if (resultType != null) {
183                exp = ExpressionBuilder.convertToExpression(exp, resultType);
184            }
185            return exp;
186        } catch (Exception e) {
187            throw CamelExecutionException.wrapCamelExecutionException(null, e);
188        }
189    }
190
191    @Override
192    public String toString() {
193        return "Simple: " + text;
194    }
195
196}