camel-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From davscl...@apache.org
Subject svn commit: r990724 - in /camel/trunk: camel-core/src/main/java/org/apache/camel/ camel-core/src/main/java/org/apache/camel/component/bean/ camel-core/src/main/java/org/apache/camel/model/ camel-core/src/main/java/org/apache/camel/processor/ camel-core...
Date Mon, 30 Aug 2010 08:11:04 GMT
Author: davsclaus
Date: Mon Aug 30 08:11:03 2010
New Revision: 990724

URL: http://svn.apache.org/viewvc?rev=990724&view=rev
Log:
CAMEL-3074: Added dynamicRouter to the DSL.

Added:
    camel/trunk/camel-core/src/main/java/org/apache/camel/DynamicRouter.java
      - copied, changed from r990601, camel/trunk/camel-core/src/main/java/org/apache/camel/RoutingSlip.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/model/DynamicRouterDefinition.java
      - copied, changed from r990601, camel/trunk/camel-core/src/main/java/org/apache/camel/model/RoutingSlipDefinition.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/processor/DynamicRouter.java
    camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouter2Test.java
    camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouterAnnotationTest.java
    camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouterTest.java
    camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringDynamicRouterTest.java
      - copied, changed from r990601, camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringRecipientListParallelTest.java
    camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/SpringDynamicRouterTest.xml
      - copied, changed from r990601, camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/SpringRecipientListParallelTest.xml
Modified:
    camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/RoutingSlip.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/model/RoutingSlipDefinition.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/processor/RoutingSlip.java
    camel/trunk/camel-core/src/main/java/org/apache/camel/view/NodeData.java
    camel/trunk/camel-core/src/main/resources/org/apache/camel/model/jaxb.index
    camel/trunk/camel-core/src/test/java/org/apache/camel/processor/routingslip/RoutingSlipPOJOTest.java

Copied: camel/trunk/camel-core/src/main/java/org/apache/camel/DynamicRouter.java (from r990601, camel/trunk/camel-core/src/main/java/org/apache/camel/RoutingSlip.java)
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/DynamicRouter.java?p2=camel/trunk/camel-core/src/main/java/org/apache/camel/DynamicRouter.java&p1=camel/trunk/camel-core/src/main/java/org/apache/camel/RoutingSlip.java&r1=990601&r2=990724&rev=990724&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/RoutingSlip.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/DynamicRouter.java Mon Aug 30 08:11:03 2010
@@ -24,26 +24,26 @@ import java.lang.annotation.Target;
 
 /**
  * Indicates that this method is to be used as a 
- * <a href="http://camel.apache.org/routing-slip.html">Routing Slip</a> routing the incoming message
+ * <a href="http://camel.apache.org/dynamic-router.html">Dynamic Router</a> routing the incoming message
  * through a series of processing steps.
  *
- * When a message {@link org.apache.camel.Exchange} is received from an {@link org.apache.camel.Endpoint} then the
+ * When a message {@link Exchange} is received from an {@link Endpoint} then the
  * <a href="http://camel.apache.org/bean-integration.html">Bean Integration</a>
- * mechanism is used to map the incoming {@link org.apache.camel.Message} to the method parameters.
+ * mechanism is used to map the incoming {@link Message} to the method parameters.
  *
  * The return value of the method is then converted to either a {@link java.util.Collection} or array of objects where each
- * element is converted to an {@link Endpoint} or a {@link String}, or if it is not a collection/array then it is converted
- * to an {@link Endpoint} or {@link String}.
+ * element is converted to an {@link org.apache.camel.Endpoint} or a {@link String}, or if it is not a collection/array then it is converted
+ * to an {@link org.apache.camel.Endpoint} or {@link String}.
  *
- * Then for each endpoint or URI the message is forwarded a separate copy.
+ * Then for each endpoint or URI the message is routed in a pipes and filter fashion.
  *
+ * @see org.apache.camel.RoutingSlip
  * @version $Revision$
  */
