Author: davsclaus
Date: Sat Oct 29 12:37:21 2011
New Revision: 1194882

URL: http://svn.apache.org/viewvc?rev=1194882&view=rev
Log:
CAMEL-4589: Added tokenizer pair to split big XML files in streaming mode, with 
low memory footprint.

Added:
    
camel/trunk/camel-core/src/main/java/org/apache/camel/processor/TokenPairExpressionIterator.java
    
camel/trunk/camel-core/src/test/java/org/apache/camel/language/TokenPairIteratorSplitChoicePerformanceTest.java
    
camel/trunk/camel-core/src/test/java/org/apache/camel/language/XPathSplitChoicePerformanceTest.java
    
camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/XPathSplitChoicePerformanceTest.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/builder/ExpressionClause.java
    
camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
    
camel/trunk/camel-core/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
    
camel/trunk/camel-core/src/main/java/org/apache/camel/model/language/TokenizerExpression.java
    
camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentTest.java
    
camel/trunk/camel-core/src/test/java/org/apache/camel/language/TokenizerTest.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=1194882&r1=1194881&r2=1194882&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
 Sat Oct 29 12:37:21 2011
@@ -39,6 +39,7 @@ import org.apache.camel.component.bean.B
 import org.apache.camel.component.properties.PropertiesComponent;
 import org.apache.camel.language.bean.BeanLanguage;
 import org.apache.camel.model.language.MethodCallExpression;
+import org.apache.camel.processor.TokenPairExpressionIterator;
 import org.apache.camel.spi.Language;
 import org.apache.camel.support.ExpressionAdapter;
 import org.apache.camel.util.ExchangeHelper;
@@ -1024,6 +1025,13 @@ public final class ExpressionBuilder {
     }
 
     /**
+     * Returns an {@link TokenPairExpressionIterator} expression
+     */
+    public static Expression tokenizePairExpression(final String startToken, 
final String endToken) {
+        return new TokenPairExpressionIterator(startToken, endToken);
+    }
+
+    /**
      * Returns a tokenize expression which will tokenize the string with the
      * given regex
      */

Modified: 
camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionClause.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionClause.java?rev=1194882&r1=1194881&r2=1194882&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionClause.java
 (original)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionClause.java
 Sat Oct 29 12:37:21 2011
@@ -424,6 +424,17 @@ public class ExpressionClause<T> extends
     }
 
     /**
+     * Evaluates a token pair expression on the message body
+     *
+     * @param startToken the start token
+     * @param endToken   the end token
+     * @return the builder to continue processing the DSL
+     */
+    public T tokenizePair(String startToken, String endToken) {
+        return delegate.tokenizePair(startToken, endToken);
+    }
+
+    /**
      * Evaluates an <a href="http://camel.apache.org/xpath.html";>XPath
      * expression</a>
      * 

Modified: 
camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java?rev=1194882&r1=1194881&r2=1194882&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
 (original)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/builder/ExpressionClauseSupport.java
 Sat Oct 29 12:37:21 2011
@@ -471,6 +471,21 @@ public class ExpressionClauseSupport<T> 
     }
 
     /**
+     * Evaluates a token pair expression on the message body
+     *
+     * @param startToken the start token
+     * @param endToken   the end token
+     * @return the builder to continue processing the DSL
+     */
+    public T tokenizePair(String startToken, String endToken) {
+        TokenizerExpression expression = new TokenizerExpression();
+        expression.setToken(startToken);
+        expression.setEndToken(endToken);
+        setExpressionType(expression);
+        return result;
+    }
+
+    /**
      * Evaluates an <a href="http://camel.apache.org/xpath.html";>XPath
      * expression</a>
      *

Modified: 
camel/trunk/camel-core/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java?rev=1194882&r1=1194881&r2=1194882&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
 (original)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/language/tokenizer/TokenizeLanguage.java
 Sat Oct 29 12:37:21 2011
@@ -26,10 +26,19 @@ import org.apache.camel.util.ObjectHelpe
 
 /**
  * A language for tokenizer expressions.
+ * <p/>
+ * This tokenizer language can operator in two modes
+ * <ul>
+ *     <li>default - using a single tokenizer</li>
+ *     <li>pair - using both start and end tokens</li>
+ * </ul>
+ * The default mode supports the <tt>headerName</tt> and <tt>regex</tt> 
options.
+ * Where as the pair mode only supports <tt>token</tt> and <tt>endToken</tt>.
  */
 public class TokenizeLanguage implements Language, IsSingleton {
 
     private String token;
+    private String endToken;
     private String headerName;
     private boolean regex;
 
@@ -56,6 +65,13 @@ public class TokenizeLanguage implements
         return language.createExpression(null);
     }
 
