Great work Claus. I look forward to using this! On Sun, Feb 15, 2009 at 2:19 PM, <davscl...@apache.org> wrote:
> Author: davsclaus > Date: Sun Feb 15 17:49:04 2009 > New Revision: 744707 > > URL: http://svn.apache.org/viewvc?rev=744707&view=rev > Log: > CAMEL-1338: Added basic operator support for simple language - end users is > confused its not working, and nice to have core support for basic operators. > Added ?method=methodname for the bean langauge so its in line with the bean > component. > > Added: > > > camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLangaugeOperator.java > (with props) > > > camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleOperatorTest.java > - copied, changed from r744631, > camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleTest.java > 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/BeanLanguage.java > > > camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguageSupport.java > > camel/trunk/camel-core/src/main/java/org/apache/camel/util/ObjectHelper.java > > camel/trunk/camel-core/src/test/java/org/apache/camel/language/BeanTest.java > > > camel/trunk/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.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=744707&r1=744706&r2=744707&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 Feb 15 17:49:04 2009 > @@ -290,6 +290,22 @@ > } > > /** > + * Returns the expression for the exchanges inbound message body type > + */ > + public static Expression bodyType() { > + return new ExpressionAdapter() { > + public Object evaluate(Exchange exchange) { > + return exchange.getIn().getBody().getClass(); > + } > + > + @Override > + public String toString() { > + return "bodyType"; > + } > + }; > + } > + > + /** > * Returns the expression for the exchanges inbound message body > converted > * to the given type > */ > @@ -445,6 +461,23 @@ > } > > /** > + * Returns an expression which converts the given expression to the > given type the type > + * expression is evaluted to > + */ > + public static Expression convertTo(final Expression expression, final > Expression type) { > + return new ExpressionAdapter() { > + public Object evaluate(Exchange exchange) { > + return expression.evaluate(exchange, > type.evaluate(exchange).getClass()); > + } > + > + @Override > + public String toString() { > + return "" + expression + ".convertTo(" + type + ")"; > + } > + }; > + } > + > + /** > * Returns a tokenize expression which will tokenize the string with > the > * given token > */ > > Modified: > camel/trunk/camel-core/src/main/java/org/apache/camel/language/bean/BeanLanguage.java > URL: > http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/language/bean/BeanLanguage.java?rev=744707&r1=744706&r2=744707&view=diff > > ============================================================================== > --- > camel/trunk/camel-core/src/main/java/org/apache/camel/language/bean/BeanLanguage.java > (original) > +++ > camel/trunk/camel-core/src/main/java/org/apache/camel/language/bean/BeanLanguage.java > Sun Feb 15 17:49:04 2009 > @@ -82,13 +82,20 @@ > public Expression createExpression(String expression) { > ObjectHelper.notNull(expression, "expression"); > > - int idx = expression.lastIndexOf('.'); > String beanName = expression; > String method = null; > + > + // we support both the .method name and the ?method= syntax > + // as the ?method= syntax is very common for the bean component > + int idx = expression.lastIndexOf('.'); > if (idx > 0) { > beanName = expression.substring(0, idx); > method = expression.substring(idx + 1); > + } else if (expression.contains("?method=")) { > + beanName = ObjectHelper.before(expression, "?"); > + method = ObjectHelper.after(expression, "?method="); > } > + > return new BeanExpression(beanName, method); > } > > > Added: > camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLangaugeOperator.java > URL: > http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLangaugeOperator.java?rev=744707&view=auto > > ============================================================================== > --- > camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLangaugeOperator.java > (added) > +++ > camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLangaugeOperator.java > Sun Feb 15 17:49:04 2009 > @@ -0,0 +1,72 @@ > +/** > + * 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.simple; > + > +/** > + * Operators supported by simple language > + * <ul> > + * <li>EQ : ==</li> > + * <li>GT : ></li> > + * <li>GTE : >=</li> > + * <li>LT : <</li> > + * <li>LTE : <=</li> > + * <li>NOT : !=</li> > + * </ul> > + */ > +public enum SimpleLangaugeOperator { > + > + EQ, GT, GTE, LT, LTE, NOT; > + > + public static SimpleLangaugeOperator asOperator(String text) { > + if ("==".equals(text)) { > + return EQ; > + } else if (">".equals(text)) { > + return GT; > + } else if (">=".equals(text)) { > + return GTE; > + } else if ("<".equals(text)) { > + return LT; > + } else if ("<=".equals(text)) { > + return LTE; > + } else if ("!=".equals(text)) { > + return NOT; > + } > + throw new IllegalArgumentException("Operator not supported: " + > text); > + } > + > + public String getOperatorText(SimpleLangaugeOperator operator) { > + if (operator == EQ) { > + return "=="; > + } else if (operator == GT) { > + return ">"; > + } else if (operator == GTE) { > + return ">="; > + } else if (operator == LT) { > + return "<"; > + } else if (operator == LTE) { > + return "<="; > + } else if (operator == NOT) { > + return "!="; > + } > + return ""; > + } > + > + @Override > + public String toString() { > + return getOperatorText(this); > + } > +} > > Propchange: > camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLangaugeOperator.java > > ------------------------------------------------------------------------------ > svn:eol-style = native > > Propchange: > camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLangaugeOperator.java > > ------------------------------------------------------------------------------ > svn:keywords = Rev Date > > Modified: > camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguageSupport.java > URL: > http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguageSupport.java?rev=744707&r1=744706&r2=744707&view=diff > > ============================================================================== > --- > camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguageSupport.java > (original) > +++ > camel/trunk/camel-core/src/main/java/org/apache/camel/language/simple/SimpleLanguageSupport.java > Sun Feb 15 17:49:04 2009 > @@ -18,30 +18,113 @@ > > import java.util.ArrayList; > import java.util.List; > +import java.util.regex.Matcher; > +import java.util.regex.Pattern; > > +import org.apache.camel.Exchange; > import org.apache.camel.Expression; > import org.apache.camel.Predicate; > import org.apache.camel.builder.ExpressionBuilder; > import org.apache.camel.builder.PredicateBuilder; > +import org.apache.camel.impl.ExpressionAdapter; > import org.apache.camel.spi.Language; > +import org.apache.camel.util.ObjectHelper; > +import org.apache.commons.logging.Log; > +import org.apache.commons.logging.LogFactory; > +import static org.apache.camel.language.simple.SimpleLangaugeOperator.*; > > /** > * Abstract base class for Simple languages. > */ > public abstract class SimpleLanguageSupport implements Language { > - > + > + protected static final Pattern PATTERN = > Pattern.compile("^\\$\\{(.+)\\}\\s+(==|>|>=|<|<=|!=|is)\\s+(.+)$"); > + protected final Log log = LogFactory.getLog(getClass()); > + > public Predicate createPredicate(String expression) { > return PredicateBuilder.toPredicate(createExpression(expression)); > } > > public Expression createExpression(String expression) { > - if (expression.indexOf("${") >= 0) { > - return createComplexExpression(expression); > + Matcher matcher = PATTERN.matcher(expression); > + if (matcher.matches()) { > + if (log.isDebugEnabled()) { > + log.debug("Expression is evaluated as operator expression: > " + expression); > + } > + return createOperatorExpression(matcher, expression); > + } else if (expression.indexOf("${") >= 0) { > + if (log.isDebugEnabled()) { > + log.debug("Expression is evaluated as complex expression: > " + expression); > + } > + return createComplexConcatExpression(expression); > + } else { > + if (log.isDebugEnabled()) { > + log.debug("Expression is evaluated as simple expression: " > + expression); > + } > + return createSimpleExpression(expression); > } > - return createSimpleExpression(expression); > } > > - protected Expression createComplexExpression(String expression) { > + private Expression createOperatorExpression(final Matcher matcher, > final String expression) { > + final Expression left = createSimpleExpression(matcher.group(1)); > + final SimpleLangaugeOperator operator = > asOperator(matcher.group(2)); > + > + // the right hand side expression can either be a constant > expression wiht ' ' > + // or another simple expression using ${ } placeholders > + String text = matcher.group(3); > + > + final Expression right; > + // special null handling > + if ("null".equals(text)) { > + right = createConstantExpression(null); > + } else { > + // text can either be a constant enclosed by ' ' or another > expression using ${ } placeholders > + String constant = ObjectHelper.between(text, "'", "'"); > + String simple = ObjectHelper.between(text, "${", "}"); > + > + Expression exp = simple != null ? > createSimpleExpression(simple) : createConstantExpression(constant); > + // to support numeric comparions using > and < operators we > must convert the right hand side > + // to the same type as the left > + right = ExpressionBuilder.convertTo(exp, left); > + } > + > + return new ExpressionAdapter() { > + @Override > + protected String assertionFailureMessage(Exchange exchange) { > + return super.assertionFailureMessage(exchange); > + } > + > + @Override > + public Object evaluate(Exchange exchange) { > + Predicate predicate = null; > + if (operator == EQ) { > + predicate = PredicateBuilder.isEqualTo(left, right); > + } else if (operator == GT) { > + predicate = PredicateBuilder.isGreaterThan(left, > right); > + } else if (operator == GTE) { > + predicate = > PredicateBuilder.isGreaterThanOrEqualTo(left, right); > + } else if (operator == LT) { > + predicate = PredicateBuilder.isLessThan(left, right); > + } else if (operator == LTE) { > + predicate = PredicateBuilder.isLessThanOrEqualTo(left, > right); > + } else if (operator == NOT) { > + predicate = PredicateBuilder.isNotEqualTo(left, > right); > + } > + > + if (predicate == null) { > + throw new IllegalArgumentException("Unsupported > operator: " + operator + " for expression: " + expression); > + } > + return predicate.matches(exchange); > + } > + > + @Override > + public String toString() { > + return left + " " + operator + " " + right; > + } > + }; > + } > + > + protected Expression createComplexConcatExpression(String expression) > { > List<Expression> results = new ArrayList<Expression>(); > > int pivot = 0; > @@ -74,6 +157,10 @@ > return > ExpressionBuilder.constantExpression(expression.substring(start, end)); > } > > + protected Expression createConstantExpression(String expression) { > + return ExpressionBuilder.constantExpression(expression); > + } > + > /** > * Creates the simple expression based on the extracted content from > the ${ } place holders > * > > Modified: > camel/trunk/camel-core/src/main/java/org/apache/camel/util/ObjectHelper.java > URL: > http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/util/ObjectHelper.java?rev=744707&r1=744706&r2=744707&view=diff > > ============================================================================== > --- > camel/trunk/camel-core/src/main/java/org/apache/camel/util/ObjectHelper.java > (original) > +++ > camel/trunk/camel-core/src/main/java/org/apache/camel/util/ObjectHelper.java > Sun Feb 15 17:49:04 2009 > @@ -291,6 +291,28 @@ > return answer; > } > > + public static String after(String text, String after) { > + if (!text.contains(after)) { > + return null; > + } > + return text.substring(text.indexOf(after) + after.length()); > + } > + > + public static String before(String text, String before) { > + if (!text.contains(before)) { > + return null; > + } > + return text.substring(0, text.indexOf(before)); > + } > + > + public static String between(String text, String after, String before) > { > + text = after(text, after); > + if (text == null) { > + return null; > + } > + return before(text, before); > + } > + > /** > * Returns true if the collection contains the specified value > */ > > Modified: > camel/trunk/camel-core/src/test/java/org/apache/camel/language/BeanTest.java > URL: > http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/language/BeanTest.java?rev=744707&r1=744706&r2=744707&view=diff > > ============================================================================== > --- > camel/trunk/camel-core/src/test/java/org/apache/camel/language/BeanTest.java > (original) > +++ > camel/trunk/camel-core/src/test/java/org/apache/camel/language/BeanTest.java > Sun Feb 15 17:49:04 2009 > @@ -32,10 +32,12 @@ > > public void testSimpleExpressions() throws Exception { > assertExpression("foo.cheese", "abc"); > + assertExpression("foo?method=cheese", "abc"); > } > > public void testPredicates() throws Exception { > assertPredicate("foo.isFooHeaderAbc"); > + assertPredicate("foo?method=isFooHeaderAbc"); > } > > public void testBeanTypeExpression() throws Exception { > > Copied: > camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleOperatorTest.java > (from r744631, > 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/SimpleOperatorTest.java?p2=camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleOperatorTest.java&p1=camel/trunk/camel-core/src/test/java/org/apache/camel/language/SimpleTest.java&r1=744631&r2=744707&rev=744707&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/SimpleOperatorTest.java > Sun Feb 15 17:49:04 2009 > @@ -16,63 +16,128 @@ > */ > package org.apache.camel.language; > > +import org.apache.camel.Exchange; > import org.apache.camel.LanguageTestSupport; > +import org.apache.camel.impl.JndiRegistry; > > /** > * @version $Revision$ > */ > -public class SimpleTest extends LanguageTestSupport { > +public class SimpleOperatorTest extends LanguageTestSupport { > > - public void testConstantExpression() throws Exception { > - try { > - assertExpression("Hello World", "Hello World"); > - fail("Should have thrown an Exception"); > - } catch (IllegalSyntaxException e) { > - // constants is not supported > - } > + @Override > + protected JndiRegistry createRegistry() throws Exception { > + JndiRegistry jndi = super.createRegistry(); > + jndi.bind("generator", new MyFileNameGenerator()); > + return jndi; > } > > - public void testSimpleExpressions() throws Exception { > - assertExpression("id", exchange.getIn().getMessageId()); > - assertExpression("body", "<hello id='m123'>world!</hello>"); > - assertExpression("in.body", "<hello id='m123'>world!</hello>"); > - assertExpression("in.header.foo", "abc"); > - assertExpression("header.foo", "abc"); > - } > - > - public void testComplexExpressions() throws Exception { > - assertExpression("hey ${in.header.foo}", "hey abc"); > - assertExpression("hey ${in.header.foo}!", "hey abc!"); > - assertExpression("hey ${in.header.foo}-${in.header.foo}!", "hey > abc-abc!"); > - assertExpression("hey ${in.header.foo}${in.header.foo}", "hey > abcabc"); > - assertExpression("${in.header.foo}${in.header.foo}", "abcabc"); > - assertExpression("${in.header.foo}", "abc"); > - assertExpression("${in.header.foo}!", "abc!"); > + public void testEqualOperator() throws Exception { > + // string to string comparison > + assertExpression("${in.header.foo} == 'abc'", true); > + assertExpression("${in.header.foo} == 'def'", false); > + assertExpression("${in.header.foo} == '1'", false); > + > + // integer to string comparioson > + assertExpression("${in.header.bar} == '123'", true); > + assertExpression("${in.header.bar} == '444'", false); > + assertExpression("${in.header.bar} == '1'", false); > } > > + public void testNotEqualOperator() throws Exception { > + // string to string comparison > + assertExpression("${in.header.foo} != 'abc'", false); > + assertExpression("${in.header.foo} != 'def'", true); > + assertExpression("${in.header.foo} != '1'", true); > > - public void testInvalidComplexExpression() throws Exception { > - try { > - assertExpression("hey ${foo", "bad expression!"); > - fail("Should have thrown an exception!"); > - } catch (IllegalArgumentException e) { > - log.debug("Caught expected exception: " + e, e); > - } > + // integer to string comparioson > + assertExpression("${in.header.bar} != '123'", false); > + assertExpression("${in.header.bar} != '444'", true); > + assertExpression("${in.header.bar} != '1'", true); > + } > + > + public void testGreatherThanOperator() throws Exception { > + // string to string comparison > + assertExpression("${in.header.foo} > 'aaa'", true); > + assertExpression("${in.header.foo} > 'def'", false); > + > + // integer to string comparioson > + assertExpression("${in.header.bar} > '100'", true); > + assertExpression("${in.header.bar} > '123'", false); > + assertExpression("${in.header.bar} > '200'", false); > + } > + > + public void testGreatherThanOrEqualOperator() throws Exception { > + // string to string comparison > + assertExpression("${in.header.foo} >= 'aaa'", true); > + assertExpression("${in.header.foo} >= 'abc'", true); > + assertExpression("${in.header.foo} >= 'def'", false); > + > + // integer to string comparioson > + assertExpression("${in.header.bar} >= '100'", true); > + assertExpression("${in.header.bar} >= '123'", true); > + assertExpression("${in.header.bar} >= '200'", false); > + } > + > + public void testLessThanOperator() throws Exception { > + // string to string comparison > + assertExpression("${in.header.foo} < 'aaa'", false); > + assertExpression("${in.header.foo} < 'def'", true); > + > + // integer to string comparioson > + assertExpression("${in.header.bar} < '100'", false); > + assertExpression("${in.header.bar} < '123'", false); > + assertExpression("${in.header.bar} < '200'", true); > + } > + > + public void testLessThanOrEqualOperator() throws Exception { > + // string to string comparison > + assertExpression("${in.header.foo} <= 'aaa'", false); > + assertExpression("${in.header.foo} <= 'abc'", true); > + assertExpression("${in.header.foo} <= 'def'", true); > + > + // integer to string comparioson > + assertExpression("${in.header.bar} <= '100'", false); > + assertExpression("${in.header.bar} <= '123'", true); > + assertExpression("${in.header.bar} <= '200'", true); > + } > + > + public void testIsNull() throws Exception { > + assertExpression("${in.header.foo} == null", false); > + assertExpression("${in.header.none} == null", true); > } > > - public void testPredicates() throws Exception { > - assertPredicate("body"); > - assertPredicate("header.foo"); > - assertPredicate("header.madeUpHeader", false); > + public void testIsNotNull() throws Exception { > + assertExpression("${in.header.foo} != null", true); > + assertExpression("${in.header.none} != null", false); > } > > - public void testExceptionMessage() throws Exception { > - exchange.setException(new IllegalArgumentException("Just > testing")); > - assertExpression("exception.message", "Just testing"); > - assertExpression("Hello ${exception.message} World", "Hello Just > testing World"); > + public void testRightOperatorIsSimpleLanauge() throws Exception { > + // operator on right side is also using ${ } placeholders > + assertExpression("${in.header.foo} == ${in.header.foo}", true); > + assertExpression("${in.header.foo} == ${in.header.bar}", false); > + } > + > + public void testRightOperatorIsBeanLanauge() throws Exception { > + // operator on right side is also using ${ } placeholders > + assertExpression("${in.header.foo} == > ${bean:generator.generateFilename}", true); > + > + assertExpression("${in.header.bar} == > ${bean:generator.generateId}", true); > + assertExpression("${in.header.bar} >= > ${bean:generator.generateId}", true); > } > > protected String getLanguageName() { > return "simple"; > } > + > + public class MyFileNameGenerator { > + public String generateFilename(Exchange exchange) { > + return "abc"; > + } > + > + public int generateId(Exchange exchange) { > + return 123; > + } > + } > + > } > \ No newline at end of file > > Modified: > camel/trunk/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java > URL: > http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java?rev=744707&r1=744706&r2=744707&view=diff > > ============================================================================== > --- > camel/trunk/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java > (original) > +++ > camel/trunk/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java > Sun Feb 15 17:49:04 2009 > @@ -150,4 +150,22 @@ > assertEquals("c", it.next()); > } > > + public void testBefore() { > + assertEquals("Hello ", ObjectHelper.before("Hello World", > "World")); > + assertEquals("Hello ", ObjectHelper.before("Hello World Again", > "World")); > + assertEquals(null, ObjectHelper.before("Hello Again", "Foo")); > + } > + > + public void testAfter() { > + assertEquals(" World", ObjectHelper.after("Hello World", > "Hello")); > + assertEquals(" World Again", ObjectHelper.after("Hello World > Again", "Hello")); > + assertEquals(null, ObjectHelper.after("Hello Again", "Foo")); > + } > + > + public void testBetween() { > + assertEquals("foo bar", ObjectHelper.between("Hello 'foo bar' how > are you", "'", "'")); > + assertEquals("foo bar", ObjectHelper.between("Hello ${foo bar} how > are you", "${", "}")); > + assertEquals(null, ObjectHelper.between("Hello ${foo bar} how are > you", "'", "'")); > + } > + > } > > > -- Cheers, Jon http://janstey.blogspot.com/