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    
037    /**
038     * The <a href="http://activemq.apache.org/camel/el.html">EL Language from JSP and JSF</a>
039     * using the <a href="http://activemq.apache.org/camel/juel.html">JUEL library</a>
040     *
041     * @version $Revision: 640731 $
042     */
043    public class JuelExpression extends ExpressionSupport<Exchange> {
044        private final String expression;
045        private final Class<?> type;
046        private ExpressionFactory expressionFactory;
047        private Properties expressionFactoryProperties;
048    
049        public JuelExpression(String expression, Class<?> type) {
050            this.expression = expression;
051            this.type = type;
052        }
053    
054        public static JuelExpression el(String expression) {
055            return new JuelExpression(expression, Object.class);
056        }
057    
058        public Object evaluate(Exchange exchange) {
059            // TODO we could use caching here but then we'd have possible concurrency issues
060            // so lets assume that the provider caches
061            ELContext context = populateContext(createContext(), exchange);
062            ValueExpression valueExpression = getExpressionFactory().createValueExpression(context, expression, type);
063            return valueExpression.getValue(context);
064        }
065    
066        public ExpressionFactory getExpressionFactory() {
067            if (expressionFactory == null) {
068                Properties properties = getExpressionFactoryProperties();
069                expressionFactory = ExpressionFactory.newInstance(properties);
070            }
071            return expressionFactory;
072        }
073    
074        public void setExpressionFactory(ExpressionFactory expressionFactory) {
075            this.expressionFactory = expressionFactory;
076        }
077    
078        public Properties getExpressionFactoryProperties() {
079            if (expressionFactoryProperties == null) {
080                expressionFactoryProperties = new Properties();
081                populateDefaultExpressionProperties(expressionFactoryProperties);
082            }
083            return expressionFactoryProperties;
084        }
085    
086        public void setExpressionFactoryProperties(Properties expressionFactoryProperties) {
087            this.expressionFactoryProperties = expressionFactoryProperties;
088        }
089    
090        protected ELContext populateContext(ELContext context, Exchange exchange) {
091            setVariable(context, "exchange", exchange, Exchange.class);
092            setVariable(context, "in", exchange.getIn(), Message.class);
093            Message out = exchange.getOut(false);
094            setVariable(context, "out", out, Message.class);
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    }