+    public static Expression tokenizePair(String startToken, String endToken) {
+        TokenizeLanguage language = new TokenizeLanguage();
+        language.setToken(startToken);
+        language.setEndToken(endToken);
+        return language.createExpression(null);
+    }
+
     public Predicate createPredicate(String expression) {
         return 
ExpressionToPredicateAdapter.toPredicate(createExpression(expression));
     }
@@ -65,6 +81,13 @@ public class TokenizeLanguage implements
      */
     public Expression createExpression() {
         ObjectHelper.notNull(token, "token");
+
+        // if end token is provided then use the tokenize pair expression
+        if (endToken != null) {
+            return ExpressionBuilder.tokenizePairExpression(token, endToken);
+        }
+
+        // use the regular tokenizer
         Expression exp = headerName == null ? 
ExpressionBuilder.bodyExpression() : 
ExpressionBuilder.headerExpression(headerName);
         if (regex) {
             return ExpressionBuilder.regexTokenizeExpression(exp, token);
@@ -88,6 +111,14 @@ public class TokenizeLanguage implements
         this.token = token;
     }
 
+    public String getEndToken() {
+        return endToken;
+    }
+
+    public void setEndToken(String endToken) {
+        this.endToken = endToken;
+    }
+
     public String getHeaderName() {
         return headerName;
     }

Modified: 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/language/TokenizerExpression.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/model/language/TokenizerExpression.java?rev=1194882&r1=1194881&r2=1194882&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/language/TokenizerExpression.java
 (original)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/language/TokenizerExpression.java
 Sat Oct 29 12:37:21 2011
@@ -26,9 +26,9 @@ import org.apache.camel.Expression;
 import org.apache.camel.language.tokenizer.TokenizeLanguage;
 
 /**
- * For expressions and predicates using a body or header tokenizer
+ * For expressions and predicates using a body or header tokenizer.
  *
- * @version 
+ * @see TokenizeLanguage
  */
 @XmlRootElement(name = "tokenize")
 @XmlAccessorType(XmlAccessType.FIELD)
@@ -36,6 +36,8 @@ public class TokenizerExpression extends
     @XmlAttribute(required = true)
     private String token;
     @XmlAttribute
+    private String endToken;
+    @XmlAttribute
     private String headerName;
     @XmlAttribute
     private Boolean regex;
@@ -56,6 +58,14 @@ public class TokenizerExpression extends
         this.token = token;
     }
 
+    public String getEndToken() {
+        return endToken;
+    }
+
+    public void setEndToken(String endToken) {
+        this.endToken = endToken;
+    }
+
     public String getHeaderName() {
         return headerName;
     }
