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     */
017    package org.apache.camel.model.language;
018    
019    import java.util.List;
020    
021    import javax.xml.bind.annotation.XmlAccessType;
022    import javax.xml.bind.annotation.XmlAccessorType;
023    import javax.xml.bind.annotation.XmlAttribute;
024    import javax.xml.bind.annotation.XmlID;
025    import javax.xml.bind.annotation.XmlTransient;
026    import javax.xml.bind.annotation.XmlType;
027    import javax.xml.bind.annotation.XmlValue;
028    import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
029    import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
030    
031    import org.apache.camel.CamelContext;
032    import org.apache.camel.Exchange;
033    import org.apache.camel.Expression;
034    import org.apache.camel.Predicate;
035    import org.apache.camel.builder.ExpressionClause;
036    import org.apache.camel.impl.DefaultRouteContext;
037    import org.apache.camel.spi.Language;
038    import org.apache.camel.spi.RouteContext;
039    import org.apache.camel.util.CollectionStringBuffer;
040    import org.apache.camel.util.IntrospectionSupport;
041    import org.apache.camel.util.ObjectHelper;
042    
043    /**
044     * A useful base class for an expression
045     *
046     * @version $Revision: 659007 $
047     */
048    @XmlType(name = "expressionType")
049    @XmlAccessorType(XmlAccessType.FIELD)
050    public class ExpressionType implements Expression<Exchange>, Predicate<Exchange> {
051        @XmlAttribute
052        @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
053        @XmlID
054        private String id;
055        @XmlValue
056        private String expression;
057        @XmlTransient
058        private Predicate predicate;
059        @XmlTransient
060        private Expression expressionValue;
061        @XmlTransient
062        private ExpressionType expressionType;
063    
064        public ExpressionType() {
065        }
066    
067        public ExpressionType(String expression) {
068            this.expression = expression;
069        }
070    
071        public ExpressionType(Predicate predicate) {
072            this.predicate = predicate;
073        }
074    
075        public ExpressionType(Expression expression) {
076            this.expressionValue = expression;
077        }
078    
079        public static String getLabel(List<ExpressionType> expressions) {
080            CollectionStringBuffer buffer = new CollectionStringBuffer();
081            for (ExpressionType expression : expressions) {
082                buffer.append(expression.getLabel());
083            }
084            return buffer.toString();
085        }
086    
087        @Override
088        public String toString() {
089            return getLanguage() + "Expression[" + getExpression() + "]";
090        }
091    
092        public Object evaluate(Exchange exchange) {
093            if (expressionValue == null) {
094                RouteContext routeContext = new DefaultRouteContext(exchange.getContext());
095                expressionValue = createExpression(routeContext);
096            }
097            ObjectHelper.notNull(expressionValue, "expressionValue");
098            return expressionValue.evaluate(exchange);
099        }
100    
101        public void assertMatches(String text, Exchange exchange) throws AssertionError {
102            if (!matches(exchange)) {
103                throw new AssertionError(text + getExpression() + " for exchange: " + exchange);
104            }
105        }
106    
107        public boolean matches(Exchange exchange) {
108            if (predicate == null) {
109                RouteContext routeContext = new DefaultRouteContext(exchange.getContext());
110                predicate = createPredicate(routeContext);
111            }
112            ObjectHelper.notNull(predicate, "predicate");
113            return predicate.matches(exchange);
114        }
115    
116        public String getLanguage() {
117            return "";
118        }
119    
120        public Predicate<Exchange> createPredicate(RouteContext routeContext) {
121            if (predicate == null) {
122                if (expressionType != null) {
123                    predicate = expressionType.createPredicate(routeContext);
124                } else {
125                    CamelContext camelContext = routeContext.getCamelContext();
126                    Language language = camelContext.resolveLanguage(getLanguage());
127                    predicate = language.createPredicate(getExpression());
128                    configurePredicate(routeContext, predicate);
129                }
130            }
131            return predicate;
132        }
133    
134        public Expression createExpression(RouteContext routeContext) {
135            if (expressionValue == null) {
136                if (expressionType != null) {
137                    expressionValue = expressionType.createExpression(routeContext);
138                } else {
139                    CamelContext camelContext = routeContext.getCamelContext();
140                    Language language = camelContext.resolveLanguage(getLanguage());
141                    expressionValue = language.createExpression(getExpression());
142                    configureExpression(routeContext, expressionValue);
143                }
144            }
145            return expressionValue;
146        }
147    
148        public String getExpression() {
149            return expression;
150        }
151    
152        public void setExpression(String expression) {
153            this.expression = expression;
154        }
155    
156        /**
157         * Gets the value of the id property.
158         *
159         * @return possible object is
160         *         {@link String }
161         */
162        public String getId() {
163            return id;
164        }
165    
166        /**
167         * Sets the value of the id property.
168         *
169         * @param value allowed object is
170         *              {@link String }
171         */
172        public void setId(String value) {
173            this.id = value;
174        }
175    
176        public Predicate getPredicate() {
177            return predicate;
178        }
179    
180        public Expression getExpressionValue() {
181            return expressionValue;
182        }
183    
184        protected void setExpressionValue(Expression expressionValue) {
185            this.expressionValue = expressionValue;
186        }
187    
188        /**
189         * Returns some descriptive text to describe this node
190         */
191        public String getLabel() {
192            String language = getExpression();
193            if (ObjectHelper.isNullOrBlank(language)) {
194                Predicate predicate = getPredicate();
195                if (predicate != null) {
196                    return predicate.toString();
197                }
198                Expression expressionValue = getExpressionValue();
199                if (expressionValue != null) {
200                    return expressionValue.toString();
201                }
202            } else {
203                return language;
204            }
205            return "";
206        }
207    
208        /**
209         * Allows derived classes to set a lazily created expressionType instance
210         * such as if using the {@link ExpressionClause}
211         */
212        protected void setExpressionType(ExpressionType expressionType) {
213            this.expressionType = expressionType;
214        }
215    
216        protected void configurePredicate(RouteContext routeContext, Predicate predicate) {
217        }
218    
219        protected void configureExpression(RouteContext routeContext, Expression expression) {
220        }
221    
222        /**
223         * Sets a named property on the object instance using introspection
224         */
225        protected void setProperty(Object bean, String name, Object value) {
226            try {
227                IntrospectionSupport.setProperty(bean, name, value);
228            } catch (Exception e) {
229                throw new IllegalArgumentException("Failed to set property " + name + " on " + bean
230                                                   + ". Reason: " + e, e);
231            }
232        }
233    }