You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2010/03/14 11:37:10 UTC
svn commit: r922808 - in /camel/trunk/camel-core/src:
main/java/org/apache/camel/builder/ main/java/org/apache/camel/language/bean/
main/java/org/apache/camel/language/simple/
main/java/org/apache/camel/util/ test/java/org/apache/camel/language/
test/j...
Author: davsclaus
Date: Sun Mar 14 10:37:10 2010
New Revision: 922808
URL: http://svn.apache.org/viewvc?rev=922808&view=rev
Log:
CAMEL-2546: Added OGNL notation to simple/bean language. Work in progress.
Added:
camel/trunk/camel-core/src/main/java/org/apache/camel/util/OgnlHelper.java (with props)
camel/trunk/camel-core/src/test/java/org/apache/camel/language/BeanLanguageOGNLTest.java (with props)
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
camel/trunk/camel-core/src/main/java/org/apache/camel/language/bean/BeanExpression.java
camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguage.java
camel/trunk/camel-core/src/main/java/org/apache/camel/util/StringHelper.java
camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleTest.java
camel/trunk/camel-core/src/test/java/org/apache/camel/util/StringHelperTest.java
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java?rev=922808&r1=922807&r2=922808&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java Sun Mar 14 10:37:10 2010
@@ -22,7 +22,6 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
-import java.util.Map;
import java.util.Scanner;
import java.util.regex.Pattern;
@@ -33,16 +32,17 @@ import org.apache.camel.Expression;
import org.apache.camel.InvalidPayloadException;
import org.apache.camel.Message;
import org.apache.camel.NoSuchEndpointException;
-import org.apache.camel.NoTypeConversionAvailableException;
import org.apache.camel.Producer;
import org.apache.camel.component.bean.BeanInvocation;
import org.apache.camel.component.properties.PropertiesComponent;
import org.apache.camel.impl.ExpressionAdapter;
import org.apache.camel.language.bean.BeanLanguage;
+import org.apache.camel.model.language.MethodCallExpression;
import org.apache.camel.spi.Language;
import org.apache.camel.util.ExchangeHelper;
import org.apache.camel.util.FileUtil;
import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.OgnlHelper;
/**
* A helper class for working with <a href="http://camel.apache.org/expression.html">expressions</a>.
@@ -102,32 +102,37 @@ public final class ExpressionBuilder {
}
/**
- * Returns an expression to lookup a key in the header which should be Map based.
+ * Returns the expression for the exchanges inbound message header invoking methods defined
+ * in a simple OGNL notation
*
- * @param headerName the name of the header the expression will return
- * @param keyName the name of the key to lookup in the header value
- * @return an expression object which will return the key value looked up in the header
+ * @param ognl methods to invoke on the header in a simple OGNL syntax
*/
- public static Expression headerAsMapExpression(final String headerName, final String keyName) {
+ public static Expression headersOgnlExpression(final String ognl) {
return new ExpressionAdapter() {
public Object evaluate(Exchange exchange) {
- Object header = exchange.getIn().getHeader(headerName);
- if (header == null) {
- return null;
+ // try with full name first
+ Object header = exchange.getIn().getHeader(ognl);
+ if (header != null) {
+ return header;
}
- try {
- Map map = exchange.getContext().getTypeConverter().mandatoryConvertTo(Map.class, header);
- Object answer = map.get(keyName);
- return answer;
- } catch (NoTypeConversionAvailableException e) {
- throw new IllegalArgumentException("Header " + headerName + " cannot be converted to a Map on " + this, e);
+ // split into first name
+ List<String> methods = OgnlHelper.splitOgnl(ognl);
+ // remove any OGNL operators so we got the pure key name
+ String key = OgnlHelper.removeOperators(methods.get(0));
+
+ header = exchange.getIn().getHeader(key);
+ if (header == null) {
+ return null;
}
+ // the remainder is the rest of the ognl without the key
+ String remainder = ObjectHelper.after(ognl, key);
+ return new MethodCallExpression(header, remainder).evaluate(exchange);
}
@Override
public String toString() {
- return "headerAsMap(" + headerName + ")[" + keyName + "]";
+ return "headerOgnl(" + ognl + ")";
}
};
}
@@ -502,6 +507,29 @@ public final class ExpressionBuilder {
}
/**
+ * Returns the expression for the exchanges inbound message body invoking methods defined
+ * in a simple OGNL notation
+ *
+ * @param ognl methods to invoke on the body in a simple OGNL syntax
+ */
+ public static Expression bodyOgnlExpression(final String ognl) {
+ return new ExpressionAdapter() {
+ public Object evaluate(Exchange exchange) {
+ Object body = exchange.getIn().getBody();
+ if (body == null) {
+ return null;
+ }
+ return new MethodCallExpression(body, ognl).evaluate(exchange);
+ }
+
+ @Override
+ public String toString() {
+ return "bodyOgnl(" + ognl + ")";
+ }
+ };
+ }
+
+ /**
* Returns the expression for the exchanges inbound message body converted
* to the given type
*/
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/language/bean/BeanExpression.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/language/bean/BeanExpression.java?rev=922808&r1=922807&r2=922808&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/language/bean/BeanExpression.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/language/bean/BeanExpression.java Sun Mar 14 10:37:10 2010
@@ -16,15 +16,21 @@
*/
package org.apache.camel.language.bean;
+import java.util.List;
+import java.util.Map;
+
import org.apache.camel.Exchange;
import org.apache.camel.ExchangePattern;
import org.apache.camel.Expression;
import org.apache.camel.Predicate;
+import org.apache.camel.Processor;
import org.apache.camel.component.bean.BeanHolder;
import org.apache.camel.component.bean.BeanProcessor;
import org.apache.camel.component.bean.ConstantBeanHolder;
import org.apache.camel.component.bean.RegistryBean;
+import org.apache.camel.util.KeyValueHolder;
import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.OgnlHelper;
/**
* Evaluates an expression using a bean method invocation
@@ -59,22 +65,28 @@ public class BeanExpression implements E
} else {
holder = new ConstantBeanHolder(bean, exchange.getContext());
}
+
+ // invoking the bean can either be the easy way or using OGNL
- BeanProcessor processor = new BeanProcessor(holder);
- if (method != null) {
- processor.setMethod(method);
- }
- try {
- Exchange newExchange = exchange.copy();
- // The BeanExpression always has a result regardless of the ExchangePattern,
- // so I add a checker here to make sure we can get the result.
- if (!newExchange.getPattern().isOutCapable()) {
- newExchange.setPattern(ExchangePattern.InOut);
- }
- processor.process(newExchange);
- return newExchange.getOut().getBody();
- } catch (Exception e) {
- throw new RuntimeBeanExpressionException(exchange, beanName, method, e);
+ if (OgnlHelper.isValidOgnlExpression(method)) {
+ // okay the method is an ognl expression
+ Object beanToCall = holder.getBean();
+ OgnlInvokeProcessor ognl = new OgnlInvokeProcessor(beanToCall, method);
+ try {
+ ognl.process(exchange);
+ return ognl.getResult();
+ } catch (Exception e) {
+ throw new RuntimeBeanExpressionException(exchange, beanName, method, e);
+ }
+ } else {
+ // regular non ognl invocation
+ InvokeProcessor invoke = new InvokeProcessor(holder, method);
+ try {
+ invoke.process(exchange);
+ return invoke.getResult();
+ } catch (Exception e) {
+ throw new RuntimeBeanExpressionException(exchange, beanName, method, e);
+ }
}
}
@@ -88,4 +100,156 @@ public class BeanExpression implements E
return ObjectHelper.evaluateValuePredicate(value);
}
+ /**
+ * Invokes a given bean holder. The method name is optional.
+ */
+ private final class InvokeProcessor implements Processor {
+
+ private BeanHolder beanHolder;
+ private String methodName;
+ private Object result;
+
+ private InvokeProcessor(BeanHolder beanHolder, String methodName) {
+ this.beanHolder = beanHolder;
+ this.methodName = methodName;
+ }
+
+ public void process(Exchange exchange) throws Exception {
+ BeanProcessor processor = new BeanProcessor(beanHolder);
+ if (methodName != null) {
+ processor.setMethod(methodName);
+ }
+ try {
+ // copy the original exchange to avoid side effects on it
+ Exchange resultExchange = exchange.copy();
+ // force to use InOut to retrieve the result on the OUT message
+ resultExchange.setPattern(ExchangePattern.InOut);
+ processor.process(resultExchange);
+ result = resultExchange.getOut().getBody();
+ } catch (Exception e) {
+ throw new RuntimeBeanExpressionException(exchange, beanName, methodName, e);
+ }
+ }
+
+ public Object getResult() {
+ return result;
+ }
+ }
+
+ /**
+ * To invoke a bean using a OGNL notation which denotes the chain of methods to invoke.
+ * <p/>
+ * For more advanced OGNL you may have to look for a real framework such as OGNL, Mvel or dynamic
+ * programming language such as Groovy, JuEL, JavaScript.
+ */
+ private final class OgnlInvokeProcessor implements Processor {
+
+ private final Object bean;
+ private final String ognl;
+ private Object result;
+ private boolean startElvis;
+
+ public OgnlInvokeProcessor(Object bean, String ognl) {
+ this.bean = bean;
+ this.ognl = ognl;
+ // we must start with having bean as the result
+ this.result = bean;
+ }
+
+
+ public void process(Exchange exchange) throws Exception {
+ // copy the original exchange to avoid side effects on it
+ Exchange resultExchange = exchange.copy();
+ // force to use InOut to retrieve the result on the OUT message
+ resultExchange.setPattern(ExchangePattern.InOut);
+
+ // loop and invoke each method
+ Object beanToCall = bean;
+
+ // current ognl path as we go along
+ String ognlPath = "";
+
+ List<String> methods = OgnlHelper.splitOgnl(ognl);
+ for (String methodName : methods) {
+ BeanHolder holder = new ConstantBeanHolder(beanToCall, exchange.getContext());
+
+ // support the elvis operator
+ boolean elvis = OgnlHelper.isElvis(methodName);
+ if (startElvis) {
+ elvis = true;
+ // flip flag to not apply elvis the next time
+ startElvis = false;
+ }
+
+ // keep up with how far are we doing
+ ognlPath += methodName;
+
+ // get rid of leading ?. or . as we only needed that to determine if elvis was enabled or not
+ methodName = OgnlHelper.removeLeadingOperators(methodName);
+
+ // are we doing an index lookup (eg in Map/List/array etc)?
+ String key = null;
+ KeyValueHolder<String, String> index = OgnlHelper.isOgnlIndex(methodName);
+ if (index != null) {
+ methodName = index.getKey();
+ key = index.getValue();
+ }
+
+ // only invoke if we have a method name to use to invoke
+ if (methodName != null) {
+ InvokeProcessor invoke = new InvokeProcessor(holder, methodName);
+ invoke.process(resultExchange);
+ result = invoke.getResult();
+ }
+
+ // if there was a key then we need to lookup using the key
+ if (key != null) {
+ result = lookupResult(resultExchange, key, result, elvis, ognlPath, holder.getBean());
+ }
+
+ // check elvis for null results
+ if (result == null && elvis) {
+ return;
+ }
+
+ // prepare for next bean to invoke
+ beanToCall = result;
+ }
+ }
+
+ private Object lookupResult(Exchange exchange, String key, Object result, boolean elvis, String ognlPath, Object bean) {
+ // try map first
+ Map map = exchange.getContext().getTypeConverter().convertTo(Map.class, result);
+ if (map != null) {
+ return map.get(key);
+ }
+
+ Integer num = exchange.getContext().getTypeConverter().convertTo(Integer.class, key);
+ if (num != null) {
+ List list = exchange.getContext().getTypeConverter().convertTo(List.class, result);
+ if (list != null) {
+ if (list.size() > num - 1) {
+ return list.get(num);
+ } else if (!elvis) {
+ // not elvis then its mandatory so thrown out of bounds exception
+ throw new IndexOutOfBoundsException("Index: " + num + ", Size: " + list.size()
+ + " out of bounds with List from bean: " + bean + "using OGNL path [" + ognlPath + "]");
+ }
+ }
+ }
+
+ if (!elvis) {
+ throw new IndexOutOfBoundsException("Key: " + key + " not found in bean: " + bean + " of type: "
+ + ObjectHelper.classCanonicalName(bean) + " using OGNL path [" + ognlPath + "]");
+ } else {
+ // elvis so we can return null
+ return null;
+ }
+ }
+
+ public Object getResult() {
+ return result;
+ }
+ }
+
}
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguage.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguage.java?rev=922808&r1=922807&r2=922808&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguage.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguage.java Sun Mar 14 10:37:10 2010
@@ -16,13 +16,11 @@
*/
package org.apache.camel.language.simple;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
import org.apache.camel.Expression;
import org.apache.camel.ExpressionIllegalSyntaxException;
import org.apache.camel.builder.ExpressionBuilder;
import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.OgnlHelper;
/**
* A <a href="http://camel.apache.org/simple.html">simple language</a>
@@ -31,10 +29,12 @@ import org.apache.camel.util.ObjectHelpe
* <ul>
* <li>id to access the inbound message id</li>
* <li>in.body or body to access the inbound body</li>
+ * <li>in.body.OGNL or body.OGNL to access the inbound body using an OGNL expression</li>
* <li>bodyAs(<classname>) to convert the in body to the given type</li>
* <li>out.body to access the inbound body</li>
* <li>in.header.foo or header.foo to access an inbound header called 'foo'</li>
* <li>in.header.foo[bar] or header.foo[bar] to access an inbound header called 'foo' as a Map and lookup the map with 'bar' as key</li>
+ * <li>in.header.foo.OGNL or header.OGNL to access an inbound header called 'foo' using an OGNL expression</li>
* <li>out.header.foo to access an outbound header called 'foo'</li>
* <li>property.foo to access the exchange property called 'foo'</li>
* <li>sys.foo to access the system property called 'foo'</li>
@@ -53,6 +53,8 @@ import org.apache.camel.util.ObjectHelpe
* </li>
* </ul>
* <p/>
+ * The simple language supports OGNL notation when accessing either body or header.
+ * <p/>
* The simple language now also includes file language out of the box which means the following expression is also
* supported:
* <ul>
@@ -82,7 +84,6 @@ import org.apache.camel.util.ObjectHelpe
public class SimpleLanguage extends SimpleLanguageSupport {
private static final SimpleLanguage SIMPLE = new SimpleLanguage();
- private static final Pattern HEADER_MAP = Pattern.compile("^(.*)\\[(.*)\\]$");
public static Expression simple(String expression) {
return SIMPLE.createExpression(expression);
@@ -109,28 +110,45 @@ public class SimpleLanguage extends Simp
return ExpressionBuilder.bodyExpression(type);
}
+ // body OGNL
+ remainder = ifStartsWithReturnRemainder("body", expression);
+ if (remainder == null) {
+ remainder = ifStartsWithReturnRemainder("in.body", expression);
+ }
+ if (remainder != null) {
+ boolean invalid = OgnlHelper.isInvalidValidOgnlExpression(remainder);
+ if (invalid) {
+ throw new ExpressionIllegalSyntaxException("Valid syntax: ${body.OGNL} was: " + expression);
+ }
+ return ExpressionBuilder.bodyOgnlExpression(remainder);
+ }
+
// in header expression
- remainder = ifStartsWithReturnRemainder("in.header.", expression);
+ remainder = ifStartsWithReturnRemainder("in.headers", expression);
if (remainder == null) {
- remainder = ifStartsWithReturnRemainder("header.", expression);
+ remainder = ifStartsWithReturnRemainder("in.header", expression);
}
if (remainder == null) {
- remainder = ifStartsWithReturnRemainder("headers.", expression);
+ remainder = ifStartsWithReturnRemainder("headers", expression);
}
if (remainder == null) {
- remainder = ifStartsWithReturnRemainder("in.headers.", expression);
+ remainder = ifStartsWithReturnRemainder("header", expression);
}
if (remainder != null) {
- // could be a map based index
- Matcher matcher = HEADER_MAP.matcher(remainder);
- if (matcher.matches()) {
- String name = matcher.group(1);
- String key = matcher.group(2);
- return ExpressionBuilder.headerAsMapExpression(name, key);
+ // remove leading dot
+ remainder = remainder.substring(1);
+
+ // validate syntax
+ boolean invalid = OgnlHelper.isInvalidValidOgnlExpression(remainder);
+ if (invalid) {
+ throw new ExpressionIllegalSyntaxException("Valid syntax: ${header.name[key]} was: " + expression);
+ }
+
+ if (OgnlHelper.isValidOgnlExpression(remainder)) {
+ // ognl based header
+ return ExpressionBuilder.headersOgnlExpression(remainder);
} else {
- if (remainder.contains("[") || remainder.contains("]")) {
- throw new ExpressionIllegalSyntaxException("Valid syntax: ${header.name[key]} was: " + expression);
- }
+ // regular header
return ExpressionBuilder.headerExpression(remainder);
}
}
Added: camel/trunk/camel-core/src/main/java/org/apache/camel/util/OgnlHelper.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/util/OgnlHelper.java?rev=922808&view=auto
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/util/OgnlHelper.java (added)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/util/OgnlHelper.java Sun Mar 14 10:37:10 2010
@@ -0,0 +1,212 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Helper for Camel OGNL expressions.
+ *
+ * @version $Revision$
+ */
+public final class OgnlHelper {
+
+ private static final Pattern INDEX_PATTERN = Pattern.compile("^(.*)\\[(.*)\\]$");
+
+ private OgnlHelper() {
+ }
+
+ /**
+ * Tests whether or not the given String is a Camel OGNL expression.
+ * <p/>
+ * Its consider Camel OGNL expression when it contains either one of the following chars: . or [
+ *
+ * @param expression the String
+ * @return <tt>true</tt> if Camel OGNL expression, otherwise <tt>false</tt>.
+ */
+ public static boolean isValidOgnlExpression(String expression) {
+ if (ObjectHelper.isEmpty(expression)) {
+ return false;
+ }
+
+ // TODO: if possible used regexp to parse if its valid/invalid
+
+ // the brackets should come in pair
+ int bracketBegin = StringHelper.countChar(expression, '[');
+ int bracketEnd = StringHelper.countChar(expression, ']');
+ if (bracketBegin > 0 && bracketEnd > 0) {
+ return bracketBegin == bracketEnd;
+ }
+
+ return expression.contains(".");
+ }
+
+ public static boolean isInvalidValidOgnlExpression(String expression) {
+ if (ObjectHelper.isEmpty(expression)) {
+ return false;
+ }
+
+ if (!expression.contains(".") && !expression.contains("[") && !expression.contains("]")) {
+ return false;
+ }
+
+ // TODO: if possible used regexp to parse if its valid/invalid
+
+ // the brackets should come in pair
+ int bracketBegin = StringHelper.countChar(expression, '[');
+ int bracketEnd = StringHelper.countChar(expression, ']');
+ if (bracketBegin > 0 || bracketEnd > 0) {
+ return bracketBegin != bracketEnd;
+ }
+
+ // check for double dots
+ if (expression.contains("..")) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Tests whether or not the given Camel OGNL expression is using the elvis operator or not.
+ *
+ * @param ognlExpression the Camel OGNL expression
+ * @return <tt>true</tt> if the elvis operator is used, otherwise <tt>false</tt>.
+ */
+ public static boolean isElvis(String ognlExpression) {
+ if (ObjectHelper.isEmpty(ognlExpression)) {
+ return false;
+ }
+
+ return ognlExpression.startsWith("?");
+ }
+
+ /**
+ * Removes any leading operators from the Camel OGNL expression.
+ * <p/>
+ * Will remove any leading of the following chars: ? or .
+ *
+ * @param ognlExpression the Camel OGNL expression
+ * @return the Camel OGNL expression without any leading operators.
+ */
+ public static String removeLeadingOperators(String ognlExpression) {
+ if (ObjectHelper.isEmpty(ognlExpression)) {
+ return ognlExpression;
+ }
+
+ if (ognlExpression.startsWith("?")) {
+ ognlExpression = ognlExpression.substring(1);
+ }
+ if (ognlExpression.startsWith(".")) {
+ ognlExpression = ognlExpression.substring(1);
+ }
+
+ return ognlExpression;
+ }
+
+ /**
+ * Removes any trailing operators from the Camel OGNL expression.
+ *
+ * @param ognlExpression the Camel OGNL expression
+ * @return the Camel OGNL expression without any trailing operators.
+ */
+ public static String removeTrailingOperators(String ognlExpression) {
+ if (ObjectHelper.isEmpty(ognlExpression)) {
+ return ognlExpression;
+ }
+
+ if (ognlExpression.contains("[")) {
+ return ObjectHelper.before(ognlExpression, "[");
+ }
+ return ognlExpression;
+ }
+
+ public static String removeOperators(String ognlExpression) {
+ return removeLeadingOperators(removeTrailingOperators(ognlExpression));
+ }
+
+ public static KeyValueHolder<String, String> isOgnlIndex(String ognlExpression) {
+ Matcher matcher = INDEX_PATTERN.matcher(ognlExpression);
+ if (matcher.matches()) {
+
+ // to avoid empty strings as we want key/value to be null in such cases
+ String key = matcher.group(1);
+ if (ObjectHelper.isEmpty(key)) {
+ key = null;
+ }
+
+ // to avoid empty strings as we want key/value to be null in such cases
+ String value = matcher.group(2);
+ if (ObjectHelper.isEmpty(value)) {
+ value = null;
+ }
+
+ return new KeyValueHolder<String, String>(key, value);
+ }
+
+ return null;
+ }
+
+ /**
+ * Regular expression with repeating groups is a pain to get right
+ * and then nobody understands the reg exp afterwards.
+ * So use a bit ugly/low-level java code to split the ognl into methods.
+ */
+ public static List<String> splitOgnl(String ognl) {
+ // TODO: if possible use reg exp to split instead
+
+ List<String> methods = new ArrayList<String>();
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < ognl.length(); i++) {
+ char ch = ognl.charAt(i);
+ // special for starting
+ if (i == 0 || (i == 1 && ognl.charAt(0) == '?')
+ || (ch != '.' && ch != '?')) {
+ sb.append(ch);
+ } else {
+ if (ch == '.') {
+ String s = sb.toString();
+
+ // reset sb
+ sb.setLength(0);
+
+ // pass over ? to the new method
+ if (s.endsWith("?")) {
+ sb.append("?");
+ s = s.substring(0, s.length() - 1);
+ }
+
+ // add the method
+ methods.add(s);
+ }
+ // and dont lose the char
+ sb.append(ch);
+ }
+ }
+ // add remainder in buffer
+ if (sb.length() > 0) {
+ methods.add(sb.toString());
+ }
+
+ return methods;
+ }
+
+}
Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/util/OgnlHelper.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: camel/trunk/camel-core/src/main/java/org/apache/camel/util/OgnlHelper.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/util/StringHelper.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/util/StringHelper.java?rev=922808&r1=922807&r2=922808&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/util/StringHelper.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/util/StringHelper.java Sun Mar 14 10:37:10 2010
@@ -44,5 +44,28 @@ public final class StringHelper {
.replace('/', '-')
.replace('\\', '-');
}
+
+ /**
+ * Counts the number of times the given char is in the string
+ *
+ * @param s the string
+ * @param ch the char
+ * @return number of times char is located in the string
+ */
+ public static int countChar(String s, char ch) {
+ if (ObjectHelper.isEmpty(s)) {
+ return 0;
+ }
+
+ int matches = 0;
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (ch == c) {
+ matches++;
+ }
+ }
+
+ return matches;
+ }
}
Added: camel/trunk/camel-core/src/test/java/org/apache/camel/language/BeanLanguageOGNLTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/language/BeanLanguageOGNLTest.java?rev=922808&view=auto
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/language/BeanLanguageOGNLTest.java (added)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/language/BeanLanguageOGNLTest.java Sun Mar 14 10:37:10 2010
@@ -0,0 +1,60 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.language;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+
+/**
+ * @version $Revision$
+ */
+public class BeanLanguageOGNLTest extends ContextTestSupport {
+
+ public void testBeanLanguageOGNL() throws Exception {
+ String reply = template.requestBody("direct:start", "World", String.class);
+ assertEquals("Hello World", reply);
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start")
+ .transform().method(MyReallyCoolBean.class, "getOther.greet");
+ }
+ };
+ }
+
+ public static class MyReallyCoolBean {
+
+ private MyOtherReallyCoolBean other = new MyOtherReallyCoolBean();
+
+ public MyOtherReallyCoolBean getOther() {
+ return other;
+ }
+
+ }
+
+ public static class MyOtherReallyCoolBean {
+
+ public String greet(String name) {
+ return "Hello " + name;
+ }
+
+ }
+}
Propchange: camel/trunk/camel-core/src/test/java/org/apache/camel/language/BeanLanguageOGNLTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: camel/trunk/camel-core/src/test/java/org/apache/camel/language/BeanLanguageOGNLTest.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Modified: camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleTest.java?rev=922808&r1=922807&r2=922808&view=diff
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleTest.java (original)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleTest.java Sun Mar 14 10:37:10 2010
@@ -16,13 +16,17 @@
*/
package org.apache.camel.language;
+import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.apache.camel.ExpressionIllegalSyntaxException;
import org.apache.camel.LanguageTestSupport;
+import org.apache.camel.component.bean.MethodNotFoundException;
+import org.apache.camel.language.bean.RuntimeBeanExpressionException;
/**
* @version $Revision$
@@ -161,7 +165,43 @@ public class SimpleTest extends Language
}
}
- public void testHeaderMap() throws Exception {
+ public void testOGNLHeaderList() throws Exception {
+ List<String> lines = new ArrayList<String>();
+ lines.add("Camel in Action");
+ lines.add("ActiveMQ in Action");
+ exchange.getIn().setHeader("wicket", lines);
+
+ assertExpression("${header.wicket[0]}", "Camel in Action");
+ assertExpression("${header.wicket[1]}", "ActiveMQ in Action");
+ try {
+ assertExpression("${header.wicket[2]}", "");
+ fail("Should have thrown an exception");
+ } catch (Exception e) {
+ IndexOutOfBoundsException cause = assertIsInstanceOf(IndexOutOfBoundsException.class, e.getCause());
+ assertEquals("Index: 2, Size: 2", cause.getMessage());
+ }
+ assertExpression("${header.unknown[cool]}", "");
+ }
+
+ public void testOGNLHeaderLinesList() throws Exception {
+ List<OrderLine> lines = new ArrayList<OrderLine>();
+ lines.add(new OrderLine(123, "Camel in Action"));
+ lines.add(new OrderLine(456, "ActiveMQ in Action"));
+ exchange.getIn().setHeader("wicket", lines);
+
+ assertExpression("${header.wicket[0].getId}", 123);
+ assertExpression("${header.wicket[1].getName}", "ActiveMQ in Action");
+ try {
+ assertExpression("${header.wicket[2]}", "");
+ fail("Should have thrown an exception");
+ } catch (Exception e) {
+ IndexOutOfBoundsException cause = assertIsInstanceOf(IndexOutOfBoundsException.class, e.getCause());
+ assertEquals("Index: 2, Size: 2", cause.getMessage());
+ }
+ assertExpression("${header.unknown[cool]}", "");
+ }
+
+ public void testOGNLHeaderMap() throws Exception {
Map map = new HashMap();
map.put("cool", "Camel rocks");
map.put("dude", "Hey dude");
@@ -172,19 +212,22 @@ public class SimpleTest extends Language
assertExpression("${header.wicket[dude]}", "Hey dude");
assertExpression("${header.wicket[unknown]}", "");
assertExpression("${header.wicket[code]}", 4321);
+ // no header named unknown
+ assertExpression("${header?.unknown[cool]}", "");
assertExpression("${header.unknown[cool]}", "");
}
- public void testHeaderMapNotMap() throws Exception {
+ public void testOGNLHeaderMapNotMap() throws Exception {
try {
assertExpression("${header.foo[bar]}", null);
fail("Should have thrown an exception");
- } catch (IllegalArgumentException e) {
- assertEquals("Header foo cannot be converted to a Map on headerAsMap(foo)[bar]", e.getMessage());
+ } catch (RuntimeBeanExpressionException e) {
+ IndexOutOfBoundsException cause = assertIsInstanceOf(IndexOutOfBoundsException.class, e.getCause());
+ assertEquals("Key: bar not found in bean: abc of type: java.lang.String using OGNL path [[bar]]", cause.getMessage());
}
}
- public void testHeaderMapIllegalSyntax() throws Exception {
+ public void testOGNLHeaderMapIllegalSyntax() throws Exception {
try {
assertExpression("${header.foo[bar}", null);
fail("Should have thrown an exception");
@@ -193,8 +236,225 @@ public class SimpleTest extends Language
}
}
+ public void testBodyOGNLSimple() throws Exception {
+ Animal camel = new Animal("Camel", 6);
+ exchange.getIn().setBody(camel);
+
+ assertExpression("${in.body.getName}", "Camel");
+ assertExpression("${in.body.getAge}", 6);
+ }
+
+ public void testBodyOGNLNested() throws Exception {
+ Animal tiger = new Animal("Tony the Tiger", 13);
+ Animal camel = new Animal("Camel", 6);
+ camel.setFriend(tiger);
+
+ exchange.getIn().setBody(camel);
+
+ assertExpression("${in.body.getName}", "Camel");
+ assertExpression("${in.body.getAge}", 6);
+
+ assertExpression("${in.body.getFriend.getName}", "Tony the Tiger");
+ assertExpression("${in.body.getFriend.getAge}", "13");
+ }
+
+ public void testBodyOGNLOrderList() throws Exception {
+ List<OrderLine> lines = new ArrayList<OrderLine>();
+ lines.add(new OrderLine(123, "Camel in Action"));
+ lines.add(new OrderLine(456, "ActiveMQ in Action"));
+ Order order = new Order(lines);
+
+ exchange.getIn().setBody(order);
+
+ assertExpression("${in.body.getLines[0].getId}", 123);
+ assertExpression("${in.body.getLines[0].getName}", "Camel in Action");
+
+ assertExpression("${in.body.getLines[1].getId}", 456);
+ assertExpression("${in.body.getLines[1].getName}", "ActiveMQ in Action");
+ }
+
+ public void testBodyOGNLList() throws Exception {
+ List<OrderLine> lines = new ArrayList<OrderLine>();
+ lines.add(new OrderLine(123, "Camel in Action"));
+ lines.add(new OrderLine(456, "ActiveMQ in Action"));
+
+ exchange.getIn().setBody(lines);
+
+ assertExpression("${in.body[0].getId}", 123);
+ assertExpression("${in.body[0].getName}", "Camel in Action");
+
+ assertExpression("${in.body[1].getId}", 456);
+ assertExpression("${in.body[1].getName}", "ActiveMQ in Action");
+ }
+
+ public void testBodyOGNLArray() throws Exception {
+ OrderLine[] lines = new OrderLine[2];
+ lines[0] = new OrderLine(123, "Camel in Action");
+ lines[1] = new OrderLine(456, "ActiveMQ in Action");
+
+ exchange.getIn().setBody(lines);
+
+ assertExpression("${in.body[0].getId}", 123);
+ assertExpression("${in.body[0].getName}", "Camel in Action");
+
+ assertExpression("${in.body[1].getId}", 456);
+ assertExpression("${in.body[1].getName}", "ActiveMQ in Action");
+ }
+
+ public void testBodyOGNLOrderListOutOfBounds() throws Exception {
+ List<OrderLine> lines = new ArrayList<OrderLine>();
+ lines.add(new OrderLine(123, "Camel in Action"));
+ lines.add(new OrderLine(456, "ActiveMQ in Action"));
+ Order order = new Order(lines);
+
+ exchange.getIn().setBody(order);
+
+ try {
+ assertExpression("${in.body.getLines[3].getId}", 123);
+ fail("Should have thrown an exception");
+ } catch (RuntimeBeanExpressionException e) {
+ IndexOutOfBoundsException cause = assertIsInstanceOf(IndexOutOfBoundsException.class, e.getCause());
+
+ assertTrue(cause.getMessage().startsWith("Index: 3, Size: 2 out of bounds with List from bean"));
+ }
+ }
+
+ public void testBodyOGNLOrderListOutOfBoundsWithElvis() throws Exception {
+ List<OrderLine> lines = new ArrayList<OrderLine>();
+ lines.add(new OrderLine(123, "Camel in Action"));
+ lines.add(new OrderLine(456, "ActiveMQ in Action"));
+ Order order = new Order(lines);
+
+ exchange.getIn().setBody(order);
+
+ assertExpression("${in.body?.getLines[3].getId}", "");
+ }
+
+ public void testBodyOGNLOrderListNoMethodNameWithElvis() throws Exception {
+ List<OrderLine> lines = new ArrayList<OrderLine>();
+ lines.add(new OrderLine(123, "Camel in Action"));
+ lines.add(new OrderLine(456, "ActiveMQ in Action"));
+ Order order = new Order(lines);
+
+ exchange.getIn().setBody(order);
+
+ try {
+ assertExpression("${in.body.getLines[0]?.getRating}", "");
+ fail("Should have thrown exception");
+ } catch (RuntimeBeanExpressionException e) {
+ MethodNotFoundException cause = assertIsInstanceOf(MethodNotFoundException.class, e.getCause().getCause());
+ assertEquals("getRating", cause.getMethodName());
+ }
+ }
+
+ public void testBodyOGNLElvisToAvoidNPE() throws Exception {
+ Animal tiger = new Animal("Tony the Tiger", 13);
+ Animal camel = new Animal("Camel", 6);
+ camel.setFriend(tiger);
+
+ exchange.getIn().setBody(camel);
+
+ assertExpression("${in.body.getName}", "Camel");
+ assertExpression("${in.body.getAge}", 6);
+
+ assertExpression("${in.body.getFriend.getName}", "Tony the Tiger");
+ assertExpression("${in.body.getFriend.getAge}", "13");
+
+ // using elvis to avoid the NPE
+ assertExpression("${in.body.getFriend?.getFriend.getName}", "");
+ try {
+ // without elvis we get an NPE
+ assertExpression("${in.body.getFriend.getFriend.getName}", "");
+ fail("Should have thrown exception");
+ } catch (RuntimeBeanExpressionException e) {
+ assertEquals("Failed to invoke method: .getFriend.getFriend.getName on null due to: java.lang.NullPointerException", e.getMessage());
+ assertIsInstanceOf(NullPointerException.class, e.getCause());
+ }
+ }
+
+ public void testBodyOGNLReentrant() throws Exception {
+ Animal camel = new Animal("Camel", 6);
+ Animal tiger = new Animal("Tony the Tiger", 13);
+ Animal elephant = new Animal("Big Ella", 48);
+
+ camel.setFriend(tiger);
+ tiger.setFriend(elephant);
+ elephant.setFriend(camel);
+
+ exchange.getIn().setBody(camel);
+
+ assertExpression("${body.getFriend.getFriend.getFriend.getName}", "Camel");
+ assertExpression("${body.getFriend.getFriend.getFriend.getFriend.getName}", "Tony the Tiger");
+ assertExpression("${body.getFriend.getFriend.getFriend.getFriend.getFriend.getName}", "Big Ella");
+ }
protected String getLanguageName() {
return "simple";
}
+
+ public static final class Animal {
+ private String name;
+ private int age;
+ private Animal friend;
+
+ private Animal(String name, int age) {
+ this.name = name;
+ this.age = age;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public Animal getFriend() {
+ return friend;
+ }
+
+ public void setFriend(Animal friend) {
+ this.friend = friend;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+
+ public static final class Order {
+ private List lines;
+
+ public Order(List lines) {
+ this.lines = lines;
+ }
+
+ public List getLines() {
+ return lines;
+ }
+
+ public void setLines(List lines) {
+ this.lines = lines;
+ }
+ }
+
+ public static final class OrderLine {
+ private int id;
+ private String name;
+
+ public OrderLine(int id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
}
\ No newline at end of file
Modified: camel/trunk/camel-core/src/test/java/org/apache/camel/util/StringHelperTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/util/StringHelperTest.java?rev=922808&r1=922807&r2=922808&view=diff
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/util/StringHelperTest.java (original)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/util/StringHelperTest.java Sun Mar 14 10:37:10 2010
@@ -35,4 +35,13 @@ public class StringHelperTest extends Te
assertTrue("Should not contain . ", out.indexOf('.') == -1);
}
+ public void testCountChar() {
+ assertEquals(0, StringHelper.countChar("Hello World", 'x'));
+ assertEquals(1, StringHelper.countChar("Hello World", 'e'));
+ assertEquals(3, StringHelper.countChar("Hello World", 'l'));
+ assertEquals(1, StringHelper.countChar("Hello World", ' '));
+ assertEquals(0, StringHelper.countChar("", ' '));
+ assertEquals(0, StringHelper.countChar(null, ' '));
+ }
+
}