@@ -76,6 +86,7 @@ public class TokenizerExpression extends
     public Expression createExpression(CamelContext camelContext) {
         TokenizeLanguage language = new TokenizeLanguage();
         language.setToken(token);
+        language.setEndToken(endToken);
         language.setHeaderName(headerName);
         if (regex != null) {
             language.setRegex(regex);
@@ -85,6 +96,10 @@ public class TokenizerExpression extends
 
     @Override
     public String toString() {
-        return "tokenize{" + (headerName != null ? "header: " + headerName : 
"body()") + " using token: " + token + "}";
+        if (endToken != null) {
+            return "tokenize{body() using tokens: " + token + "..." + endToken 
+ "}";
+        } else {
+            return "tokenize{" + (headerName != null ? "header: " + headerName 
: "body()") + " using token: " + token + "}";
+        }
     }
 }
\ No newline at end of file

Added: 
camel/trunk/camel-core/src/main/java/org/apache/camel/processor/TokenPairExpressionIterator.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/processor/TokenPairExpressionIterator.java?rev=1194882&view=auto
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/processor/TokenPairExpressionIterator.java
 (added)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/processor/TokenPairExpressionIterator.java
 Sat Oct 29 12:37:21 2011
@@ -0,0 +1,131 @@
+/**
+ * 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 java.io.InputStream;
+import java.util.Iterator;
+import java.util.Scanner;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.support.ExpressionAdapter;
+import org.apache.camel.util.ObjectHelper;
+
+/**
+ * {@link org.apache.camel.Expression} to walk a {@link 
org.apache.camel.Message} body
+ * using an {@link Iterator}, which grabs the content between a start and end 
token.
+ * <p/>
+ * The message body must be able to convert to {@link InputStream} type which 
is used as stream
+ * to access the message body.
+ * <p/>
+ * Can be used to split big XML files
+ */
+public class TokenPairExpressionIterator extends ExpressionAdapter {
+
+    private final String startToken;
+    private final String endToken;
+
+    public TokenPairExpressionIterator(String startToken, String endToken) {
+        this.startToken = startToken;
+        this.endToken = endToken;
+        ObjectHelper.notEmpty(startToken, "startToken");
+        ObjectHelper.notEmpty(endToken, "endToken");
+    }
+
+    @Override
+    public Object evaluate(Exchange exchange) {
+        try {
+            InputStream in = 
exchange.getIn().getMandatoryBody(InputStream.class);
+            return new TokenPairIterator(startToken, endToken, in);
+        } catch (InvalidPayloadException e) {
+            exchange.setException(e);
+            return null;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "tokenize[body() using tokens: " + startToken + "..." + 
endToken + "]";
+    }
+
+    /**
+     * Iterator to walk the input stream
+     */
+    private static final class TokenPairIterator implements Iterator {
+
+        private final String startToken;
+        private final String endToken;
+        private final Scanner scanner;
+        private Object image;
+
+        private TokenPairIterator(String startToken, String endToken, 
InputStream in) {
+            this.startToken = startToken;
+            this.endToken = endToken;
+            // use end token as delimiter
+            this.scanner = new Scanner(in).useDelimiter(endToken);
+            // this iterator will do look ahead as we may have data
+            // after the last end token, which the scanner would find
+            // so we need to be one step ahead of the scanner
+            this.image = hasNext() ? next() : null;
+        }
+
+        @Override
+        public boolean hasNext() {
+            // must look a head
+            boolean answer = scanner.hasNext();
+            if (!answer) {
+                scanner.close();
+            }
+            return answer;
+        }
+
+        @Override
+        public Object next() {
+            Object answer = image;
+            // calculate next
+            image = hasNext() ? getNext() : null;
+
+            if (answer == null) {
+                // first time the image may be null
+                answer = image;
+            }
+            return answer;
+        }
+
+        private Object getNext() {
+            String next = scanner.next();
+
+            // only grab text after the start token
+            if (next != null && next.contains(startToken)) {
+                next = ObjectHelper.after(next, startToken);
+            }
+
+            // include tokens in answer
+            if (next != null) {
+                StringBuilder sb = new StringBuilder();
+                next = 
sb.append(startToken).append(next).append(endToken).toString();
+            }
+            return next;
+        }
+
+        @Override
+        public void remove() {
+            // noop
+        }
+    }
+
+}

Modified: 
camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentTest.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentTest.java?rev=1194882&r1=1194881&r2=1194882&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentTest.java
 (original)
+++ 
camel/trunk/camel-core/src/test/java/org/apache/camel/component/properties/PropertiesComponentTest.java
 Sat Oct 29 12:37:21 2011
@@ -434,6 +434,37 @@ public class PropertiesComponentTest ext
         }
     }
 
