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 2017/06/19 06:34:32 UTC

[2/2] camel git commit: CAMEL-11421: Up in the sky coding. Tokenize language can now set the group size using dynamic values based on simple language like some of the other options can do.

CAMEL-11421: Up in the sky coding. Tokenize language can now set the group size using dynamic values based on simple language like some of the other options can do.


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/2f8b0190
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/2f8b0190
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/2f8b0190

Branch: refs/heads/master
Commit: 2f8b019062652a1f94728dac7ef9dc70d53c21fb
Parents: 848512f
Author: Claus Ibsen <da...@apache.org>
Authored: Sun Jun 18 15:49:31 2017 +0200
Committer: Claus Ibsen <da...@apache.org>
Committed: Mon Jun 19 08:34:17 2017 +0200

----------------------------------------------------------------------
 camel-core/src/main/docs/tokenize-language.adoc |  2 +-
 .../apache/camel/builder/ExpressionBuilder.java | 28 ++++++++--
 .../apache/camel/builder/ExpressionClause.java  | 25 +++++++++
 .../camel/builder/ExpressionClauseSupport.java  | 30 +++++++++-
 .../org/apache/camel/builder/ValueBuilder.java  |  6 +-
 .../language/tokenizer/TokenizeLanguage.java    | 10 ++--
 .../model/language/TokenizerExpression.java     | 10 ++--
 .../SplitTokenizerGroupDynamicTest.java         | 59 ++++++++++++++++++++
 .../SpringSplitTokenizerGroupDynamicTest.java   | 32 +++++++++++
 .../SpringSplitTokenizerGroupDynamicTest.xml    | 46 +++++++++++++++
 10 files changed, 226 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/2f8b0190/camel-core/src/main/docs/tokenize-language.adoc
----------------------------------------------------------------------
diff --git a/camel-core/src/main/docs/tokenize-language.adoc b/camel-core/src/main/docs/tokenize-language.adoc
index 8d5daf0..25ade1c 100644
--- a/camel-core/src/main/docs/tokenize-language.adoc
+++ b/camel-core/src/main/docs/tokenize-language.adoc
@@ -30,7 +30,7 @@ The Tokenize language supports 10 options which are listed below.
 | regex | false | Boolean | If the token is a regular expression pattern. The default value is false
 | xml | false | Boolean | Whether the input is XML messages. This option must be set to true if working with XML payloads.
 | includeTokens | false | Boolean | Whether to include the tokens in the parts when using pairs The default value is false
-| group |  | Integer | To group N parts together for example to split big files into chunks of 1000 lines.
+| group |  | String | To group N parts together for example to split big files into chunks of 1000 lines. You can use simple language as the group to support dynamic group sizes.
 | skipFirst | false | Boolean | To skip the very first element
 | trim | true | Boolean | Whether to trim the value to remove leading and trailing whitespaces and line breaks
 |=======================================================================

http://git-wip-us.apache.org/repos/asf/camel/blob/2f8b0190/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java b/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
index 60b2300..6fdc509 100644
--- a/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
+++ b/camel-core/src/main/java/org/apache/camel/builder/ExpressionBuilder.java
@@ -40,12 +40,14 @@ import org.apache.camel.Component;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
 import org.apache.camel.Expression;
+import org.apache.camel.ExpressionEvaluationException;
 import org.apache.camel.InvalidPayloadException;
 import org.apache.camel.Message;
 import org.apache.camel.NoSuchEndpointException;
 import org.apache.camel.NoSuchLanguageException;
 import org.apache.camel.NoTypeConversionAvailableException;
 import org.apache.camel.Producer;
+import org.apache.camel.RuntimeExchangeException;
 import org.apache.camel.component.bean.BeanInvocation;
 import org.apache.camel.component.properties.PropertiesComponent;
 import org.apache.camel.language.bean.BeanLanguage;
@@ -1639,14 +1641,21 @@ public final class ExpressionBuilder {
         };
     }
 
