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