-
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
-@Target({ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR })
-public @interface RoutingSlip {
+@Target({ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface DynamicRouter {
     String context() default "";
     String delimiter() default ",";
     boolean ignoreInvalidEndpoints() default false;

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java?rev=990724&r1=990723&r2=990724&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java Mon Aug 30 08:11:03 2010
@@ -109,6 +109,7 @@ public interface Exchange {
 
     String SOAP_ACTION        = "CamelSoapAction";
     String SKIP_GZIP_ENCODING = "CamelSkipGzipEncoding";
+    String SLIP_ENDPOINT      = "CamelSlipEndpoint";
     String SPLIT_INDEX        = "CamelSplitIndex";
     String SPLIT_COMPLETE     = "CamelSplitComplete";
     String SPLIT_SIZE         = "CamelSplitSize";

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/RoutingSlip.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/RoutingSlip.java?rev=990724&r1=990723&r2=990724&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/RoutingSlip.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/RoutingSlip.java Mon Aug 30 08:11:03 2010
@@ -35,14 +35,14 @@ import java.lang.annotation.Target;
  * element is converted to an {@link Endpoint} or a {@link String}, or if it is not a collection/array then it is converted
  * to an {@link Endpoint} or {@link String}.
  *
- * Then for each endpoint or URI the message is forwarded a separate copy.
+ * Then for each endpoint or URI the message is routed in a pipes and filter fashion.
  *
+ * @see org.apache.camel.DynamicRouter
  * @version $Revision$
  */
-
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
-@Target({ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR })
+@Target({ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR})
 public @interface RoutingSlip {
     String context() default "";
     String delimiter() default ",";

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java?rev=990724&r1=990723&r2=990724&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfo.java Mon Aug 30 08:11:03 2010
@@ -34,6 +34,8 @@ import org.apache.camel.ExchangePattern;
 import org.apache.camel.Expression;
 import org.apache.camel.NoTypeConversionAvailableException;
 import org.apache.camel.Pattern;
+import org.apache.camel.impl.ExpressionAdapter;
+import org.apache.camel.processor.DynamicRouter;
 import org.apache.camel.processor.RecipientList;
 import org.apache.camel.processor.RoutingSlip;
 import org.apache.camel.processor.aggregate.AggregationStrategy;
@@ -64,6 +66,34 @@ public class MethodInfo {
     private ExchangePattern pattern = ExchangePattern.InOut;
     private RecipientList recipientList;
     private RoutingSlip routingSlip;
+    private DynamicRouter dynamicRouter;
+
+    /**
+     * Adapter to invoke the method which has been annotated with the @DynamicRouter
+     */
+    private final class DynamicRouterExpression extends ExpressionAdapter {
+        private final Object pojo;
+
+        private DynamicRouterExpression(Object pojo) {
+            this.pojo = pojo;
+        }
+
+        @Override
+        public Object evaluate(Exchange exchange) {
+            // evaluate arguments on each invocation as the parameters can have changed/updated since last invocation
+            final Object[] arguments = parametersExpression.evaluate(exchange, Object[].class);
+            try {
+                return invoke(method, pojo, arguments, exchange);
+            } catch (Exception e) {
+                throw ObjectHelper.wrapRuntimeCamelException(e);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "DynamicRouter[invoking: " + method + " on bean: " + pojo + "]";
+        }
+    }
 
     public MethodInfo(CamelContext camelContext, Class<?> type, Method method, List<ParameterInfo> parameters, List<ParameterInfo> bodyParameters,
                       boolean hasCustomAnnotation, boolean hasHandlerAnnotation) {
@@ -87,7 +117,7 @@ public class MethodInfo {
             routingSlip = new RoutingSlip(camelContext);
             routingSlip.setDelimiter(annotation.delimiter());
             routingSlip.setIgnoreInvalidEndpoints(annotation.ignoreInvalidEndpoints());
-            // add created recipientList as a service so we have its lifecycle managed
+            // add created routingSlip as a service so we have its lifecycle managed
             try {
                 camelContext.addService(routingSlip);
             } catch (Exception e) {
@@ -95,6 +125,20 @@ public class MethodInfo {
             }
         }
 
+        if (method.getAnnotation(org.apache.camel.DynamicRouter.class) != null
+                && matchContext(method.getAnnotation(org.apache.camel.DynamicRouter.class).context())) {
+            org.apache.camel.DynamicRouter annotation = method.getAnnotation(org.apache.camel.DynamicRouter.class);
+            dynamicRouter = new DynamicRouter(camelContext);
+            dynamicRouter.setDelimiter(annotation.delimiter());
+            dynamicRouter.setIgnoreInvalidEndpoints(annotation.ignoreInvalidEndpoints());
+            // add created dynamicRouter as a service so we have its lifecycle managed
+            try {
+                camelContext.addService(dynamicRouter);
+            } catch (Exception e) {
+                throw ObjectHelper.wrapRuntimeCamelException(e);
+            }
+        }
+
         if (method.getAnnotation(org.apache.camel.RecipientList.class) != null
                 && matchContext(method.getAnnotation(org.apache.camel.RecipientList.class).context())) {
 
@@ -160,10 +204,25 @@ public class MethodInfo {
             }
 
             public Object proceed(AsyncCallback callback, AtomicBoolean doneSync) throws Exception {
+                // dynamic router should be invoked beforehand
+                if (dynamicRouter != null) {
+                    if (!dynamicRouter.isStarted()) {
+                        ServiceHelper.startService(dynamicRouter);
+                    }
+                    // use a expression which invokes the method to be used by dynamic router
+                    Expression expression = new DynamicRouterExpression(pojo);
+                    boolean sync = dynamicRouter.doRoutingSlip(exchange, expression, callback);
+                    // must remember the done sync returned from the dynamic router
+                    doneSync.set(sync);
+                    return Void.TYPE;
+                }
+
+                // invoke pojo
                 if (LOG.isTraceEnabled()) {
                     LOG.trace(">>>> invoking: " + method + " on bean: " + pojo + " with arguments: " + asString(arguments) + " for exchange: " + exchange);
                 }
                 Object result = invoke(method, pojo, arguments, exchange);
+
                 if (recipientList != null) {
                     // ensure its started
                     if (!recipientList.isStarted()) {
@@ -185,6 +244,7 @@ public class MethodInfo {
                     doneSync.set(sync);
                     return Void.TYPE;
                 }
+
                 return result;
             }
 

Copied: camel/trunk/camel-core/src/main/java/org/apache/camel/model/DynamicRouterDefinition.java (from r990601, camel/trunk/camel-core/src/main/java/org/apache/camel/model/RoutingSlipDefinition.java)
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/model/DynamicRouterDefinition.java?p2=camel/trunk/camel-core/src/main/java/org/apache/camel/model/DynamicRouterDefinition.java&p1=camel/trunk/camel-core/src/main/java/org/apache/camel/model/RoutingSlipDefinition.java&r1=990601&r2=990724&rev=990724&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/model/RoutingSlipDefinition.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/model/DynamicRouterDefinition.java Mon Aug 30 08:11:03 2010
@@ -18,7 +18,6 @@ package org.apache.camel.model;
 
 import java.util.Collections;
 import java.util.List;
-
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.XmlAttribute;
@@ -26,70 +25,37 @@ import javax.xml.bind.annotation.XmlRoot
 
 import org.apache.camel.Expression;
 import org.apache.camel.Processor;
-import org.apache.camel.builder.Builder;
-import org.apache.camel.processor.RoutingSlip;
+import org.apache.camel.processor.DynamicRouter;
 import org.apache.camel.spi.RouteContext;
 
 /**
- * Represents an XML &lt;routingSlip/&gt; element
+ * Represents an XML &lt;dynamicRouter/&gt; element
  */
-@XmlRootElement(name = "routingSlip")
+@XmlRootElement(name = "dynamicRouter")
 @XmlAccessorType(XmlAccessType.FIELD)
-public class RoutingSlipDefinition <Type extends ProcessorDefinition> extends NoOutputExpressionNode {
+public class DynamicRouterDefinition<Type extends ProcessorDefinition> extends NoOutputExpressionNode {
+
     public static final String DEFAULT_DELIMITER = ",";
-    @Deprecated
-    private String headerName;
     @XmlAttribute
-    private String uriDelimiter;
+    private String uriDelimiter = DEFAULT_DELIMITER;
     @XmlAttribute
     private Boolean ignoreInvalidEndpoints;
 
-    public RoutingSlipDefinition() {
-        this((String)null, DEFAULT_DELIMITER);
-    }
-
-    public RoutingSlipDefinition(String headerName) {
-        this(headerName, DEFAULT_DELIMITER);
+    public DynamicRouterDefinition() {
     }
 
-    public RoutingSlipDefinition(String headerName, String uriDelimiter) {
-        super(Builder.header(headerName));
-        setHeaderName(headerName);
-        setUriDelimiter(uriDelimiter);       
-    }
-    
-    public RoutingSlipDefinition(Expression expression, String uriDelimiter) {
+    public DynamicRouterDefinition(Expression expression) {
         super(expression);
-        setUriDelimiter(uriDelimiter);
-    }
-    
-    public RoutingSlipDefinition(Expression expression) {
-        this(expression, DEFAULT_DELIMITER);
     }
 
     @Override
     public String toString() {
-        return "RoutingSlip[headerName=" + getHeaderName() + ", uriDelimiter=" + getUriDelimiter() + "]";
+        return "DynamicRouter[" + getExpression() + "]";
     }
 
     @Override
     public String getShortName() {
-        return "routingSlip";
-    }
-
-    @Override
-    public Processor createProcessor(RouteContext routeContext) throws Exception {
-        RoutingSlip routingSlip;
-        if (getHeaderName() != null) {        
-            routingSlip = new RoutingSlip(routeContext.getCamelContext(), getHeaderName(), getUriDelimiter());
-        } else {
-            Expression expression = getExpression().createExpression(routeContext);
-            routingSlip = new RoutingSlip(routeContext.getCamelContext(), expression, getUriDelimiter());
-        }
-        if (getIgnoreInvalidEndpoint() != null) {
-            routingSlip.setIgnoreInvalidEndpoints(getIgnoreInvalidEndpoint());
-        }
-        return routingSlip;
+        return "dynamicRouter";
     }
 
     @Override
@@ -97,14 +63,15 @@ public class RoutingSlipDefinition <Type
         return Collections.emptyList();
     }
 
-    @Deprecated
-    public void setHeaderName(String headerName) {
-        this.headerName = headerName;
-    }
+    @Override
+    public Processor createProcessor(RouteContext routeContext) throws Exception {
+        Expression expression = getExpression().createExpression(routeContext);
 
-    @Deprecated
-    public String getHeaderName() {
-        return this.headerName;
+        DynamicRouter dynamicRouter = new DynamicRouter(routeContext.getCamelContext(), expression, getUriDelimiter());
+        if (getIgnoreInvalidEndpoint() != null) {
+            dynamicRouter.setIgnoreInvalidEndpoints(getIgnoreInvalidEndpoint());
+        }
+        return dynamicRouter;
     }
 
     public void setUriDelimiter(String uriDelimiter) {
@@ -114,33 +81,44 @@ public class RoutingSlipDefinition <Type
     public String getUriDelimiter() {
         return uriDelimiter;
     }
-    
+
     public void setIgnoreInvalidEndpoints(Boolean ignoreInvalidEndpoints) {
         this.ignoreInvalidEndpoints = ignoreInvalidEndpoints;
     }
-    
+
     public Boolean getIgnoreInvalidEndpoint() {
         return ignoreInvalidEndpoints;
     }
-    
+
     // Fluent API
     // -------------------------------------------------------------------------
 
-    
     @Override
     @SuppressWarnings("unchecked")
     public Type end() {
         // allow end() to return to previous type so you can continue in the DSL
         return (Type) super.end();
     }
-    
+
     /**
      * Ignore the invalidate endpoint exception when try to create a producer with that endpoint
      *
      * @return the builder
      */
-    public RoutingSlipDefinition<Type> ignoreInvalidEndpoints() {
+    public DynamicRouterDefinition<Type> ignoreInvalidEndpoints() {
         setIgnoreInvalidEndpoints(true);
         return this;
     }
+
+    /**
+     * Sets the uri delimiter to use
+     *
+     * @param uriDelimiter the delimiter
+     * @return the builder
+     */
+    public DynamicRouterDefinition<Type> uriDelimiter(String uriDelimiter) {
+        setUriDelimiter(uriDelimiter);
+        return this;
+    }
+
 }

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java?rev=990724&r1=990723&r2=990724&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java Mon Aug 30 08:11:03 2010
@@ -1218,6 +1218,8 @@ public abstract class ProcessorDefinitio
      * <a href="http://camel.apache.org/routing-slip.html">Routing Slip EIP:</a>
      * Creates a routing slip allowing you to route a message consecutively through a series of processing
      * steps where the sequence of steps is not known at design time and can vary for each message.
+     * <p/>
+     * The route slip will be evaluated <i>once</i>, use {@link #dynamicRouter()} if you need even more dynamic routing.
      *
      * @param header  is the header that the {@link org.apache.camel.processor.RoutingSlip RoutingSlip}
      *                class will look in for the list of URIs to route the message to.
@@ -1236,8 +1238,10 @@ public abstract class ProcessorDefinitio
      * <a href="http://camel.apache.org/routing-slip.html">Routing Slip EIP:</a>
      * Creates a routing slip allowing you to route a message consecutively through a series of processing
      * steps where the sequence of steps is not known at design time and can vary for each message.
-     * <p>
+     * <p/>
      * The list of URIs will be split based on the default delimiter {@link RoutingSlipDefinition#DEFAULT_DELIMITER}
+     * <p/>
+     * The route slip will be evaluated <i>once</i>, use {@link #dynamicRouter()} if you need even more dynamic routing.
      *
      * @param header  is the header that the {@link org.apache.camel.processor.RoutingSlip RoutingSlip}
      *                class will look in for the list of URIs to route the message to.
@@ -1254,6 +1258,8 @@ public abstract class ProcessorDefinitio
      * <a href="http://camel.apache.org/routing-slip.html">Routing Slip EIP:</a>
      * Creates a routing slip allowing you to route a message consecutively through a series of processing
      * steps where the sequence of steps is not known at design time and can vary for each message.
+     * <p/>
+     * The route slip will be evaluated <i>once</i>, use {@link #dynamicRouter()} if you need even more dynamic routing.
      *
      * @param header  is the header that the {@link org.apache.camel.processor.RoutingSlip RoutingSlip}
      *                class will look in for the list of URIs to route the message to.
@@ -1275,8 +1281,10 @@ public abstract class ProcessorDefinitio
      * <a href="http://camel.apache.org/routing-slip.html">Routing Slip EIP:</a>
      * Creates a routing slip allowing you to route a message consecutively through a series of processing
      * steps where the sequence of steps is not known at design time and can vary for each message.
-     * <p>
+     * <p/>
      * The list of URIs will be split based on the default delimiter {@link RoutingSlipDefinition#DEFAULT_DELIMITER}
+     * <p/>
+     * The route slip will be evaluated <i>once</i>, use {@link #dynamicRouter()} if you need even more dynamic routing.
      *
      * @param header  is the header that the {@link org.apache.camel.processor.RoutingSlip RoutingSlip}
      *                class will look in for the list of URIs to route the message to.
@@ -1296,6 +1304,8 @@ public abstract class ProcessorDefinitio
      * <a href="http://camel.apache.org/routing-slip.html">Routing Slip EIP:</a>
      * Creates a routing slip allowing you to route a message consecutively through a series of processing
      * steps where the sequence of steps is not known at design time and can vary for each message.
+     * <p/>
+     * The route slip will be evaluated <i>once</i>, use {@link #dynamicRouter()} if you need even more dynamic routing.
      *
      * @param expression  to decide the destinations
      * @param uriDelimiter  is the delimiter that will be used to split up
@@ -1313,8 +1323,10 @@ public abstract class ProcessorDefinitio
      * <a href="http://camel.apache.org/routing-slip.html">Routing Slip EIP:</a>
      * Creates a routing slip allowing you to route a message consecutively through a series of processing
      * steps where the sequence of steps is not known at design time and can vary for each message.
-     * <p>
+     * <p/>
      * The list of URIs will be split based on the default delimiter {@link RoutingSlipDefinition#DEFAULT_DELIMITER}
+     * <p/>
+     * The route slip will be evaluated <i>once</i>, use {@link #dynamicRouter()} if you need even more dynamic routing.
      *
      * @param expression  to decide the destinations
      * 
@@ -1330,10 +1342,11 @@ public abstract class ProcessorDefinitio
      * <a href="http://camel.apache.org/routing-slip.html">Routing Slip EIP:</a>
      * Creates a routing slip allowing you to route a message consecutively through a series of processing
      * steps where the sequence of steps is not known at design time and can vary for each message.
-     * <p>
+     * <p/>
      * The list of URIs will be split based on the default delimiter {@link RoutingSlipDefinition#DEFAULT_DELIMITER}
+     * <p/>
+     * The route slip will be evaluated <i>once</i>, use {@link #dynamicRouter()} if you need even more dynamic routing.
      *
-     * 
      * @return the expression clause to configure the expression to decide the destinations
      */
     public ExpressionClause<RoutingSlipDefinition<Type>> routingSlip() {
@@ -1343,6 +1356,41 @@ public abstract class ProcessorDefinitio
     }
 
     /**
+     * <a href="http://camel.apache.org/dynamic-router.html">Dynamic Router EIP:</a>
+     * Creates a dynamic router allowing you to route a message consecutively through a series of processing
+     * steps where the sequence of steps is not known at design time and can vary for each message.
+     * <p/>
+     * <br/><b>Important:</b> The expression will be invoked repeatedly until it returns <tt>null</tt>, so be sure it does that,
+     * otherwise it will be invoked endlessly.
+     *
+     * @param expression  to decide the destinations, which will be invoked repeatedly
+     *                    until it evaluates <tt>null</tt> to indicate no more destinations.
+     * @return the builder
+     */
+    public DynamicRouterDefinition<Type> dynamicRouter(Expression expression) {
+        DynamicRouterDefinition<Type> answer = new DynamicRouterDefinition<Type>(expression);
+        addOutput(answer);
+        return answer;
+    }
+
+    /**
+     * <a href="http://camel.apache.org/dynamic-router.html">Dynamic Router EIP:</a>
+     * Creates a dynamic router allowing you to route a message consecutively through a series of processing
+     * steps where the sequence of steps is not known at design time and can vary for each message.
+     * <p/>
+     * <br/><b>Important:</b> The expression will be invoked repeatedly until it returns <tt>null</tt>, so be sure it does that,
+     * otherwise it will be invoked endlessly.
+     *
+     * @return the expression clause to configure the expression to decide the destinations,
+     * which will be invoked repeatedly until it evaluates <tt>null</tt> to indicate no more destinations.
+     */
+    public ExpressionClause<DynamicRouterDefinition<Type>> dynamicRouter() {
+        DynamicRouterDefinition<Type> answer = new DynamicRouterDefinition<Type>();
+        addOutput(answer);
+        return ExpressionClause.createAndSetExpression(answer);
+    }
+
+    /**
      * <a href="http://camel.apache.org/sampling.html">Sampling Throttler</a>
      * Creates a sampling throttler allowing you to extract a sample of
      * exchanges from the traffic on a route. It is configured with a sampling

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/model/RoutingSlipDefinition.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/model/RoutingSlipDefinition.java?rev=990724&r1=990723&r2=990724&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/model/RoutingSlipDefinition.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/model/RoutingSlipDefinition.java Mon Aug 30 08:11:03 2010
@@ -35,10 +35,8 @@ import org.apache.camel.spi.RouteContext
  */
 @XmlRootElement(name = "routingSlip")
 @XmlAccessorType(XmlAccessType.FIELD)
-public class RoutingSlipDefinition <Type extends ProcessorDefinition> extends NoOutputExpressionNode {
+public class RoutingSlipDefinition<Type extends ProcessorDefinition> extends NoOutputExpressionNode {
     public static final String DEFAULT_DELIMITER = ",";
-    @Deprecated
-    private String headerName;
     @XmlAttribute
     private String uriDelimiter;
     @XmlAttribute
@@ -54,8 +52,7 @@ public class RoutingSlipDefinition <Type
 
     public RoutingSlipDefinition(String headerName, String uriDelimiter) {
         super(Builder.header(headerName));
-        setHeaderName(headerName);
-        setUriDelimiter(uriDelimiter);       
+        setUriDelimiter(uriDelimiter);
     }
     
     public RoutingSlipDefinition(Expression expression, String uriDelimiter) {
@@ -69,7 +66,7 @@ public class RoutingSlipDefinition <Type
 
     @Override
     public String toString() {
-        return "RoutingSlip[headerName=" + getHeaderName() + ", uriDelimiter=" + getUriDelimiter() + "]";
+        return "RoutingSlip[" + getExpression() + "]";
     }
 
     @Override
@@ -79,13 +76,8 @@ public class RoutingSlipDefinition <Type
 
     @Override
     public Processor createProcessor(RouteContext routeContext) throws Exception {
-        RoutingSlip routingSlip;
-        if (getHeaderName() != null) {        
-            routingSlip = new RoutingSlip(routeContext.getCamelContext(), getHeaderName(), getUriDelimiter());
-        } else {
-            Expression expression = getExpression().createExpression(routeContext);
-            routingSlip = new RoutingSlip(routeContext.getCamelContext(), expression, getUriDelimiter());
-        }
+        Expression expression = getExpression().createExpression(routeContext);
+        RoutingSlip routingSlip = new RoutingSlip(routeContext.getCamelContext(), expression, getUriDelimiter());
         if (getIgnoreInvalidEndpoint() != null) {
             routingSlip.setIgnoreInvalidEndpoints(getIgnoreInvalidEndpoint());
         }
@@ -97,16 +89,6 @@ public class RoutingSlipDefinition <Type
         return Collections.emptyList();
     }
 
-    @Deprecated
-    public void setHeaderName(String headerName) {
-        this.headerName = headerName;
-    }
-
-    @Deprecated
-    public String getHeaderName() {
-        return this.headerName;
-    }
-
     public void setUriDelimiter(String uriDelimiter) {
         this.uriDelimiter = uriDelimiter;
     }
@@ -126,7 +108,6 @@ public class RoutingSlipDefinition <Type
     // Fluent API
     // -------------------------------------------------------------------------
 
-    
     @Override
     @SuppressWarnings("unchecked")
     public Type end() {
@@ -143,4 +124,15 @@ public class RoutingSlipDefinition <Type
         setIgnoreInvalidEndpoints(true);
         return this;
     }
+
+    /**
+     * Sets the uri delimiter to use
+     *
+     * @param uriDelimiter the delimiter
+     * @return the builder
+     */
+    public RoutingSlipDefinition<Type> uriDelimiter(String uriDelimiter) {
+        setUriDelimiter(uriDelimiter);
+        return this;
+    }
 }

Added: camel/trunk/camel-core/src/main/java/org/apache/camel/processor/DynamicRouter.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/processor/DynamicRouter.java?rev=990724&view=auto
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/processor/DynamicRouter.java (added)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/processor/DynamicRouter.java Mon Aug 30 08:11:03 2010
@@ -0,0 +1,79 @@
+/**
+ * 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.util.Iterator;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Expression;
+import org.apache.camel.util.ObjectHelper;
+
+/**
+ * Implements a <a href="http://camel.apache.org/dynamic-router.html">Dynamic Router</a> pattern
+ * where the destination(s) is computed at runtime.
+ * <p/>
+ * This implementation builds on top of {@link org.apache.camel.processor.RoutingSlip} which contains
+ * the most logic.
+ *
+ * @version $Revision$
+ */
+public class DynamicRouter extends RoutingSlip {
+    
+    public DynamicRouter(CamelContext camelContext) {
+        super(camelContext);
+    }
+
+    public DynamicRouter(CamelContext camelContext, Expression expression, String uriDelimiter) {
+        super(camelContext, expression, uriDelimiter);
+    }
+
+    @Override
+    protected RoutingSlipIterator createRoutingSlipIterator(Exchange exchange) {
+        return new DynamicRoutingSlipIterator(expression);
+    }
+
+    /**
+     * The dynamic routing slip iterator.
+     */
+    private final class DynamicRoutingSlipIterator implements RoutingSlipIterator {
+
+        private final Expression slip;
+        private Iterator current;
+
+        private DynamicRoutingSlipIterator(Expression slip) {
+            this.slip = slip;
+        }
+
+        public boolean hasNext(Exchange exchange) {
+            if (current != null && current.hasNext()) {
+                return true;
+            }
+            // evaluate next slip
+            Object routingSlip = slip.evaluate(exchange, Object.class);
+            if (routingSlip == null) {
+                return false;
+            }
+            current = ObjectHelper.createIterator(routingSlip, uriDelimiter);
+            return current != null && current.hasNext();
+        }
+
+        public Object next(Exchange exchange) {
+            return current.next();
+        }
+    }
+}

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/processor/RoutingSlip.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/processor/RoutingSlip.java?rev=990724&r1=990723&r2=990724&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/processor/RoutingSlip.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/processor/RoutingSlip.java Mon Aug 30 08:11:03 2010
@@ -33,7 +33,6 @@ import org.apache.camel.builder.Expressi
 import org.apache.camel.impl.DefaultExchange;
 import org.apache.camel.impl.ProducerCache;
 import org.apache.camel.impl.ServiceSupport;
-import org.apache.camel.model.RoutingSlipDefinition;
 import org.apache.camel.util.AsyncProcessorHelper;
 import org.apache.camel.util.ExchangeHelper;
 import org.apache.camel.util.ObjectHelper;
@@ -53,41 +52,42 @@ import static org.apache.camel.util.Obje
  * pipeline to ensure it works the same and the async routing engine is flawless.
  */
 public class RoutingSlip extends ServiceSupport implements AsyncProcessor, Traceable {
-    private static final transient Log LOG = LogFactory.getLog(RoutingSlip.class);
-    private ProducerCache producerCache;
-    private boolean ignoreInvalidEndpoints;
-    private String header;
-    private Expression expression;    
-    private String uriDelimiter;
-    private final CamelContext camelContext;
-    
-    public RoutingSlip(CamelContext camelContext) {
-        this.camelContext = camelContext;
-    }
+    protected final transient Log log = LogFactory.getLog(getClass());
+    protected ProducerCache producerCache;
+    protected boolean ignoreInvalidEndpoints;
+    protected String header;
+    protected Expression expression;
+    protected String uriDelimiter;
+    protected final CamelContext camelContext;
 
     /**
-     * Will be removed in Camel 2.5
+     * The iterator to be used for retrieving the next routing slip(s) to be used.
      */
-    @Deprecated
-    public RoutingSlip(CamelContext camelContext, String header) {
-        this(camelContext, header, RoutingSlipDefinition.DEFAULT_DELIMITER);
+    protected interface RoutingSlipIterator {
+
+        /**
+         * Are the more routing slip(s)?
+         *
+         * @param exchange the current exchange
+         * @return <tt>true</tt> if more slips, <tt>false</tt> otherwise.
+         */
+        boolean hasNext(Exchange exchange);
+
+        /**
+         * Returns the next routing slip(s).
+         *
+         * @param exchange the current exchange
+         * @return the slip(s).
+         */
+        Object next(Exchange exchange);
+
     }
 
-    /**
-     * Will be removed in Camel 2.5
-     */
-    @Deprecated
-    public RoutingSlip(CamelContext camelContext, String header, String uriDelimiter) {
+    public RoutingSlip(CamelContext camelContext) {
         notNull(camelContext, "camelContext");
-        notNull(header, "header");
-        notNull(uriDelimiter, "uriDelimiter");
-
         this.camelContext = camelContext;
-        this.header = header;
-        expression = ExpressionBuilder.headerExpression(header);
-        this.uriDelimiter = uriDelimiter;
     }
-    
+
     public RoutingSlip(CamelContext camelContext, Expression expression, String uriDelimiter) {
         notNull(camelContext, "camelContext");
         notNull(expression, "expression");
@@ -128,15 +128,49 @@ public class RoutingSlip extends Service
             throw new IllegalStateException("RoutingSlip has not been started: " + this);
         }
 
-        Object routingSlip = expression.evaluate(exchange, Object.class);
-        return doRoutingSlip(exchange, routingSlip, callback);
+        return doRoutingSlip(exchange, callback);
     }
 
     public boolean doRoutingSlip(Exchange exchange, Object routingSlip, AsyncCallback callback) {
-        Iterator<Object> iter = ObjectHelper.createIterator(routingSlip, uriDelimiter);
+        if (routingSlip instanceof Expression) {
+            this.expression = (Expression) routingSlip;
+        } else {
+            this.expression = ExpressionBuilder.constantExpression(routingSlip);
+        }
+        return doRoutingSlip(exchange, callback);
+    }
+
+    /**
+     * Creates the route slip iterator to be used.
+     *
+     * @param exchange the exchange
+     * @return the iterator, should never be <tt>null</tt>
+     */
+    protected RoutingSlipIterator createRoutingSlipIterator(final Exchange exchange) {
+        Object slip = expression.evaluate(exchange, Object.class);
+        final Iterator<Object> delegate = ObjectHelper.createIterator(slip, uriDelimiter);
+
+        return new RoutingSlipIterator() {
+            public boolean hasNext(Exchange exchange) {
+                return delegate.hasNext();
+            }
+
+            public Object next(Exchange exchange) {
+                return delegate.next();
+            }
+        };
+    }
+
+    private boolean doRoutingSlip(Exchange exchange, AsyncCallback callback) {
         Exchange current = exchange;
+        RoutingSlipIterator iter = createRoutingSlipIterator(exchange);
 
-        while (iter.hasNext()) {
+        // ensure the slip is empty when we start
+        if (current.hasProperties()) {
+            current.setProperty(Exchange.SLIP_ENDPOINT, null);
+        }
+
+        while (iter.hasNext(current)) {
             Endpoint endpoint;
             try {
                 endpoint = resolveEndpoint(iter, exchange);
@@ -151,28 +185,28 @@ public class RoutingSlip extends Service
             }
 
             // prepare and process the routing slip
-            Exchange copy = prepareExchangeForRoutingSlip(current);
+            Exchange copy = prepareExchangeForRoutingSlip(current, endpoint);
             boolean sync = processExchange(endpoint, copy, exchange, callback, iter);
             current = copy;
 
             if (!sync) {
-                if (LOG.isTraceEnabled()) {
-                    LOG.trace("Processing exchangeId: " + exchange.getExchangeId() + " is continued being processed asynchronously");
+                if (log.isTraceEnabled()) {
+                    log.trace("Processing exchangeId: " + exchange.getExchangeId() + " is continued being processed asynchronously");
                 }
                 // the remainder of the routing slip will be completed async
                 // so we break out now, then the callback will be invoked which then continue routing from where we left here
                 return false;
             }
 
-            if (LOG.isTraceEnabled()) {
-                LOG.trace("Processing exchangeId: " + exchange.getExchangeId() + " is continued being processed synchronously");
+            if (log.isTraceEnabled()) {
+                log.trace("Processing exchangeId: " + exchange.getExchangeId() + " is continued being processed synchronously");
             }
 
             // we ignore some kind of exceptions and allow us to continue
             if (isIgnoreInvalidEndpoints()) {
                 FailedToCreateProducerException e = current.getException(FailedToCreateProducerException.class);
                 if (e != null) {
-                    LOG.info("Endpoint uri is invalid: " + endpoint + ". This exception will be ignored.", e);
+                    log.info("Endpoint uri is invalid: " + endpoint + ". This exception will be ignored.", e);
                     current.setException(null);
                 }
             }
@@ -182,7 +216,7 @@ public class RoutingSlip extends Service
             if (current.isFailed() || current.isRollbackOnly() || exceptionHandled) {
                 // The Exchange.ERRORHANDLED_HANDLED property is only set if satisfactory handling was done
                 // by the error handler. It's still an exception, the exchange still failed.
-                if (LOG.isDebugEnabled()) {
+                if (log.isDebugEnabled()) {
                     StringBuilder sb = new StringBuilder();
                     sb.append("Message exchange has failed so breaking out of the routing slip: ").append(current);
                     if (current.isRollbackOnly()) {
@@ -197,17 +231,17 @@ public class RoutingSlip extends Service
                     if (exceptionHandled) {
                         sb.append(" Handled by the error handler.");
                     }
-                    LOG.debug(sb.toString());
+                    log.debug(sb.toString());
                 }
                 break;
             }
         }
 
-        if (LOG.isTraceEnabled()) {
+        if (log.isTraceEnabled()) {
             // logging nextExchange as it contains the exchange that might have altered the payload and since
             // we are logging the completion if will be confusing if we log the original instead
             // we could also consider logging the original and the nextExchange then we have *before* and *after* snapshots
-            LOG.trace("Processing complete for exchangeId: " + exchange.getExchangeId() + " >>> " + current);
+            log.trace("Processing complete for exchangeId: " + exchange.getExchangeId() + " >>> " + current);
         }
 
         // copy results back to the original exchange
@@ -217,14 +251,14 @@ public class RoutingSlip extends Service
         return true;
     }
 
-    protected Endpoint resolveEndpoint(Iterator<Object> iter, Exchange exchange) throws Exception {
-        Object nextRecipient = iter.next();
+    protected Endpoint resolveEndpoint(RoutingSlipIterator iter, Exchange exchange) throws Exception {
+        Object nextRecipient = iter.next(exchange);
         Endpoint endpoint = null;
         try {
             endpoint = ExchangeHelper.resolveEndpoint(exchange, nextRecipient);
         } catch (Exception e) {
             if (isIgnoreInvalidEndpoints()) {
-                LOG.info("Endpoint uri is invalid: " + nextRecipient + ". This exception will be ignored.", e);
+                log.info("Endpoint uri is invalid: " + nextRecipient + ". This exception will be ignored.", e);
             } else {
                 throw e;
             }
@@ -232,7 +266,7 @@ public class RoutingSlip extends Service
         return endpoint;
     }
 
-    protected Exchange prepareExchangeForRoutingSlip(Exchange current) {
+    protected Exchange prepareExchangeForRoutingSlip(Exchange current, Endpoint endpoint) {
         Exchange copy = new DefaultExchange(current);
         // we must use the same id as this is a snapshot strategy where Camel copies a snapshot
         // before processing the next step in the pipeline, so we have a snapshot of the exchange
@@ -240,24 +274,25 @@ public class RoutingSlip extends Service
         // DeadLetterChannel. That is why it's important the id is the same, as it is the *same*
         // exchange being routed.
         copy.setExchangeId(current.getExchangeId());
-        updateRoutingSlipHeader(current);
         copyOutToIn(copy, current);
         return copy;
     }
 
     protected boolean processExchange(final Endpoint endpoint, final Exchange exchange, final Exchange original,
-                                      final AsyncCallback callback, final Iterator<Object> iter) {
+                                      final AsyncCallback callback, final RoutingSlipIterator iter) {
 
-        if (LOG.isTraceEnabled()) {
+        if (log.isTraceEnabled()) {
             // this does the actual processing so log at trace level
-            LOG.trace("Processing exchangeId: " + exchange.getExchangeId() + " >>> " + exchange);
+            log.trace("Processing exchangeId: " + exchange.getExchangeId() + " >>> " + exchange);
         }
 
         boolean sync = producerCache.doInAsyncProducer(endpoint, exchange, null, callback, new AsyncProducerCallback() {
             public boolean doInAsyncProducer(Producer producer, AsyncProcessor asyncProducer, final Exchange exchange,
                                              ExchangePattern exchangePattern, final AsyncCallback callback) {
                 // set property which endpoint we send to
-                exchange.setProperty(Exchange.TO_ENDPOINT, producer.getEndpoint().getEndpointUri());
+                exchange.setProperty(Exchange.TO_ENDPOINT, endpoint.getEndpointUri());
+                exchange.setProperty(Exchange.SLIP_ENDPOINT, endpoint.getEndpointUri());
+
                 boolean sync = AsyncProcessorHelper.process(asyncProducer, exchange, new AsyncCallback() {
                     public void done(boolean doneSync) {
                         // we only have to handle async completion of the routing slip
@@ -268,13 +303,13 @@ public class RoutingSlip extends Service
                         // continue processing the routing slip asynchronously
                         Exchange current = exchange;
 
-                        while (iter.hasNext()) {
+                        while (iter.hasNext(current)) {
 
                             // we ignore some kind of exceptions and allow us to continue
                             if (isIgnoreInvalidEndpoints()) {
                                 FailedToCreateProducerException e = current.getException(FailedToCreateProducerException.class);
                                 if (e != null) {
-                                    LOG.info("Endpoint uri is invalid: " + endpoint + ". This exception will be ignored.", e);
+                                    log.info("Endpoint uri is invalid: " + endpoint + ". This exception will be ignored.", e);
                                     current.setException(null);
                                 }
                             }
@@ -284,7 +319,7 @@ public class RoutingSlip extends Service
                             if (current.isFailed() || current.isRollbackOnly() || exceptionHandled) {
                                 // The Exchange.ERRORHANDLED_HANDLED property is only set if satisfactory handling was done
                                 // by the error handler. It's still an exception, the exchange still failed.
-                                if (LOG.isDebugEnabled()) {
+                                if (log.isDebugEnabled()) {
                                     StringBuilder sb = new StringBuilder();
                                     sb.append("Message exchange has failed so breaking out of the routing slip: ").append(current);
                                     if (current.isRollbackOnly()) {
@@ -299,7 +334,7 @@ public class RoutingSlip extends Service
                                     if (exceptionHandled) {
                                         sb.append(" Handled by the error handler.");
                                     }
-                                    LOG.debug(sb.toString());
+                                    log.debug(sb.toString());
                                 }
                                 break;
                             }
@@ -318,23 +353,23 @@ public class RoutingSlip extends Service
                             }
 
                             // prepare and process the routing slip
-                            Exchange copy = prepareExchangeForRoutingSlip(current);
+                            Exchange copy = prepareExchangeForRoutingSlip(current, endpoint);
                             boolean sync = processExchange(endpoint, copy, original, callback, iter);
                             current = copy;
 
                             if (!sync) {
-                                if (LOG.isTraceEnabled()) {
-                                    LOG.trace("Processing exchangeId: " + original.getExchangeId() + " is continued being processed asynchronously");
+                                if (log.isTraceEnabled()) {
+                                    log.trace("Processing exchangeId: " + original.getExchangeId() + " is continued being processed asynchronously");
                                 }
                                 return;
                             }
                         }
 
-                        if (LOG.isTraceEnabled()) {
+                        if (log.isTraceEnabled()) {
                             // logging nextExchange as it contains the exchange that might have altered the payload and since
                             // we are logging the completion if will be confusing if we log the original instead
                             // we could also consider logging the original and the nextExchange then we have *before* and *after* snapshots
-                            LOG.trace("Processing complete for exchangeId: " + original.getExchangeId() + " >>> " + current);
+                            log.trace("Processing complete for exchangeId: " + original.getExchangeId() + " >>> " + current);
                         }
 
                         // copy results back to the original exchange
@@ -367,19 +402,6 @@ public class RoutingSlip extends Service
         ServiceHelper.stopService(producerCache);
     }
 
-    private void updateRoutingSlipHeader(Exchange current) {
-        // only update the header value which used as the routing slip
-        if (header != null) {
-            Message message = getResultMessage(current);
-            String oldSlip = message.getHeader(header, String.class);
-            if (oldSlip != null) {
-                int delimiterIndex = oldSlip.indexOf(uriDelimiter);
-                String newSlip = delimiterIndex > 0 ? oldSlip.substring(delimiterIndex + 1) : "";
-                message.setHeader(header, newSlip);
-            }
-        }
-    }
-
     /**
      * Returns the outbound message if available. Otherwise return the inbound message.
      */

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/view/NodeData.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/view/NodeData.java?rev=990724&r1=990723&r2=990724&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/view/NodeData.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/view/NodeData.java Mon Aug 30 08:11:03 2010
@@ -106,7 +106,6 @@ public class NodeData {
             this.image = imagePrefix + "RoutingTableIcon.png";
             this.nodeType = "Routing Slip";
             this.url = "http://camel.apache.org/routing-slip.html";
-            this.tooltop = ((RoutingSlipDefinition) node).getHeaderName();
         } else if (node instanceof SplitDefinition) {
             this.image = imagePrefix + "SplitterIcon.png";
             this.nodeType = "Splitter";

Modified: camel/trunk/camel-core/src/main/resources/org/apache/camel/model/jaxb.index
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/resources/org/apache/camel/model/jaxb.index?rev=990724&r1=990723&r2=990724&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/resources/org/apache/camel/model/jaxb.index (original)
+++ camel/trunk/camel-core/src/main/resources/org/apache/camel/model/jaxb.index Mon Aug 30 08:11:03 2010
@@ -24,6 +24,7 @@ ContextScanDefinition
 DataFormatDefinition
 DelayDefinition
 DescriptionDefinition
+DynamicRouterDefinition
 EnrichDefinition
 ExpressionSubElementDefinition
 FilterDefinition

Added: camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouter2Test.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouter2Test.java?rev=990724&view=auto
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouter2Test.java (added)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouter2Test.java Mon Aug 30 08:11:03 2010
@@ -0,0 +1,75 @@
+/**
+ * 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.Exchange;
+import org.apache.camel.Header;
+import org.apache.camel.builder.RouteBuilder;
+
+/**
+ * @version $Revision$
+ */
+public class DynamicRouter2Test extends ContextTestSupport {
+
+    public void testDynamicRouter() throws Exception {
+        getMockEndpoint("mock:a").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:b").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:result").expectedBodiesReceived("Hello World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                // START SNIPPET: e1
+                from("direct:start")
+                    // use a bean as the dynamic router
+                    .dynamicRouter().method(DynamicRouter2Test.class, "slip");
+                // END SNIPPET: e1
+            }
+        };
+    }
+
+    // START SNIPPET: e2
+    /**
+     * Use this method to compute dynamic where we should route next.
+     *
+     * @param body the message body
+     * @param previous the previous slip
+     * @return endpoints to go, or <tt>null</tt> to indicate the end
+     */
+    public String slip(String body, @Header(Exchange.SLIP_ENDPOINT) String previous) {
+        if (previous == null) {
+            return "mock:a";
+        } else if ("mock://a".equals(previous)) {
+            return "mock:b";
+        } else if ("mock://b".equals(previous)) {
+            return "mock:result";
+        }
+
+        // no more so return null
+        return null;
+    }
+    // END SNIPPET: e2
+
+}

Added: camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouterAnnotationTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouterAnnotationTest.java?rev=990724&view=auto
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouterAnnotationTest.java (added)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouterAnnotationTest.java Mon Aug 30 08:11:03 2010
@@ -0,0 +1,92 @@
+/**
+ * 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.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+
+/**
+ * @version $Revision$
+ */
+public class DynamicRouterAnnotationTest extends ContextTestSupport {
+
+    private static int invoked;
+    private static List<String> bodies = new ArrayList<String>();
+
+    public void testDynamicRouterAnnotation() throws Exception {
+        getMockEndpoint("mock:a").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:b").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:c").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:foo").expectedBodiesReceived("Bye World");
+        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+
+        assertEquals(5, invoked);
+        assertEquals(5, bodies.size());
+        assertEquals("Hello World", bodies.get(0));
+        assertEquals("Hello World", bodies.get(1));
+        assertEquals("Hello World", bodies.get(2));
+        assertEquals("Bye World", bodies.get(3));
+        assertEquals("Bye World", bodies.get(4));
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                // START SNIPPET: e1
+                from("direct:start")
+                    .bean(MyBean.class, "dynamicRouter");
+
+                from("direct:foo").transform(constant("Bye World")).to("mock:foo");
+                // END SNIPPET: e1
+            }
+        };
+    }
+
+    // START SNIPPET: e2
+    public static class MyBean {
+
+        @org.apache.camel.DynamicRouter
+        public String dynamicRouter(String body) {
+            bodies.add(body);
+            invoked++;
+
+            if (invoked == 1) {
+                return "mock:a";
+            } else if (invoked == 2) {
+                return "mock:b,mock:c";
+            } else if (invoked == 3) {
+                return "direct:foo";
+            } else if (invoked == 4) {
+                return "mock:result";
+            }
+
+            // no more so return null
+            return null;
+        }
+    }
+    // END SNIPPET: e2
+
+}

Added: camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouterTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouterTest.java?rev=990724&view=auto
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouterTest.java (added)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/processor/DynamicRouterTest.java Mon Aug 30 08:11:03 2010
@@ -0,0 +1,95 @@
+/**
+ * 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.util.ArrayList;
+import java.util.List;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+
+/**
+ * @version $Revision$
+ */
+public class DynamicRouterTest extends ContextTestSupport {
+
+    private static int invoked;
+    private static List<String> bodies = new ArrayList<String>();
+
+    public void testDynamicRouter() throws Exception {
+        getMockEndpoint("mock:a").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:b").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:c").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:foo").expectedBodiesReceived("Bye World");
+        getMockEndpoint("mock:result").expectedBodiesReceived("Bye World");
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+
+        assertEquals(5, invoked);
+        assertEquals(5, bodies.size());
+        assertEquals("Hello World", bodies.get(0));
+        assertEquals("Hello World", bodies.get(1));
+        assertEquals("Hello World", bodies.get(2));
+        assertEquals("Bye World", bodies.get(3));
+        assertEquals("Bye World", bodies.get(4));
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                // START SNIPPET: e1
+                from("direct:start")
+                    // use a bean as the dynamic router
+                    .dynamicRouter(bean(DynamicRouterTest.class, "slip"));
+                // END SNIPPET: e1
+
+                from("direct:foo").transform(constant("Bye World")).to("mock:foo");
+            }
+        };
+    }
+
+    // START SNIPPET: e2
+    /**
+     * Use this method to compute dynamic where we should route next.
+     *
+     * @param body the message body
+     * @return endpoints to go, or <tt>null</tt> to indicate the end
+     */
+    public String slip(String body) {
+        bodies.add(body);
+        invoked++;
+
+        if (invoked == 1) {
+            return "mock:a";
+        } else if (invoked == 2) {
+            return "mock:b,mock:c";
+        } else if (invoked == 3) {
+            return "direct:foo";
+        } else if (invoked == 4) {
+            return "mock:result";
+        }
+
+        // no more so return null
+        return null;
+    }
+    // END SNIPPET: e2
+
+}

Modified: camel/trunk/camel-core/src/test/java/org/apache/camel/processor/routingslip/RoutingSlipPOJOTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/routingslip/RoutingSlipPOJOTest.java?rev=990724&r1=990723&r2=990724&view=diff
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/processor/routingslip/RoutingSlipPOJOTest.java (original)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/processor/routingslip/RoutingSlipPOJOTest.java Mon Aug 30 08:11:03 2010
@@ -40,15 +40,12 @@ public class RoutingSlipPOJOTest extends
     protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {
             public void configure() {
-                
                 from("direct:a").bean(new MyRoutingSlipPOJO());
                 
                 from("direct:b").process(new Processor() {
-
                     public void process(Exchange exchange) throws Exception {
                         exchange.getOut().setBody(exchange.getIn().getBody() + " is processed!");                        
                     }
-                    
                 });
             }
         };
@@ -60,7 +57,5 @@ public class RoutingSlipPOJOTest extends
             return new String[]{"mock:foo", "direct:b", "mock:result"};
         }
     }
-    
-    
 
 }

Copied: camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringDynamicRouterTest.java (from r990601, camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringRecipientListParallelTest.java)
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringDynamicRouterTest.java?p2=camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringDynamicRouterTest.java&p1=camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringRecipientListParallelTest.java&r1=990601&r2=990724&rev=990724&view=diff
==============================================================================
--- camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringRecipientListParallelTest.java (original)
+++ camel/trunk/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringDynamicRouterTest.java Mon Aug 30 08:11:03 2010
@@ -17,14 +17,14 @@
 package org.apache.camel.spring.processor;
 
 import org.apache.camel.CamelContext;
-import org.apache.camel.processor.RecipientListParallelTest;
+import org.apache.camel.processor.DynamicRouterTest;
 
 import static org.apache.camel.spring.processor.SpringTestHelper.createSpringCamelContext;
 
-public class SpringRecipientListParallelTest extends RecipientListParallelTest {
+public class SpringDynamicRouterTest extends DynamicRouterTest {
 
     protected CamelContext createCamelContext() throws Exception {
         return createSpringCamelContext(this,
-                "org/apache/camel/spring/processor/SpringRecipientListParallelTest.xml");
+                "org/apache/camel/spring/processor/SpringDynamicRouterTest.xml");
     }
 }
\ No newline at end of file

Copied: camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/SpringDynamicRouterTest.xml (from r990601, camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/SpringRecipientListParallelTest.xml)
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/SpringDynamicRouterTest.xml?p2=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/SpringDynamicRouterTest.xml&p1=camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/SpringRecipientListParallelTest.xml&r1=990601&r2=990724&rev=990724&view=diff
==============================================================================
--- camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/SpringRecipientListParallelTest.xml (original)
+++ camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/SpringDynamicRouterTest.xml Mon Aug 30 08:11:03 2010
@@ -22,35 +22,25 @@
        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
     ">
 
+    <!-- START SNIPPET: e1 -->
+    <bean id="mySlip" class="org.apache.camel.processor.DynamicRouterTest"/>
 
     <camelContext xmlns="http://camel.apache.org/schema/spring">
         <route>
             <from uri="direct:start"/>
-            <recipientList parallelProcessing="true">
-                <header>foo</header>
-            </recipientList>
+            <dynamicRouter>
+                <!-- use a method call on a bean as dynamic router -->
+                <method ref="mySlip" method="slip"/>
+            </dynamicRouter>
         </route>
 
         <route>
-            <from uri="direct:a"/>
-            <delay><constant>1000</constant></delay>
-            <transform><constant>a</constant></transform>
-            <to uri="mock:result"/>
-        </route>
-
-        <route>
-            <from uri="direct:b"/>
-            <delay><constant>500</constant></delay>
-            <transform><constant>b</constant></transform>
-            <to uri="mock:result"/>
-        </route>
-
-        <route>
-            <from uri="direct:c"/>
-            <transform><constant>c</constant></transform>
-            <to uri="mock:result"/>
+            <from uri="direct:foo"/>
+            <transform><constant>Bye World</constant></transform>
+            <to uri="mock:foo"/>
         </route>
 
     </camelContext>
+    <!-- END SNIPPET: e1 -->
 
 </beans>



Mime
View raw message