-    public static Expression groupXmlIteratorExpression(final Expression expression, final int group) {
+    public static Expression groupXmlIteratorExpression(final Expression expression, final String group) {
         return new ExpressionAdapter() {
             public Object evaluate(Exchange exchange) {
                 // evaluate expression as iterator
                 Iterator<?> it = expression.evaluate(exchange, Iterator.class);
                 ObjectHelper.notNull(it, "expression: " + expression + " evaluated on " + exchange + " must return an java.util.Iterator");
                 // must use GroupTokenIterator in xml mode as we want to concat the xml parts into a single message
-                return new GroupTokenIterator(exchange, it, null, group, false);
+                // the group can be a simple expression so evaluate it as a number
+                Integer parts = exchange.getContext().resolveLanguage("simple").createExpression(group).evaluate(exchange, Integer.class);
+                if (parts == null) {
+                    throw new RuntimeExchangeException("Group evaluated as null, must be evaluated as a positive Integer value from expression: " + group, exchange);
+                } else if (parts <= 0) {
+                    throw new RuntimeExchangeException("Group must be a positive number, was: " + parts, exchange);
+                }
+                return new GroupTokenIterator(exchange, it, null, parts, false);
             }
 
             @Override
@@ -1656,16 +1665,23 @@ public final class ExpressionBuilder {
         };
     }
 
-    public static Expression groupIteratorExpression(final Expression expression, final String token, final int group, final boolean skipFirst) {
+    public static Expression groupIteratorExpression(final Expression expression, final String token, final String group, final boolean skipFirst) {
         return new ExpressionAdapter() {
             public Object evaluate(Exchange exchange) {
                 // evaluate expression as iterator
                 Iterator<?> it = expression.evaluate(exchange, Iterator.class);
                 ObjectHelper.notNull(it, "expression: " + expression + " evaluated on " + exchange + " must return an java.util.Iterator");
+                // the group can be a simple expression so evaluate it as a number
+                Integer parts = exchange.getContext().resolveLanguage("simple").createExpression(group).evaluate(exchange, Integer.class);
+                if (parts == null) {
+                    throw new RuntimeExchangeException("Group evaluated as null, must be evaluated as a positive Integer value from expression: " + group, exchange);
+                } else if (parts <= 0) {
+                    throw new RuntimeExchangeException("Group must be a positive number, was: " + parts, exchange);
+                }
                 if (token != null) {
-                    return new GroupTokenIterator(exchange, it, token, group, skipFirst);
+                    return new GroupTokenIterator(exchange, it, token, parts, skipFirst);
                 } else {
-                    return new GroupIterator(exchange, it, group, skipFirst);
+                    return new GroupIterator(exchange, it, parts, skipFirst);
                 }
             }
 
@@ -2382,7 +2398,7 @@ public final class ExpressionBuilder {
             public Object evaluate(Exchange exchange) {
                 // use simple language
                 Expression exp = exchange.getContext().resolveLanguage("simple").createExpression(expression);
-                return ExpressionBuilder.groupIteratorExpression(exp, null, group, false).evaluate(exchange, Object.class);
+                return ExpressionBuilder.groupIteratorExpression(exp, null, "" + group, false).evaluate(exchange, Object.class);
             }
 
             @Override

http://git-wip-us.apache.org/repos/asf/camel/blob/2f8b0190/camel-core/src/main/java/org/apache/camel/builder/ExpressionClause.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/builder/ExpressionClause.java b/camel-core/src/main/java/org/apache/camel/builder/ExpressionClause.java
index 07e9c85..05fd859 100644
--- a/camel-core/src/main/java/org/apache/camel/builder/ExpressionClause.java
+++ b/camel-core/src/main/java/org/apache/camel/builder/ExpressionClause.java
@@ -679,6 +679,18 @@ public class ExpressionClause<T> extends ExpressionDefinition {
      * @param token the token
      * @param regex whether the token is a regular expression or not
      * @param group to group by the given number
+     * @return the builder to continue processing the DSL
+     */
+    public T tokenize(String token, boolean regex, String group) {
+        return tokenize(token, regex, group, false);
+    }
+
+    /**
+     * Evaluates a token expression on the message body
+     *
+     * @param token the token
+     * @param regex whether the token is a regular expression or not
+     * @param group to group by the given number
      * @param skipFirst whether to skip the first element
      * @return the builder to continue processing the DSL
      */
@@ -690,6 +702,19 @@ public class ExpressionClause<T> extends ExpressionDefinition {
      * Evaluates a token expression on the message body
      *
      * @param token the token
+     * @param regex whether the token is a regular expression or not
+     * @param group to group by the given number
+     * @param skipFirst whether to skip the first element
+     * @return the builder to continue processing the DSL
+     */
+    public T tokenize(String token, boolean regex, String group, boolean skipFirst) {
+        return delegate.tokenize(token, null, regex, group, skipFirst);
+    }
+
+    /**
+     * Evaluates a token expression on the message body
+     *
+     * @param token the token
      * @param group to group by the given number
      * @return the builder to continue processing the DSL
      */

http://git-wip-us.apache.org/repos/asf/camel/blob/2f8b0190/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java b/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
index 910645f..64cef85 100644
--- a/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
+++ b/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
@@ -708,6 +708,20 @@ public class ExpressionClauseSupport<T> {
      * @return the builder to continue processing the DSL
      */
     public T tokenize(String token, String headerName, boolean regex, int group, boolean skipFirst) {
+        return tokenize(token, headerName, regex, "" + group, skipFirst);
+    }
+
+    /**
+     * Evaluates a token expression on the given header
+     *
+     * @param token the token
+     * @param headerName name of header to tokenize
+     * @param regex whether the token is a regular expression or not
+     * @param group to group by number of parts
+     * @param skipFirst whether to skip the very first element
+     * @return the builder to continue processing the DSL
+     */
+    public T tokenize(String token, String headerName, boolean regex, String group, boolean skipFirst) {
         TokenizerExpression expression = new TokenizerExpression();
         expression.setToken(token);
         expression.setHeaderName(headerName);
@@ -744,13 +758,23 @@ public class ExpressionClauseSupport<T> {
      * @return the builder to continue processing the DSL
      */
     public T tokenizeXMLPair(String tagName, String inheritNamespaceTagName, int group) {
+        return tokenizeXMLPair(tagName, inheritNamespaceTagName, "" + group);
+    }
+
+    /**
+     * Evaluates a token pair expression on the message body with XML content
+     *
+     * @param tagName the the tag name of the child nodes to tokenize
+     * @param inheritNamespaceTagName  optional parent or root tag name that contains namespace(s) to inherit
+     * @param group to group by the given number
+     * @return the builder to continue processing the DSL
+     */
+    public T tokenizeXMLPair(String tagName, String inheritNamespaceTagName, String group) {
         TokenizerExpression expression = new TokenizerExpression();
         expression.setToken(tagName);
         expression.setInheritNamespaceTagName(inheritNamespaceTagName);
         expression.setXml(true);
-        if (group > 0) {
-            expression.setGroup(group);
-        }
+        expression.setGroup(group);
         setExpressionType(expression);
         return result;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/2f8b0190/camel-core/src/main/java/org/apache/camel/builder/ValueBuilder.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/builder/ValueBuilder.java b/camel-core/src/main/java/org/apache/camel/builder/ValueBuilder.java
index 91b5fcd..eb87b11 100644
--- a/camel-core/src/main/java/org/apache/camel/builder/ValueBuilder.java
+++ b/camel-core/src/main/java/org/apache/camel/builder/ValueBuilder.java
@@ -185,8 +185,12 @@ public class ValueBuilder implements Expression, Predicate {
     }
 
     public ValueBuilder tokenize(String token, int group, boolean skipFirst) {
+        return tokenize(token, "" + group, skipFirst);
+    }
+
+    public ValueBuilder tokenize(String token, String group, boolean skipFirst) {
         Expression newExp = ExpressionBuilder.tokenizeExpression(expression, token);
-        if (group == 0 && skipFirst) {
+        if (group == null && skipFirst) {
             // wrap in skip first (if group then it has its own skip first logic)
             newExp = ExpressionBuilder.skipFirstExpression(newExp);
         }

http://git-wip-us.apache.org/repos/asf/camel/blob/2f8b0190/camel-core/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java b/camel-core/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
index 22b62a2..33bf48d 100644
--- a/camel-core/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
+++ b/camel-core/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
@@ -46,7 +46,7 @@ public class TokenizeLanguage implements Language, IsSingleton {
     private boolean regex;
     private boolean xml;
     private boolean includeTokens;
-    private int group;
+    private String group;
     private boolean skipFirst;
 
     public static Expression tokenize(String token) {
@@ -121,14 +121,14 @@ public class TokenizeLanguage implements Language, IsSingleton {
             } else {
                 answer = ExpressionBuilder.tokenizeExpression(exp, token);
             }
-            if (group == 0 && skipFirst) {
+            if (group == null && skipFirst) {
                 // wrap in skip first (if group then it has its own skip first logic)
                 answer = ExpressionBuilder.skipFirstExpression(answer);
             }
         }
 
         // if group then wrap answer in group expression
-        if (group > 0) {
+        if (group != null) {
             if (isXml()) {
                 answer = ExpressionBuilder.groupXmlIteratorExpression(answer, group);
             } else {
@@ -202,11 +202,11 @@ public class TokenizeLanguage implements Language, IsSingleton {
         this.includeTokens = includeTokens;
     }
 
-    public int getGroup() {
+    public String getGroup() {
         return group;
     }
 
-    public void setGroup(int group) {
+    public void setGroup(String group) {
         this.group = group;
     }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/2f8b0190/camel-core/src/main/java/org/apache/camel/model/language/TokenizerExpression.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/language/TokenizerExpression.java b/camel-core/src/main/java/org/apache/camel/model/language/TokenizerExpression.java
index 83aacd6..2099317 100644
--- a/camel-core/src/main/java/org/apache/camel/model/language/TokenizerExpression.java
+++ b/camel-core/src/main/java/org/apache/camel/model/language/TokenizerExpression.java
@@ -52,7 +52,7 @@ public class TokenizerExpression extends ExpressionDefinition {
     @XmlAttribute
     private Boolean includeTokens;
     @XmlAttribute
-    private Integer group;
+    private String group;
     @XmlAttribute
     private Boolean skipFirst;
 
@@ -149,14 +149,15 @@ public class TokenizerExpression extends ExpressionDefinition {
         this.includeTokens = includeTokens;
     }
 
-    public Integer getGroup() {
+    public String getGroup() {
         return group;
     }
 
     /**
      * To group N parts together, for example to split big files into chunks of 1000 lines.
+     * You can use simple language as the group to support dynamic group sizes.
      */
-    public void setGroup(Integer group) {
+    public void setGroup(String group) {
         this.group = group;
     }
 
@@ -193,9 +194,6 @@ public class TokenizerExpression extends ExpressionDefinition {
             language.setIncludeTokens(includeTokens);
         }
         if (group != null) {
-            if (group <= 0) {
-                throw new IllegalArgumentException("Group must be a positive number, was: " + group);
-            }
             language.setGroup(group);
         }
         if (skipFirst != null) {

http://git-wip-us.apache.org/repos/asf/camel/blob/2f8b0190/camel-core/src/test/java/org/apache/camel/processor/SplitTokenizerGroupDynamicTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/processor/SplitTokenizerGroupDynamicTest.java b/camel-core/src/test/java/org/apache/camel/processor/SplitTokenizerGroupDynamicTest.java
new file mode 100644
index 0000000..53436a6
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/processor/SplitTokenizerGroupDynamicTest.java
@@ -0,0 +1,59 @@
+/**
+ * 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.processor;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+
+public class SplitTokenizerGroupDynamicTest extends ContextTestSupport {
+
+    public void testSplitTokenizerA() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:split");
+        mock.expectedBodiesReceived("Claus,James", "Willem");
+
+        template.sendBodyAndHeader("direct:a", "Claus,James,Willem", "groups", 2);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    public void testSplitTokenizerB() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:split");
+        mock.expectedBodiesReceived("James,Willem");
+
+        template.sendBodyAndHeader("direct:b", "Claus,James,Willem".getBytes(), "groups", 2);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                
+                from("direct:a")
+                    .split().tokenize(",", false, "${header.groups}")
+                        .to("mock:split");
+
+                from("direct:b")
+                    .split(bodyAs(String.class).tokenize(",", "${header.groups}", true))
+                        .to("mock:split");
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/2f8b0190/camel-core/src/test/java/org/apache/camel/spring/processor/SpringSplitTokenizerGroupDynamicTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/spring/processor/SpringSplitTokenizerGroupDynamicTest.java b/camel-core/src/test/java/org/apache/camel/spring/processor/SpringSplitTokenizerGroupDynamicTest.java
new file mode 100644
index 0000000..d5cd66b
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/spring/processor/SpringSplitTokenizerGroupDynamicTest.java
@@ -0,0 +1,32 @@
+/**
+ * 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.spring.processor;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.processor.SplitTokenizerGroupDynamicTest;
+
+import static org.apache.camel.spring.processor.SpringTestHelper.createSpringCamelContext;
+
+/**
+ * @version 
+ */
+public class SpringSplitTokenizerGroupDynamicTest extends SplitTokenizerGroupDynamicTest {
+
+    protected CamelContext createCamelContext() throws Exception {
+        return createSpringCamelContext(this, "org/apache/camel/spring/processor/SpringSplitTokenizerGroupDynamicTest.xml");
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/2f8b0190/camel-core/src/test/resources/org/apache/camel/spring/processor/SpringSplitTokenizerGroupDynamicTest.xml
----------------------------------------------------------------------
diff --git a/camel-core/src/test/resources/org/apache/camel/spring/processor/SpringSplitTokenizerGroupDynamicTest.xml b/camel-core/src/test/resources/org/apache/camel/spring/processor/SpringSplitTokenizerGroupDynamicTest.xml
new file mode 100644
index 0000000..7744a14
--- /dev/null
+++ b/camel-core/src/test/resources/org/apache/camel/spring/processor/SpringSplitTokenizerGroupDynamicTest.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
+    ">
+
+  <!-- START SNIPPET: example -->
+  <camelContext xmlns="http://camel.apache.org/schema/spring">
+    <route>
+      <from uri="direct:a"/>
+      <split>
+        <tokenize token="," group="${header.groups}"/>
+        <to uri="mock:split"/>
+      </split>
+    </route>
+    <route>
+      <from uri="direct:b"/>
+      <split>
+        <tokenize token="," group="${header.groups}" skipFirst="true"/>
+        <to uri="mock:split"/>
+      </split>
+    </route>
+  </camelContext>
+  <!-- END SNIPPET: example -->
+
+</beans>