+    public void testCache() throws Exception {
+        PropertiesComponent pc = context.getComponent("properties", 
PropertiesComponent.class);
+        assertTrue(pc.isCache());
+        assertNotNull(pc);
+
+        for (int i = 0; i < 2000; i++) {
+            String uri = pc.parseUri("{{cool.mock}}:" + i);
+            assertEquals("mock:" + i, uri);
+        }
+    }
+
+    public void testCacheRoute() throws Exception {
+        context.addRoutes(new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .setBody(simple("${properties:cool.mock}${body}"))
+                    .to("mock:result");
+            }
+        });
+        context.start();
+
+        getMockEndpoint("mock:result").expectedMessageCount(2000);
+
+        for (int i = 0; i < 2000; i++) {
+            template.sendBody("direct:start", i);
+        }
+
+        assertMockEndpointsSatisfied();
+    }
+
     @Override
     protected CamelContext createCamelContext() throws Exception {
         CamelContext context = super.createCamelContext();

Added: 
camel/trunk/camel-core/src/test/java/org/apache/camel/language/TokenPairIteratorSplitChoicePerformanceTest.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/language/TokenPairIteratorSplitChoicePerformanceTest.java?rev=1194882&view=auto
==============================================================================
--- 
camel/trunk/camel-core/src/test/java/org/apache/camel/language/TokenPairIteratorSplitChoicePerformanceTest.java
 (added)
+++ 
camel/trunk/camel-core/src/test/java/org/apache/camel/language/TokenPairIteratorSplitChoicePerformanceTest.java
 Sat Oct 29 12:37:21 2011
@@ -0,0 +1,183 @@
+/**
+ * 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 java.io.File;
+import java.io.FileOutputStream;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.NotifyBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.util.StopWatch;
+import org.apache.camel.util.TimeUtils;
+import org.slf4j.Logger;
+
+/**
+ *
+ */
+public class TokenPairIteratorSplitChoicePerformanceTest extends 
ContextTestSupport {
+
+    private int size = 20 * 1000;
+    private final AtomicInteger tiny = new AtomicInteger();
+    private final AtomicInteger small = new AtomicInteger();
+    private final AtomicInteger med = new AtomicInteger();
+    private final AtomicInteger large = new AtomicInteger();
+    private final StopWatch watch = new StopWatch();
+
+    @Override
+    public void setUp() throws Exception {
+        createDataFile(log, size);
+        super.setUp();
+    }
+
+    public void testDummy() {
+        // this is a manual test
+    }
+
+    public void xxxtestTokenPairPerformanceRoute() throws Exception {
+        NotifyBuilder notify = new 
NotifyBuilder(context).whenDone(size).create();
+
+        boolean matches = notify.matches(5, TimeUnit.MINUTES);
+        log.info("Processed file with " + size + " elements in: " + 
TimeUtils.printDuration(watch.stop()));
+
+        log.info("Processed " + tiny.get() + " tiny messages");
+        log.info("Processed " + small.get() + " small messages");
+        log.info("Processed " + med.get() + " medium messages");
+        log.info("Processed " + large.get() + " large messages");
+
+        assertEquals((size / 10) * 4, tiny.get());
+        assertEquals((size / 10) * 2, small.get());
+        assertEquals((size / 10) * 3, med.get());
+        assertEquals((size / 10) * 1, large.get());
+
+        assertTrue("Should complete route", matches);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("file:target/data?noop=true")
+                    .process(new Processor() {
+                        public void process(Exchange exchange) throws 
Exception {
+                            log.info("Starting to process file");
+                            watch.restart();
+                        }
+                    })
+                    .split().tokenizePair("<order>", "</order>").streaming()
+                        .choice()
+                            .when().xpath("/order/amount < 10")
+                                .process(new Processor() {
+                                    public void process(Exchange exchange) 
throws Exception {
+                                        String xml = 
exchange.getIn().getBody(String.class);
+                                        assertTrue(xml, 
xml.contains("<amount>3</amount>"));
+
+                                        int num = tiny.incrementAndGet();
+                                        if (num % 100 == 0) {
+                                            log.info("Processed " + num + " 
tiny messages");
+                                            log.debug(xml);
+                                        }
+                                    }
+                                })
+                            .when().xpath("/order/amount < 50")
+                                .process(new Processor() {
+                                    public void process(Exchange exchange) 
throws Exception {
+                                        String xml = 
exchange.getIn().getBody(String.class);
+                                        assertTrue(xml, 
xml.contains("<amount>44</amount>"));
+
+                                        int num = small.incrementAndGet();
+                                        if (num % 100 == 0) {
+                                            log.info("Processed " + num + " 
small messages: " + xml);
+                                            log.debug(xml);
+                                        }
+                                    }
+                                })
+                            .when().xpath("/order/amount < 100")
+                                .process(new Processor() {
+                                    public void process(Exchange exchange) 
throws Exception {
+                                        String xml = 
exchange.getIn().getBody(String.class);
+                                        assertTrue(xml, 
xml.contains("<amount>88</amount>"));
+
+                                        int num = med.incrementAndGet();
+                                        if (num % 100 == 0) {
+                                            log.info("Processed " + num + " 
medium messages");
+                                            log.debug(xml);
+                                        }
+                                    }
+                                })
+                            .otherwise()
+                                .process(new Processor() {
+                                    public void process(Exchange exchange) 
throws Exception {
+                                        String xml = 
exchange.getIn().getBody(String.class);
+                                        assertTrue(xml, 
xml.contains("<amount>123</amount>"));
+
+                                        int num = large.incrementAndGet();
+                                        if (num % 100 == 0) {
+                                            log.info("Processed " + num + " 
large messages");
+                                            log.debug(xml);
+                                        }
+                                    }
+                                })
+                        .end() // choice
+                    .end(); // split
+            }
+        };
+    }
+
+    public static void createDataFile(Logger log, int size) throws Exception {
+        deleteDirectory("target/data");
+        createDirectory("target/data");
+
+        log.info("Creating data file ...");
+
+        File file = new File("target/data/data.xml");
+        FileOutputStream fos = new FileOutputStream(file, true);
+        fos.write("<orders>\n".getBytes());
+
+        for (int i = 0; i < size; i++) {
+            fos.write("<order>\n".getBytes());
+            fos.write(("  <id>" + i + "</id>\n").getBytes());
+            int num = i % 10;
+            if (num >= 0 && num <= 3) {
+                fos.write("  <amount>3</amount>\n".getBytes());
+                fos.write("  <customerId>333</customerId>\n".getBytes());
+            } else if (num >= 4 && num <= 5) {
+                fos.write("  <amount>44</amount>\n".getBytes());
+                fos.write("  <customerId>444</customerId>\n".getBytes());
+            } else if (num >= 6 && num <= 8) {
+                fos.write("  <amount>88</amount>\n".getBytes());
+                fos.write("  <customerId>888</customerId>\n".getBytes());
+            } else {
+                fos.write("  <amount>123</amount>\n".getBytes());
+                fos.write("  <customerId>123123</customerId>\n".getBytes());
+            }
+            fos.write("  <description>bla bla bla bla bla bla bla bla bla bla 
bla bla bla bla bla bla</description>\n".getBytes());
+            fos.write("</order>\n".getBytes());
+        }
+
+        fos.write("</orders>".getBytes());
+        fos.close();
+
+        log.info("Creating data file done.");
+    }
+
+}

Modified: 
camel/trunk/camel-core/src/test/java/org/apache/camel/language/TokenizerTest.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/language/TokenizerTest.java?rev=1194882&r1=1194881&r2=1194882&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/test/java/org/apache/camel/language/TokenizerTest.java
 (original)
+++ 
camel/trunk/camel-core/src/test/java/org/apache/camel/language/TokenizerTest.java
 Sat Oct 29 12:37:21 2011
@@ -99,4 +99,51 @@ public class TokenizerTest extends Excha
         assertEquals(false, lan.isSingleton());
     }
 
+    public void testTokenizePair() throws Exception {
+        Expression exp = TokenizeLanguage.tokenizePair("<person>", 
"</person>");
+
+        
exchange.getIn().setBody("<persons><person>James</person><person>Claus</person><person>Jonathan</person><person>Hadrian</person></persons>");
+
+        List names = exp.evaluate(exchange, List.class);
+        assertEquals(4, names.size());
+
+        assertEquals("<person>James</person>", names.get(0));
+        assertEquals("<person>Claus</person>", names.get(1));
+        assertEquals("<person>Jonathan</person>", names.get(2));
+        assertEquals("<person>Hadrian</person>", names.get(3));
+    }
+
+    public void testTokenizePairWithNoise() throws Exception {
+        Expression exp = TokenizeLanguage.tokenizePair("<person>", 
"</person>");
+
+        exchange.getIn().setBody("<?xml version=\"1.0\"?><!-- bla bla 
--><persons>\n<person>James</person>\n<person>Claus</person>\n"
+                + "<!-- more bla bla 
--><person>Jonathan</person>\n<person>Hadrian</person>\n</persons>   ");
+
+        List names = exp.evaluate(exchange, List.class);
+        assertEquals(4, names.size());
+
+        assertEquals("<person>James</person>", names.get(0));
+        assertEquals("<person>Claus</person>", names.get(1));
+        assertEquals("<person>Jonathan</person>", names.get(2));
+        assertEquals("<person>Hadrian</person>", names.get(3));
+    }
+
+    public void testTokenizePairEmpty() throws Exception {
+        Expression exp = TokenizeLanguage.tokenizePair("<person>", 
"</person>");
+
+        exchange.getIn().setBody("<?xml version=\"1.0\"?><!-- bla bla 
--><persons></persons>   ");
+
+        List names = exp.evaluate(exchange, List.class);
+        assertEquals(0, names.size());
+    }
+
+    public void testTokenizePairNoData() throws Exception {
+        Expression exp = TokenizeLanguage.tokenizePair("<person>", 
"</person>");
+
+        exchange.getIn().setBody("");
+
+        List names = exp.evaluate(exchange, List.class);
+        assertNull(names);
+    }
+
 }
\ No newline at end of file

Added: 
camel/trunk/camel-core/src/test/java/org/apache/camel/language/XPathSplitChoicePerformanceTest.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/language/XPathSplitChoicePerformanceTest.java?rev=1194882&view=auto
==============================================================================
--- 
camel/trunk/camel-core/src/test/java/org/apache/camel/language/XPathSplitChoicePerformanceTest.java
 (added)
+++ 
camel/trunk/camel-core/src/test/java/org/apache/camel/language/XPathSplitChoicePerformanceTest.java
 Sat Oct 29 12:37:21 2011
@@ -0,0 +1,183 @@
+/**
+ * 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 java.io.File;
+import java.io.FileOutputStream;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.NotifyBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.util.StopWatch;
+import org.apache.camel.util.TimeUtils;
+import org.slf4j.Logger;
+
+/**
+ *
+ */
+public class XPathSplitChoicePerformanceTest extends ContextTestSupport {
+
+    private int size = 20 * 1000;
+    private final AtomicInteger tiny = new AtomicInteger();
+    private final AtomicInteger small = new AtomicInteger();
+    private final AtomicInteger med = new AtomicInteger();
+    private final AtomicInteger large = new AtomicInteger();
+    private final StopWatch watch = new StopWatch();
+
+    @Override
+    public void setUp() throws Exception {
+        createDataFile(log, size);
+        super.setUp();
+    }
+
+    public void testDummy() {
+        // this is a manual test
+    }
+
+    public void xxTestXPatPerformanceRoute() throws Exception {
+        NotifyBuilder notify = new 
NotifyBuilder(context).whenDone(size).create();
+
+        boolean matches = notify.matches(60, TimeUnit.SECONDS);
+        log.info("Processed file with " + size + " elements in: " + 
TimeUtils.printDuration(watch.stop()));
+
+        log.info("Processed " + tiny.get() + " tiny messages");
+        log.info("Processed " + small.get() + " small messages");
+        log.info("Processed " + med.get() + " medium messages");
+        log.info("Processed " + large.get() + " large messages");
+
+        assertEquals((size / 10) * 4, tiny.get());
+        assertEquals((size / 10) * 2, small.get());
+        assertEquals((size / 10) * 3, med.get());
+        assertEquals((size / 10) * 1, large.get());
+
+        assertTrue("Should complete route", matches);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("file:target/data?noop=true")
+                    .process(new Processor() {
+                        public void process(Exchange exchange) throws 
Exception {
+                            log.info("Starting to process file");
+                            watch.restart();
+                        }
+                    })
+                    .split().xpath("/orders/order").streaming()
+                        .choice()
+                            .when().xpath("/order/amount < 10")
+                                .process(new Processor() {
+                                    public void process(Exchange exchange) 
throws Exception {
+                                        String xml = 
exchange.getIn().getBody(String.class);
+                                        assertTrue(xml, 
xml.contains("<amount>3</amount>"));
+
+                                        int num = tiny.incrementAndGet();
+                                        if (num % 100 == 0) {
+                                            log.info("Processed " + num + " 
tiny messages");
+                                            log.debug(xml);
+                                        }
+                                    }
+                                })
+                            .when().xpath("/order/amount < 50")
+                                .process(new Processor() {
+                                    public void process(Exchange exchange) 
throws Exception {
+                                        String xml = 
exchange.getIn().getBody(String.class);
+                                        assertTrue(xml, 
xml.contains("<amount>44</amount>"));
+
+                                        int num = small.incrementAndGet();
+                                        if (num % 100 == 0) {
+                                            log.info("Processed " + num + " 
small messages");
+                                            log.debug(xml);
+                                        }
+                                    }
+                                })
+                            .when().xpath("/order/amount < 100")
+                                .process(new Processor() {
+                                    public void process(Exchange exchange) 
throws Exception {
+                                        String xml = 
exchange.getIn().getBody(String.class);
+                                        assertTrue(xml, 
xml.contains("<amount>88</amount>"));
+
+                                        int num = med.incrementAndGet();
+                                        if (num % 100 == 0) {
+                                            log.info("Processed " + num + " 
medium messages");
+                                            log.debug(xml);
+                                        }
+                                    }
+                                })
+                            .otherwise()
+                                .process(new Processor() {
+                                    public void process(Exchange exchange) 
throws Exception {
+                                        String xml = 
exchange.getIn().getBody(String.class);
+                                        assertTrue(xml, 
xml.contains("<amount>123</amount>"));
+
+                                        int num = large.incrementAndGet();
+                                        if (num % 100 == 0) {
+                                            log.info("Processed " + num + " 
large messages");
+                                            log.debug(xml);
+                                        }
+                                    }
+                                })
+                        .end() // choice
+                    .end(); // split
+            }
+        };
+    }
+
+    public static void createDataFile(Logger log, int size) throws Exception {
+        deleteDirectory("target/data");
+        createDirectory("target/data");
+
+        log.info("Creating data file ...");
+
+        File file = new File("target/data/data.xml");
+        FileOutputStream fos = new FileOutputStream(file, true);
+        fos.write("<orders>\n".getBytes());
+
+        for (int i = 0; i < size; i++) {
+            fos.write("<order>\n".getBytes());
+            fos.write(("  <id>" + i + "</id>\n").getBytes());
+            int num = i % 10;
+            if (num >= 0 && num <= 3) {
+                fos.write("  <amount>3</amount>\n".getBytes());
+                fos.write("  <customerId>333</customerId>\n".getBytes());
+            } else if (num >= 4 && num <= 5) {
+                fos.write("  <amount>44</amount>\n".getBytes());
+                fos.write("  <customerId>444</customerId>\n".getBytes());
+            } else if (num >= 6 && num <= 8) {
+                fos.write("  <amount>88</amount>\n".getBytes());
+                fos.write("  <customerId>888</customerId>\n".getBytes());
+            } else {
+                fos.write("  <amount>123</amount>\n".getBytes());
+                fos.write("  <customerId>123123</customerId>\n".getBytes());
+            }
+            fos.write("  <description>bla bla bla bla bla bla bla bla bla bla 
bla bla bla bla bla bla</description>\n".getBytes());
+            fos.write("</order>\n".getBytes());
+        }
+
+        fos.write("</orders>".getBytes());
+        fos.close();
+
+        log.info("Creating data file done.");
+    }
+
+}

Added: 
camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/XPathSplitChoicePerformanceTest.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/XPathSplitChoicePerformanceTest.java?rev=1194882&view=auto
==============================================================================
--- 
camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/XPathSplitChoicePerformanceTest.java
 (added)
+++ 
camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/XPathSplitChoicePerformanceTest.java
 Sat Oct 29 12:37:21 2011
@@ -0,0 +1,183 @@
+/**
+ * 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.builder.saxon;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.NotifyBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.apache.camel.util.StopWatch;
+import org.apache.camel.util.TimeUtils;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+
+/**
+ *
+ */
+public class XPathSplitChoicePerformanceTest extends CamelTestSupport {
+
+    private int size = 20 * 1000;
+    private final AtomicInteger tiny = new AtomicInteger();
+    private final AtomicInteger small = new AtomicInteger();
+    private final AtomicInteger med = new AtomicInteger();
+    private final AtomicInteger large = new AtomicInteger();
+    private final StopWatch watch = new StopWatch();
+
+    @Override
+    public void setUp() throws Exception {
+        createDataFile(log, size);
+        super.setUp();
+    }
+
+    @Test
+    @Ignore("Manual test")
+    public void testXPathPerformanceRoute() throws Exception {
+        NotifyBuilder notify = new 
NotifyBuilder(context).whenDone(size).create();
+
+        boolean matches = notify.matches(60, TimeUnit.SECONDS);
+        log.info("Processed file with " + size + " elements in: " + 
TimeUtils.printDuration(watch.stop()));
+
+        log.info("Processed " + tiny.get() + " tiny messages");
+        log.info("Processed " + small.get() + " small messages");
+        log.info("Processed " + med.get() + " medium messages");
+        log.info("Processed " + large.get() + " large messages");
+
+        assertEquals((size / 10) * 4, tiny.get());
+        assertEquals((size / 10) * 2, small.get());
+        assertEquals((size / 10) * 3, med.get());
+        assertEquals((size / 10) * 1, large.get());
+
+        assertTrue("Should complete route", matches);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("file:target/data?noop=true")
+                    .process(new Processor() {
+                        public void process(Exchange exchange) throws 
Exception {
+                            log.info("Starting to process file");
+                            watch.restart();
+                        }
+                    })
+                    .split().xpath("/orders/order").streaming()
+                        .choice()
+                            .when().xpath("/order/amount < 10")
+                                .process(new Processor() {
+                                    public void process(Exchange exchange) 
throws Exception {
+                                        String xml = 
exchange.getIn().getBody(String.class);
+                                        assertTrue(xml, 
xml.contains("<amount>3</amount>"));
+
+                                        int num = tiny.incrementAndGet();
+                                        if (num % 100 == 0) {
+                                            log.info("Processed " + num + " 
tiny messages");
+                                            log.debug(xml);
+                                        }
+                                    }
+                                })
+                            .when().xpath("/order/amount < 50")
+                                .process(new Processor() {
+                                    public void process(Exchange exchange) 
throws Exception {
+                                        String xml = 
exchange.getIn().getBody(String.class);
+                                        assertTrue(xml, 
xml.contains("<amount>44</amount>"));
+
+                                        int num = small.incrementAndGet();
+                                        if (num % 100 == 0) {
+                                            log.info("Processed " + num + " 
small messages");
+                                            log.debug(xml);
+                                        }
+                                    }
+                                })
+                            .when().xpath("/order/amount < 100")
+                                .process(new Processor() {
+                                    public void process(Exchange exchange) 
throws Exception {
+                                        String xml = 
exchange.getIn().getBody(String.class);
+                                        assertTrue(xml, 
xml.contains("<amount>88</amount>"));
+
+                                        int num = med.incrementAndGet();
+                                        if (num % 100 == 0) {
+                                            log.info("Processed " + num + " 
medium messages");
+                                            log.debug(xml);
+                                        }
+                                    }
+                                })
+                            .otherwise()
+                                .process(new Processor() {
+                                    public void process(Exchange exchange) 
throws Exception {
+                                        String xml = 
exchange.getIn().getBody(String.class);
+                                        assertTrue(xml, 
xml.contains("<amount>123</amount>"));
+
+                                        int num = large.incrementAndGet();
+                                        if (num % 100 == 0) {
+                                            log.info("Processed " + num + " 
large messages");
+                                            log.debug(xml);
+                                        }
+                                    }
+                                })
+                        .end() // choice
+                    .end(); // split
+            }
+        };
+    }
+
+    public static void createDataFile(Logger log, int size) throws Exception {
+        deleteDirectory("target/data");
+        createDirectory("target/data");
+
+        log.info("Creating data file ...");
+
+        File file = new File("target/data/data.xml");
+        FileOutputStream fos = new FileOutputStream(file, true);
+        fos.write("<orders>\n".getBytes());
+
+        for (int i = 0; i < size; i++) {
+            fos.write("<order>\n".getBytes());
+            fos.write(("  <id>" + i + "</id>\n").getBytes());
+            int num = i % 10;
+            if (num >= 0 && num <= 3) {
+                fos.write("  <amount>3</amount>\n".getBytes());
+                fos.write("  <customerId>333</customerId>\n".getBytes());
+            } else if (num >= 4 && num <= 5) {
+                fos.write("  <amount>44</amount>\n".getBytes());
+                fos.write("  <customerId>444</customerId>\n".getBytes());
+            } else if (num >= 6 && num <= 8) {
+                fos.write("  <amount>88</amount>\n".getBytes());
+                fos.write("  <customerId>888</customerId>\n".getBytes());
+            } else {
+                fos.write("  <amount>123</amount>\n".getBytes());
+                fos.write("  <customerId>123123</customerId>\n".getBytes());
+            }
+            fos.write("  <description>bla bla bla bla bla bla bla bla bla bla 
bla bla bla bla bla bla</description>\n".getBytes());
+            fos.write("</order>\n".getBytes());
+        }
+
+        fos.write("</orders>".getBytes());
+        fos.close();
+
+        log.info("Creating data file done.");
+    }
+
+}

Propchange: 
camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/XPathSplitChoicePerformanceTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
camel/trunk/components/camel-saxon/src/test/java/org/apache/camel/builder/saxon/XPathSplitChoicePerformanceTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date


Reply via email to