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.language.juel;
018    
019    import java.util.Properties;
020    
021    import javax.el.ArrayELResolver;
022    import javax.el.CompositeELResolver;
023    import javax.el.ELContext;
024    import javax.el.ELResolver;
025    import javax.el.ExpressionFactory;
026    import javax.el.ListELResolver;
027    import javax.el.MapELResolver;
028    import javax.el.ResourceBundleELResolver;
029    import javax.el.ValueExpression;
030    import de.odysseus.el.util.SimpleContext;
031    import org.apache.camel.Exchange;
032    import org.apache.camel.Message;
033    import org.apache.camel.impl.ExpressionSupport;
034    
035    /**
036     * The <a href="http://camel.apache.org/el.html">EL Language from JSP and JSF</a>
037     * using the <a href="http://camel.apache.org/juel.html">JUEL library</a>
038     *
039     * @version $Revision: 769448 $
040     */
041    public class JuelExpression extends ExpressionSupport {
042        private final String expression;
043        private final Class<?> type;
044        private ExpressionFactory expressionFactory;
045        private Properties expressionFactoryProperties;
046    
047        public JuelExpression(String expression, Class<?> type) {
048            this.expression = expression;
049            this.type = type;
050        }
051    
052        public static JuelExpression el(String expression) {
053            return new JuelExpression(expression, Object.class);
054        }
055    
056        public <T> T evaluate(Exchange exchange, Class<T> tClass) {
057            // TODO we could use caching here but then we'd have possible concurrency issues
058            // so lets assume that the provider caches
059            ELContext context = populateContext(createContext(), exchange);
060            ValueExpression valueExpression = getExpressionFactory().createValueExpression(context, expression, type);
061            Object value = valueExpression.getValue(context);
062            return exchange.getContext().getTypeConverter().convertTo(tClass, value);
063        }
064    
065        public ExpressionFactory getExpressionFactory() {
066            if (expressionFactory == null) {
067                Properties properties = getExpressionFactoryProperties();
068                expressionFactory = ExpressionFactory.newInstance(properties);
069            }
070            return expressionFactory;
071        }
072    
073        public void setExpressionFactory(ExpressionFactory expressionFactory) {
074            this.expressionFactory = expressionFactory;
075        }
076    
077        public Properties getExpressionFactoryProperties() {
078            if (expressionFactoryProperties == null) {
079                expressionFactoryProperties = new Properties();
080                populateDefaultExpressionProperties(expressionFactoryProperties);
081            }
082            return expressionFactoryProperties;
083        }
084    
085        public void setExpressionFactoryProperties(Properties expressionFactoryProperties) {
086            this.expressionFactoryProperties = expressionFactoryProperties;
087        }
088    
089        protected ELContext populateContext(ELContext context, Exchange exchange) {
090            setVariable(context, "exchange", exchange, Exchange.class);
091            setVariable(context, "in", exchange.getIn(), Message.class);
092            if (exchange.hasOut()) {
093                setVariable(context, "out", exchange.getOut(), Message.class);
094            }
095            return context;
096        }
097    
098        /**
099         * A Strategy Method to populate the default properties used to create the expression factory
100         */
101        protected void populateDefaultExpressionProperties(Properties properties) {
102            // lets enable method invocations
103            properties.setProperty("javax.el.methodInvocations", "true");
104        }
105    
106        protected void setVariable(ELContext context, String name, Object value, Class<?> type) {
107            ValueExpression valueExpression = getExpressionFactory().createValueExpression(value, type);
108            SimpleContext simpleContext = (SimpleContext) context;
109            simpleContext.setVariable(name, valueExpression);
110        }
111    
112        /**
113         * Factory method to create the EL context
114         */
115        protected ELContext createContext() {
116            ELResolver resolver = new CompositeELResolver() {
117                {
118                    //add(methodResolver);
119                    add(new ArrayELResolver(false));
120                    add(new ListELResolver(false));
121                    add(new MapELResolver(false));
122                    add(new ResourceBundleELResolver());
123                    add(new BeanAndMethodELResolver());
124                }
125            };
126            return new SimpleContext(resolver);
127        }
128    
129        protected String assertionFailureMessage(Exchange exchange) {
130            return expression;
131        }
132    }