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.io.IOException;
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.ExpressionFactoryImpl;
031 import de.odysseus.el.util.SimpleContext;
032
033 import org.apache.camel.CamelContext;
034 import org.apache.camel.Exchange;
035 import org.apache.camel.Message;
036 import org.apache.camel.impl.ExpressionSupport;
037 import org.apache.camel.spi.FactoryFinder;
038 import org.slf4j.Logger;
039 import org.slf4j.LoggerFactory;
040
041 /**
042 * The <a href="http://camel.apache.org/el.html">EL Language from JSP and JSF</a>
043 * using the <a href="http://camel.apache.org/juel.html">JUEL library</a>
044 *
045 * @version
046 */
047 public class JuelExpression extends ExpressionSupport {
048 public static final String DEFAULT_EXPRESSION_FACTORY_IMPL_CLASS = "de.odysseus.el.ExpressionFactoryImpl";
049 private static final Logger LOG = LoggerFactory.getLogger(JuelExpression.class);
050
051 private final String expression;
052 private final Class<?> type;
053 private ExpressionFactory expressionFactory;
054
055 public JuelExpression(String expression, Class<?> type) {
056 this.expression = expression;
057 this.type = type;
058 }
059
060 public static JuelExpression el(String expression) {
061 return new JuelExpression(expression, Object.class);
062 }
063
064 public <T> T evaluate(Exchange exchange, Class<T> tClass) {
065 // TODO we could use caching here but then we'd have possible concurrency issues
066 // so lets assume that the provider caches
067
068 // Create (if needed) the ExpressionFactory first from the CamelContext using FactoryFinder
069 ExpressionFactory factory = getExpressionFactory(exchange.getContext());
070 ELContext context = populateContext(createContext(), exchange);
071 ValueExpression valueExpression = factory.createValueExpression(context, expression, type);
072 Object value = valueExpression.getValue(context);
073 return exchange.getContext().getTypeConverter().convertTo(tClass, value);
074 }
075
076 public ExpressionFactory getExpressionFactory(CamelContext context) {
077 if (expressionFactory == null && context != null) {
078 try {
079 FactoryFinder finder = context.getFactoryFinder("META-INF/services/org/apache/camel/language/");
080 Class<?> clazz = finder.findClass("el", "impl.", ExpressionFactory.class);
081 if (clazz != null) {
082 expressionFactory = (ExpressionFactory)clazz.newInstance();
083 }
084 } catch (ClassNotFoundException e) {
085 LOG.debug("'impl.class' not found", e);
086 } catch (IOException e) {
087 LOG.debug("No impl class for juel ExpressionFactory defined in 'META-INF/services/org/apache/camel/language/el'", e);
088 } catch (InstantiationException e) {
089 LOG.debug("Failed to instantiate juel ExpressionFactory implementation class.", e);
090 } catch (IllegalAccessException e) {
091 LOG.debug("Failed to instantiate juel ExpressionFactory implementation class.", e);
092 }
093 }
094 return getExpressionFactory();
095 }
096
097 public ExpressionFactory getExpressionFactory() {
098 if (expressionFactory == null) {
099 expressionFactory = new ExpressionFactoryImpl();
100 }
101 return expressionFactory;
102 }
103
104 public void setExpressionFactory(ExpressionFactory expressionFactory) {
105 this.expressionFactory = expressionFactory;
106 }
107
108 protected ELContext populateContext(ELContext context, Exchange exchange) {
109 setVariable(context, "exchange", exchange, Exchange.class);
110 setVariable(context, "in", exchange.getIn(), Message.class);
111 if (exchange.hasOut()) {
112 setVariable(context, "out", exchange.getOut(), Message.class);
113 }
114 return context;
115 }
116
117 protected void setVariable(ELContext context, String name, Object value, Class<?> type) {
118 ValueExpression valueExpression = getExpressionFactory().createValueExpression(value, type);
119 SimpleContext simpleContext = (SimpleContext) context;
120 simpleContext.setVariable(name, valueExpression);
121 }
122
123 /**
124 * Factory method to create the EL context
125 */
126 protected ELContext createContext() {
127 ELResolver resolver = new CompositeELResolver() {
128 {
129 //add(methodResolver);
130 add(new ArrayELResolver(false));
131 add(new ListELResolver(false));
132 add(new MapELResolver(false));
133 add(new ResourceBundleELResolver());
134 add(new BeanAndMethodELResolver());
135 }
136 };
137 return new SimpleContext(resolver);
138 }
139
140 protected String assertionFailureMessage(Exchange exchange) {
141 return expression;
142 }
143 }