001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.model;
018    
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.Collections;
022    import java.util.LinkedList;
023    import java.util.List;
024    import java.util.concurrent.ThreadPoolExecutor;
025    
026    import javax.xml.bind.annotation.XmlAttribute;
027    import javax.xml.bind.annotation.XmlTransient;
028    
029    import org.apache.camel.CamelException;
030    import org.apache.camel.Endpoint;
031    import org.apache.camel.Exchange;
032    import org.apache.camel.Expression;
033    import org.apache.camel.Predicate;
034    import org.apache.camel.Processor;
035    import org.apache.camel.Route;
036    import org.apache.camel.RuntimeCamelException;
037    import org.apache.camel.Message;
038    import org.apache.camel.builder.Builder;
039    import org.apache.camel.builder.DataFormatClause;
040    import org.apache.camel.builder.DeadLetterChannelBuilder;
041    import org.apache.camel.builder.ErrorHandlerBuilder;
042    import org.apache.camel.builder.ExpressionClause;
043    import org.apache.camel.builder.NoErrorHandlerBuilder;
044    import org.apache.camel.builder.ProcessorBuilder;
045    import org.apache.camel.converter.ObjectConverter;
046    import org.apache.camel.impl.RouteContext;
047    import org.apache.camel.model.dataformat.DataFormatType;
048    import org.apache.camel.model.language.ExpressionType;
049    import org.apache.camel.model.language.LanguageExpression;
050    import org.apache.camel.processor.DelegateProcessor;
051    import org.apache.camel.processor.MulticastProcessor;
052    import org.apache.camel.processor.Pipeline;
053    import org.apache.camel.processor.RecipientList;
054    import org.apache.camel.processor.ConvertBodyProcessor;
055    import org.apache.camel.processor.aggregate.AggregationCollection;
056    import org.apache.camel.processor.aggregate.AggregationStrategy;
057    import org.apache.camel.processor.idempotent.IdempotentConsumer;
058    import org.apache.camel.processor.idempotent.MessageIdRepository;
059    import org.apache.camel.spi.DataFormat;
060    import org.apache.camel.spi.Policy;
061    import org.apache.camel.spi.Registry;
062    import org.apache.commons.logging.Log;
063    import org.apache.commons.logging.LogFactory;
064    
065    /**
066     * @version $Revision: 644383 $
067     */
068    public abstract class ProcessorType<Type extends ProcessorType> implements Block {
069        public static final String DEFAULT_TRACE_CATEGORY = "org.apache.camel.TRACE";
070        private ErrorHandlerBuilder errorHandlerBuilder;
071        private Boolean inheritErrorHandlerFlag = Boolean.TRUE; // TODO not sure how
072        private DelegateProcessor lastInterceptor;
073        private NodeFactory nodeFactory;
074        private LinkedList<Block> blocks = new LinkedList<Block>();
075        private ProcessorType<? extends ProcessorType> parent;
076    
077        // else to use an
078        // optional
079        // attribute in
080        // JAXB2
081    
082        public abstract List<ProcessorType<?>> getOutputs();
083    
084    
085        public Processor createProcessor(RouteContext routeContext) throws Exception {
086            throw new UnsupportedOperationException("Not implemented yet for class: " + getClass().getName());
087        }
088    
089        public Processor createOutputsProcessor(RouteContext routeContext) throws Exception {
090            Collection<ProcessorType<?>> outputs = getOutputs();
091            return createOutputsProcessor(routeContext, outputs);
092        }
093    
094        public void addRoutes(RouteContext routeContext, Collection<Route> routes) throws Exception {
095            Processor processor = makeProcessor(routeContext);
096            routeContext.addEventDrivenProcessor(processor);
097        }
098    
099        /**
100         * Wraps the child processor in whatever necessary interceptors and error
101         * handlers
102         */
103        public Processor wrapProcessor(RouteContext routeContext, Processor processor) throws Exception {
104            processor = wrapProcessorInInterceptors(routeContext, processor);
105            return wrapInErrorHandler(processor);
106        }
107    
108        // Fluent API
109        // -------------------------------------------------------------------------
110    
111        /**
112         * Sends the exchange to the given endpoint URI
113         */
114        public Type to(String uri) {
115            addOutput(new ToType(uri));
116            return (Type) this;
117        }
118    
119        /**
120         * Sends the exchange to the given endpoint
121         */
122        public Type to(Endpoint endpoint) {
123            addOutput(new ToType(endpoint));
124            return (Type) this;
125        }
126    
127        /**
128         * Sends the exchange to a list of endpoints using the
129         * {@link MulticastProcessor} pattern
130         */
131        public Type to(String... uris) {
132            for (String uri : uris) {
133                addOutput(new ToType(uri));
134            }
135            return (Type) this;
136        }
137    
138        /**
139         * Sends the exchange to a list of endpoints using the
140         * {@link MulticastProcessor} pattern
141         */
142        public Type to(Endpoint... endpoints) {
143            for (Endpoint endpoint : endpoints) {
144                addOutput(new ToType(endpoint));
145            }
146            return (Type) this;
147        }
148    
149        /**
150         * Sends the exchange to a list of endpoint using the
151         * {@link MulticastProcessor} pattern
152         */
153        public Type to(Collection<Endpoint> endpoints) {
154            for (Endpoint endpoint : endpoints) {
155                addOutput(new ToType(endpoint));
156            }
157            return (Type) this;
158        }
159    
160        /**
161         * Multicasts messages to all its child outputs; so that each processor and
162         * destination gets a copy of the original message to avoid the processors
163         * interfering with each other.
164         */
165        public MulticastType multicast() {
166            MulticastType answer = new MulticastType();
167            addOutput(answer);
168            return answer;
169        }
170    
171        /**
172         * Multicasts messages to all its child outputs; so that each processor and
173         * destination gets a copy of the original message to avoid the processors
174         * interfering with each other.
175         * @param aggregationStrategy the strategy used to aggregate responses for
176         *          every part
177         * @param parallelProcessing if is <tt>true</tt> camel will fork thread to call the endpoint producer
178         * @return the multicast type
179         */
180        public MulticastType multicast(AggregationStrategy aggregationStrategy, boolean parallelProcessing) {
181            MulticastType answer = new MulticastType();
182            addOutput(answer);
183            answer.setAggregationStrategy(aggregationStrategy);
184            answer.setParallelProcessing(parallelProcessing);
185            return answer;
186        }
187    
188        /**
189         * Multicasts messages to all its child outputs; so that each processor and
190         * destination gets a copy of the original message to avoid the processors
191         * interfering with each other.
192         * @param aggregationStrategy the strategy used to aggregate responses for
193         *          every part
194         * @return the multicast type
195         */
196        public MulticastType multicast(AggregationStrategy aggregationStrategy) {
197            MulticastType answer = new MulticastType();
198            addOutput(answer);
199            answer.setAggregationStrategy(aggregationStrategy);
200            return answer;
201        }
202    
203        /**
204         * Creates a {@link Pipeline} of the list of endpoints so that the message
205         * will get processed by each endpoint in turn and for request/response the
206         * output of one endpoint will be the input of the next endpoint
207         */
208        public Type pipeline(String... uris) {
209            // TODO pipeline v mulicast
210            return to(uris);
211        }
212    
213        /**
214         * Creates a {@link Pipeline} of the list of endpoints so that the message
215         * will get processed by each endpoint in turn and for request/response the
216         * output of one endpoint will be the input of the next endpoint
217         */
218        public Type pipeline(Endpoint... endpoints) {
219            // TODO pipeline v mulicast
220            return to(endpoints);
221        }
222    
223        /**
224         * Creates a {@link Pipeline} of the list of endpoints so that the message
225         * will get processed by each endpoint in turn and for request/response the
226         * output of one endpoint will be the input of the next endpoint
227         */
228        public Type pipeline(Collection<Endpoint> endpoints) {
229            // TODO pipeline v mulicast
230            return to(endpoints);
231        }
232    
233        /**
234         * Ends the current block
235         */
236        public ProcessorType<? extends ProcessorType> end() {
237            if (blocks.isEmpty()) {
238                if (parent == null) {
239                    throw new IllegalArgumentException("Root node with no active block");
240                }
241                return parent;
242            }
243            popBlock();
244            return this;
245        }
246    
247        /**
248         * Causes subsequent processors to be called asynchronously
249         *
250         * @param coreSize the number of threads that will be used to process
251         *                 messages in subsequent processors.
252         * @return a ThreadType builder that can be used to further configure the
253         *         the thread pool.
254         */
255        public ThreadType thread(int coreSize) {
256            ThreadType answer = new ThreadType(coreSize);
257            addOutput(answer);
258            return answer;
259        }
260    
261        /**
262         * Causes subsequent processors to be called asynchronously
263         *
264         * @param executor the executor that will be used to process
265         *                 messages in subsequent processors.
266         * @return a ThreadType builder that can be used to further configure the
267         *         the thread pool.
268         */
269        public ProcessorType<Type> thread(ThreadPoolExecutor executor) {
270            ThreadType answer = new ThreadType(executor);
271            addOutput(answer);
272            return this;
273        }
274    
275        /**
276         * Creates an {@link IdempotentConsumer} to avoid duplicate messages
277         */
278        public IdempotentConsumerType idempotentConsumer(Expression messageIdExpression,
279                MessageIdRepository messageIdRepository) {
280            IdempotentConsumerType answer = new IdempotentConsumerType(messageIdExpression, messageIdRepository);
281            addOutput(answer);
282            return answer;
283        }
284    
285        /**
286         * Creates an {@link IdempotentConsumer} to avoid duplicate messages
287         *
288         * @return the builder used to create the expression
289         */
290        public ExpressionClause<IdempotentConsumerType> idempotentConsumer(MessageIdRepository messageIdRepository) {
291            IdempotentConsumerType answer = new IdempotentConsumerType();
292            answer.setMessageIdRepository(messageIdRepository);
293            addOutput(answer);
294            return ExpressionClause.createAndSetExpression(answer);
295        }
296    
297        /**
298         * Creates a predicate expression which only if it is true then the
299         * exchange is forwarded to the destination
300         *
301         * @return the clause used to create the filter expression
302         */
303        public ExpressionClause<FilterType> filter() {
304            FilterType filter = new FilterType();
305            addOutput(filter);
306            return ExpressionClause.createAndSetExpression(filter);
307        }
308    
309        /**
310         * Creates a predicate which is applied and only if it is true then the
311         * exchange is forwarded to the destination
312         *
313         * @return the builder for a predicate
314         */
315        public FilterType filter(Predicate predicate) {
316            FilterType filter = new FilterType(predicate);
317            addOutput(filter);
318            return filter;
319        }
320    
321        public FilterType filter(ExpressionType expression) {
322            FilterType filter = getNodeFactory().createFilter();
323            filter.setExpression(expression);
324            addOutput(filter);
325            return filter;
326        }
327    
328        public FilterType filter(String language, String expression) {
329            return filter(new LanguageExpression(language, expression));
330        }
331    
332        public LoadBalanceType loadBalance() {
333            LoadBalanceType answer = new LoadBalanceType();
334            addOutput(answer);
335            return answer;
336        }
337    
338    
339        /**
340         * Creates a choice of one or more predicates with an otherwise clause
341         *
342         * @return the builder for a choice expression
343         */
344        public ChoiceType choice() {
345            ChoiceType answer = new ChoiceType();
346            addOutput(answer);
347            return answer;
348        }
349    
350        /**
351         * Creates a try/catch block
352         *
353         * @return the builder for a tryBlock expression
354         */
355        public TryType tryBlock() {
356            TryType answer = new TryType();
357            addOutput(answer);
358            return answer;
359        }
360    
361        /**
362         * Creates a dynamic <a
363         * href="http://activemq.apache.org/camel/recipient-list.html">Recipient
364         * List</a> pattern.
365         *
366         * @param receipients is the builder of the expression used in the
367         *                    {@link RecipientList} to decide the destinations
368         */
369        public Type recipientList(Expression receipients) {
370            RecipientListType answer = new RecipientListType(receipients);
371            addOutput(answer);
372            return (Type) this;
373        }
374    
375        /**
376         * Creates a dynamic <a
377         * href="http://activemq.apache.org/camel/recipient-list.html">Recipient
378         * List</a> pattern.
379         *
380         * @return the expression clause for the expression used in the
381         *                    {@link RecipientList} to decide the destinations
382         */
383        public ExpressionClause<ProcessorType<Type>> recipientList() {
384            RecipientListType answer = new RecipientListType();
385            addOutput(answer);
386            ExpressionClause<ProcessorType<Type>> clause = new ExpressionClause<ProcessorType<Type>>((Type) this);
387            answer.setExpression(clause);
388            return clause;
389        }
390    
391        /**
392         * Creates a <a
393         * href="http://activemq.apache.org/camel/routing-slip.html">Routing
394         * Slip</a> pattern.
395         *
396         * @param header is the header that the {@link org.apache.camel.processor.RoutingSlip RoutingSlip}
397         * class will look in for the list of URIs to route the message to.
398         * @param uriDelimiter is the delimiter that will be used to split up
399         * the list of URIs in the routing slip.
400         */
401        public Type routingSlip(String header, String uriDelimiter) {
402            RoutingSlipType answer = new RoutingSlipType(header, uriDelimiter);
403            addOutput(answer);
404            return (Type) this;
405        }      
406        
407        /**
408         * Creates a <a
409         * href="http://activemq.apache.org/camel/routing-slip.html">Routing
410         * Slip</a> pattern.
411         *
412         * @param header is the header that the {@link org.apache.camel.processor.RoutingSlip RoutingSlip}
413         * class will look in for the list of URIs to route the message to. The list of URIs
414         * will be split based on the default delimiter 
415         * {@link RoutingSlipType#DEFAULT_DELIMITER}.
416         */
417        public Type routingSlip(String header) {
418            RoutingSlipType answer = new RoutingSlipType(header);
419            addOutput(answer);
420            return (Type) this;
421        }    
422    
423        /**
424         * Creates a <a
425         * href="http://activemq.apache.org/camel/routing-slip.html">Routing
426         * Slip</a> pattern with the default header {@link RoutingSlipType#ROUTING_SLIP_HEADER}.
427         * The list of URIs in the header will be split based on the default delimiter 
428         * {@link RoutingSlipType#DEFAULT_DELIMITER}.
429         */
430        public Type routingSlip() {
431            RoutingSlipType answer = new RoutingSlipType();
432            addOutput(answer);
433            return (Type) this;
434        }     
435    
436        /**
437         * Creates the <a
438         * href="http://activemq.apache.org/camel/splitter.html">Splitter</a>
439         * pattern where an expression is evaluated to iterate through each of the
440         * parts of a message and then each part is then send to some endpoint.
441         * This splitter responds with the latest message returned from destination
442         * endpoint.
443         *
444         * @param receipients the expression on which to split
445         * @return the builder
446         */
447        public SplitterType splitter(Expression receipients) {
448            SplitterType answer = new SplitterType(receipients);
449            addOutput(answer);
450            return answer;
451        }
452    
453        /**
454         * Creates the <a
455         * href="http://activemq.apache.org/camel/splitter.html">Splitter</a>
456         * pattern where an expression is evaluated to iterate through each of the
457         * parts of a message and then each part is then send to some endpoint.
458         * This splitter responds with the latest message returned from destination
459         * endpoint.
460         *
461         * @return the expression clause for the expression on which to split
462         */
463        public ExpressionClause<SplitterType> splitter() {
464            SplitterType answer = new SplitterType();
465            addOutput(answer);
466            return ExpressionClause.createAndSetExpression(answer);
467        }
468    
469        /**
470         * Creates the <a
471         * href="http://activemq.apache.org/camel/splitter.html">Splitter</a>
472         * pattern where an expression is evaluated to iterate through each of the
473         * parts of a message and then each part is then send to some endpoint.
474         * Answer from the splitter is produced using given {@link AggregationStrategy}
475         * @param partsExpression the expression on which to split
476         * @param aggregationStrategy the strategy used to aggregate responses for
477         *          every part
478         * @return the builder
479         */
480        public SplitterType splitter(Expression partsExpression, AggregationStrategy aggregationStrategy) {
481            SplitterType answer = new SplitterType(partsExpression);
482            addOutput(answer);
483            answer.setAggregationStrategy(aggregationStrategy);
484            return answer;
485        }
486    
487        /**
488         * Creates the <a
489         * href="http://activemq.apache.org/camel/splitter.html">Splitter</a>
490         * pattern where an expression is evaluated to iterate through each of the
491         * parts of a message and then each part is then send to some endpoint.
492         * Answer from the splitter is produced using given {@link AggregationStrategy}
493         * @param aggregationStrategy the strategy used to aggregate responses for
494         *          every part
495         * @return the expression clause for the expression on which to split
496         */
497        public ExpressionClause<SplitterType> splitter(AggregationStrategy aggregationStrategy) {
498            SplitterType answer = new SplitterType();
499            addOutput(answer);
500            answer.setAggregationStrategy(aggregationStrategy);
501            return ExpressionClause.createAndSetExpression(answer);
502        }
503    
504        /**
505         * Creates the <a
506         * href="http://activemq.apache.org/camel/splitter.html">Splitter</a>
507         * pattern where an expression is evaluated to iterate through each of the
508         * parts of a message and then each part is then send to some endpoint.
509         * This splitter responds with the latest message returned from destination
510         * endpoint.
511         *
512         * @param receipients the expression on which to split
513         * @param parallelProcessing if is <tt>true</tt> camel will fork thread to call the endpoint producer
514         * @return the builder
515         */
516        public SplitterType splitter(Expression receipients, boolean parallelProcessing) {
517            SplitterType answer = new SplitterType(receipients);
518            addOutput(answer);
519            answer.setParallelProcessing(parallelProcessing);
520            return answer;
521        }
522    
523        /**
524         * Creates the <a
525         * href="http://activemq.apache.org/camel/splitter.html">Splitter</a>
526         * pattern where an expression is evaluated to iterate through each of the
527         * parts of a message and then each part is then send to some endpoint.
528         * This splitter responds with the latest message returned from destination
529         * endpoint.
530         *
531         * @param parallelProcessing if is <tt>true</tt> camel will fork thread to call the endpoint producer
532         * @return the expression clause for the expression on which to split
533         */
534        public ExpressionClause<SplitterType> splitter(boolean parallelProcessing) {
535            SplitterType answer = new SplitterType();
536            addOutput(answer);
537            answer.setParallelProcessing(parallelProcessing);
538            return ExpressionClause.createAndSetExpression(answer);
539        }
540    
541        /**
542         * Creates the <a
543         * href="http://activemq.apache.org/camel/splitter.html">Splitter</a>
544         * pattern where an expression is evaluated to iterate through each of the
545         * parts of a message and then each part is then send to some endpoint.
546         * Answer from the splitter is produced using given {@link AggregationStrategy}
547         * @param partsExpression the expression on which to split
548         * @param aggregationStrategy the strategy used to aggregate responses for
549         *          every part
550         * @param parallelProcessing if is <tt>true</tt> camel will fork thread to call the endpoint producer
551         * @return the builder
552         */
553        public SplitterType splitter(Expression partsExpression,
554                AggregationStrategy aggregationStrategy, boolean parallelProcessing) {
555            SplitterType answer = new SplitterType(partsExpression);
556            addOutput(answer);
557            answer.setAggregationStrategy(aggregationStrategy);
558            answer.setParallelProcessing(parallelProcessing);
559            return answer;
560        }
561    
562        /**
563         * Creates the <a
564         * href="http://activemq.apache.org/camel/splitter.html">Splitter</a>
565         * pattern where an expression is evaluated to iterate through each of the
566         * parts of a message and then each part is then send to some endpoint.
567         * Answer from the splitter is produced using given {@link AggregationStrategy}
568         * @param aggregationStrategy the strategy used to aggregate responses for
569         *          every part
570         * @param parallelProcessing if is <tt>true</tt> camel will fork thread to call the endpoint producer
571         * @return the expression clause for the expression on which to split
572         */
573        public ExpressionClause<SplitterType> splitter(AggregationStrategy aggregationStrategy, boolean parallelProcessing) {
574            SplitterType answer = new SplitterType();
575            addOutput(answer);
576            answer.setAggregationStrategy(aggregationStrategy);
577            answer.setParallelProcessing(parallelProcessing);
578            return ExpressionClause.createAndSetExpression(answer);
579        }
580    
581        
582        /**
583         * Creates the <a
584         * href="http://activemq.apache.org/camel/resequencer.html">Resequencer</a>
585         * pattern where a list of expressions are evaluated to be able to compare
586         * the message exchanges to reorder them. e.g. you may wish to sort by some
587         * headers
588         *
589         * @return the expression clause for the expressions on which to compare messages in order
590         */
591        public ExpressionClause<ResequencerType> resequencer() {
592            ResequencerType answer = new ResequencerType();
593            addOutput(answer);
594            ExpressionClause<ResequencerType> clause = new ExpressionClause<ResequencerType>(answer);
595            answer.expression(clause);
596            return clause;
597        }
598    
599        /**
600         * Creates the <a
601         * href="http://activemq.apache.org/camel/resequencer.html">Resequencer</a>
602         * pattern where an expression is evaluated to be able to compare the
603         * message exchanges to reorder them. e.g. you may wish to sort by some
604         * header
605         *
606         * @param expression the expression on which to compare messages in order
607         * @return the builder
608         */
609        public ResequencerType resequencer(Expression<Exchange> expression) {
610            return resequencer(Collections.<Expression>singletonList(expression));
611        }
612    
613        /**
614         * Creates the <a
615         * href="http://activemq.apache.org/camel/resequencer.html">Resequencer</a>
616         * pattern where a list of expressions are evaluated to be able to compare
617         * the message exchanges to reorder them. e.g. you may wish to sort by some
618         * headers
619         *
620         * @param expressions the expressions on which to compare messages in order
621         * @return the builder
622         */
623        public ResequencerType resequencer(List<Expression> expressions) {
624            ResequencerType answer = new ResequencerType(expressions);
625            addOutput(answer);
626            return answer;
627        }
628    
629        /**
630         * Creates the <a
631         * href="http://activemq.apache.org/camel/resequencer.html">Resequencer</a>
632         * pattern where a list of expressions are evaluated to be able to compare
633         * the message exchanges to reorder them. e.g. you may wish to sort by some
634         * headers
635         *
636         * @param expressions the expressions on which to compare messages in order
637         * @return the builder
638         */
639        public ResequencerType resequencer(Expression... expressions) {
640            List<Expression> list = new ArrayList<Expression>();
641            for (Expression expression : expressions) {
642                list.add(expression);
643            }
644            return resequencer(list);
645        }
646    
647        /**
648         * Creates an <a
649         * href="http://activemq.apache.org/camel/aggregator.html">Aggregator</a>
650         * pattern where a batch of messages are processed (up to a maximum amount
651         * or until some timeout is reached) and messages for the same correlation
652         * key are combined together using some kind of {@link AggregationStrategy}
653         * (by default the latest message is used) to compress many message exchanges
654         * into a smaller number of exchanges.
655         * <p/>
656         * A good example of this is stock market data; you may be receiving 30,000
657         * messages/second and you may want to throttle it right down so that multiple
658         * messages for the same stock are combined (or just the latest message is used
659         * and older prices are discarded). Another idea is to combine line item messages
660         * together into a single invoice message.
661         */
662        public ExpressionClause<AggregatorType> aggregator() {
663            AggregatorType answer = new AggregatorType();
664            addOutput(answer);
665            return ExpressionClause.createAndSetExpression(answer);
666        }
667    
668        /**
669         * Creates an <a
670         * href="http://activemq.apache.org/camel/aggregator.html">Aggregator</a>
671         * pattern where a batch of messages are processed (up to a maximum amount
672         * or until some timeout is reached) and messages for the same correlation
673         * key are combined together using some kind of {@link AggregationStrategy}
674         * (by default the latest message is used) to compress many message exchanges
675         * into a smaller number of exchanges.
676         * <p/>
677         * A good example of this is stock market data; you may be receiving 30,000
678         * messages/second and you may want to throttle it right down so that multiple
679         * messages for the same stock are combined (or just the latest message is used
680         * and older prices are discarded). Another idea is to combine line item messages
681         * together into a single invoice message.
682         *
683         * @param aggregationStrategy the strategy used for the aggregation
684         */
685        public ExpressionClause<AggregatorType> aggregator(AggregationStrategy aggregationStrategy) {
686            AggregatorType answer = new AggregatorType();
687            answer.setAggregationStrategy(aggregationStrategy);
688            addOutput(answer);
689            return ExpressionClause.createAndSetExpression(answer);
690        }
691    
692        /**
693         * Creates an <a
694         * href="http://activemq.apache.org/camel/aggregator.html">Aggregator</a>
695         * pattern using a custom aggregation collection implementation.
696         *
697         * @param aggregationCollection the collection used to perform the aggregation
698         */
699        public ExpressionClause<AggregatorType> aggregator(AggregationCollection aggregationCollection) {
700            AggregatorType answer = new AggregatorType();
701            answer.setAggregationCollection(aggregationCollection);
702            addOutput(answer);
703            return ExpressionClause.createAndSetExpression(answer);
704        }
705    
706        /**
707         * Creates an <a
708         * href="http://activemq.apache.org/camel/aggregator.html">Aggregator</a>
709         * pattern where a batch of messages are processed (up to a maximum amount
710         * or until some timeout is reached) and messages for the same correlation
711         * key are combined together using some kind of {@link AggregationStrategy}
712         * (by default the latest message is used) to compress many message exchanges
713         * into a smaller number of exchanges.
714         * <p/>
715         * A good example of this is stock market data; you may be receiving 30,000
716         * messages/second and you may want to throttle it right down so that multiple
717         * messages for the same stock are combined (or just the latest message is used
718         * and older prices are discarded). Another idea is to combine line item messages
719         * together into a single invoice message.
720         *
721         * @param correlationExpression the expression used to calculate the
722         *                              correlation key. For a JMS message this could be the
723         *                              expression <code>header("JMSDestination")</code> or
724         *                              <code>header("JMSCorrelationID")</code>
725         */
726        public AggregatorType aggregator(Expression correlationExpression) {
727            AggregatorType answer = new AggregatorType(correlationExpression);
728            addOutput(answer);
729            return answer;
730        }
731    
732        /**
733         * Creates an <a
734         * href="http://activemq.apache.org/camel/aggregator.html">Aggregator</a>
735         * pattern where a batch of messages are processed (up to a maximum amount
736         * or until some timeout is reached) and messages for the same correlation
737         * key are combined together using some kind of {@link AggregationStrategy}
738         * (by default the latest message is used) to compress many message exchanges
739         * into a smaller number of exchanges.
740         * <p/>
741         * A good example of this is stock market data; you may be receiving 30,000
742         * messages/second and you may want to throttle it right down so that multiple
743         * messages for the same stock are combined (or just the latest message is used
744         * and older prices are discarded). Another idea is to combine line item messages
745         * together into a single invoice message.
746         *
747         * @param correlationExpression the expression used to calculate the
748         *                              correlation key. For a JMS message this could be the
749         *                              expression <code>header("JMSDestination")</code> or
750         *                              <code>header("JMSCorrelationID")</code>
751         */
752        public AggregatorType aggregator(Expression correlationExpression, AggregationStrategy aggregationStrategy) {
753            AggregatorType answer = new AggregatorType(correlationExpression, aggregationStrategy);
754            addOutput(answer);
755            return answer;
756        }
757    
758        /**
759         * Creates the <a
760         * href="http://activemq.apache.org/camel/delayer.html">Delayer</a> pattern
761         * where an expression is used to calculate the time which the message will
762         * be dispatched on
763         *
764         * @param processAtExpression an expression to calculate the time at which
765         *                            the messages should be processed
766         * @return the builder
767         */
768        public DelayerType delayer(Expression<Exchange> processAtExpression) {
769            return delayer(processAtExpression, 0L);
770        }
771    
772        /**
773         * Creates the <a
774         * href="http://activemq.apache.org/camel/delayer.html">Delayer</a> pattern
775         * where an expression is used to calculate the time which the message will
776         * be dispatched on
777         *
778         * @param processAtExpression an expression to calculate the time at which
779         *                            the messages should be processed
780         * @param delay               the delay in milliseconds which is added to the
781         *                            processAtExpression to determine the time the message
782         *                            should be processed
783         * @return the builder
784         */
785        public DelayerType delayer(Expression<Exchange> processAtExpression, long delay) {
786            DelayerType answer = new DelayerType(processAtExpression, delay);
787            addOutput(answer);
788            return answer;
789        }
790    
791        /**
792         * Creates the <a
793         * href="http://activemq.apache.org/camel/delayer.html">Delayer</a> pattern
794         * where an expression is used to calculate the time which the message will
795         * be dispatched on
796         * @return the expression clause to create the expression
797         */
798        public ExpressionClause<DelayerType> delayer() {
799            DelayerType answer = new DelayerType();
800            addOutput(answer);
801            return ExpressionClause.createAndSetExpression(answer);
802        }
803    
804        /**
805         * Creates the <a
806         * href="http://activemq.apache.org/camel/delayer.html">Delayer</a> pattern
807         * where a fixed amount of milliseconds are used to delay processing of a
808         * message exchange
809         *
810         * @param delay the default delay in milliseconds
811         * @return the builder
812         */
813        public DelayerType delayer(long delay) {
814            return delayer(null, delay);
815        }
816    
817        /**
818         * Creates the <a
819         * href="http://activemq.apache.org/camel/delayer.html">Delayer</a> pattern
820         * where an expression is used to calculate the time which the message will
821         * be dispatched on
822         *
823         * @return the builder
824         */
825        public ThrottlerType throttler(long maximumRequestCount) {
826            ThrottlerType answer = new ThrottlerType(maximumRequestCount);
827            addOutput(answer);
828            return answer;
829        }
830    
831    
832        public Type throwFault(Throwable fault) {
833            ThrowFaultType answer = new ThrowFaultType();
834            answer.setFault(fault);
835            addOutput(answer);
836            return (Type) this;
837        }
838    
839        public Type throwFault(String message) {
840            return throwFault(new CamelException(message));
841        }
842    
843        public Type interceptor(String ref) {
844            InterceptorRef interceptor = new InterceptorRef(ref);
845            addInterceptor(interceptor);
846            return (Type) this;
847        }
848    
849    
850        public Type intercept(DelegateProcessor interceptor) {
851            addInterceptor(new InterceptorRef(interceptor));
852            lastInterceptor = interceptor;
853            return (Type) this;
854        }
855    
856        public InterceptType intercept() {
857            InterceptType answer = new InterceptType();
858            addOutput(answer);
859            return answer;
860        }
861    
862        public void addInterceptor(InterceptorType interceptor) {
863            addOutput(interceptor);
864            pushBlock(interceptor);
865        }
866    
867        protected void pushBlock(Block block) {
868            blocks.add(block);
869        }
870    
871        protected Block popBlock() {
872            return blocks.isEmpty() ? null : blocks.removeLast();
873        }
874    
875        public Type proceed() {
876            ProceedType proceed = null;
877            for (ProcessorType node = parent; node != null; node = node.getParent()) {
878                if (node instanceof InterceptType) {
879                    InterceptType intercept = (InterceptType) node;
880                    proceed = intercept.getProceed();
881                    break;
882                }
883            }
884            if (proceed == null) {
885                throw new IllegalArgumentException("Cannot use proceed() without being within an intercept() block");
886            }
887    
888            // TODO we should be looking up the stack to find the last InterceptType
889            // and returning its ProceedType!
890            addOutput(proceed);
891            return (Type) this;
892        }
893    
894        public ExceptionType exception(Class exceptionType) {
895            ExceptionType answer = new ExceptionType(exceptionType);
896            addOutput(answer);
897            return answer;
898        }
899    
900        /**
901         * Apply an interceptor route if the predicate is true
902         */
903        public ChoiceType intercept(Predicate predicate) {
904            InterceptType answer = new InterceptType();
905            addOutput(answer);
906            return answer.when(predicate);
907        }
908    
909        public Type interceptors(String... refs) {
910            for (String ref : refs) {
911                interceptor(ref);
912            }
913            return (Type) this;
914        }
915    
916        /**
917         * Trace logs the exchange before it goes to the next processing step using
918         * the {@link #DEFAULT_TRACE_CATEGORY} logging category.
919         */
920        public Type trace() {
921            return trace(DEFAULT_TRACE_CATEGORY);
922        }
923    
924        /**
925         * Trace logs the exchange before it goes to the next processing step using
926         * the specified logging category.
927         *
928         * @param category the logging category trace messages will sent to.
929         */
930        public Type trace(String category) {
931            final Log log = LogFactory.getLog(category);
932            return intercept(new DelegateProcessor() {
933                @Override
934                public void process(Exchange exchange) throws Exception {
935                    log.trace(exchange);
936                    processNext(exchange);
937                }
938            });
939        }
940    
941        public PolicyRef policies() {
942            PolicyRef answer = new PolicyRef();
943            addOutput(answer);
944            return answer;
945        }
946    
947        public PolicyRef policy(Policy policy) {
948            PolicyRef answer = new PolicyRef(policy);
949            addOutput(answer);
950            return answer;
951        }
952    
953    
954        /**
955         * Installs the given error handler builder
956         *
957         * @param errorHandlerBuilder the error handler to be used by default for
958         *                            all child routes
959         * @return the current builder with the error handler configured
960         */
961        public Type errorHandler(ErrorHandlerBuilder errorHandlerBuilder) {
962            setErrorHandlerBuilder(errorHandlerBuilder);
963            return (Type) this;
964        }
965    
966        /**
967         * Configures whether or not the error handler is inherited by every
968         * processing node (or just the top most one)
969         *
970         * @param condition the flag as to whether error handlers should be
971         *                  inherited or not
972         * @return the current builder
973         */
974        public Type inheritErrorHandler(boolean condition) {
975            setInheritErrorHandlerFlag(condition);
976            return (Type) this;
977        }
978    
979        // Transformers
980        // -------------------------------------------------------------------------
981    
982        /**
983         * Adds the custom processor to this destination which could be a final
984         * destination, or could be a transformation in a pipeline
985         */
986        public Type process(Processor processor) {
987            ProcessorRef answer = new ProcessorRef(processor);
988            addOutput(answer);
989            return (Type) this;
990        }
991    
992        /**
993         * Adds the custom processor reference to this destination which could be a final
994         * destination, or could be a transformation in a pipeline
995         */
996        public Type processRef(String ref) {
997            ProcessorRef answer = new ProcessorRef();
998            answer.setRef(ref);
999            addOutput(answer);
1000            return (Type) this;
1001        }
1002    
1003        /**
1004         * Adds a bean which is invoked which could be a final destination, or could
1005         * be a transformation in a pipeline
1006         */
1007        public Type bean(Object bean) {
1008            BeanRef answer = new BeanRef();
1009            answer.setBean(bean);
1010            addOutput(answer);
1011            return (Type) this;
1012        }
1013    
1014        /**
1015         * Adds a bean and method which is invoked which could be a final
1016         * destination, or could be a transformation in a pipeline
1017         */
1018        public Type bean(Object bean, String method) {
1019            BeanRef answer = new BeanRef();
1020            answer.setBean(bean);
1021            answer.setMethod(method);
1022            addOutput(answer);
1023            return (Type) this;
1024        }
1025    
1026        /**
1027         * Adds a bean by type which is invoked which could be a final destination, or could
1028         * be a transformation in a pipeline
1029         */
1030        public Type bean(Class beanType) {
1031            BeanRef answer = new BeanRef();
1032            answer.setBeanType(beanType);
1033            addOutput(answer);
1034            return (Type) this;
1035        }
1036    
1037        /**
1038         * Adds a bean type and method which is invoked which could be a final
1039         * destination, or could be a transformation in a pipeline
1040         */
1041        public Type bean(Class beanType, String method) {
1042            BeanRef answer = new BeanRef();
1043            answer.setBeanType(beanType);
1044            answer.setMethod(method);
1045            addOutput(answer);
1046            return (Type) this;
1047        }
1048    
1049        /**
1050         * Adds a bean which is invoked which could be a final destination, or could
1051         * be a transformation in a pipeline
1052         */
1053        public Type beanRef(String ref) {
1054            BeanRef answer = new BeanRef(ref);
1055            addOutput(answer);
1056            return (Type) this;
1057        }
1058    
1059        /**
1060         * Adds a bean and method which is invoked which could be a final
1061         * destination, or could be a transformation in a pipeline
1062         */
1063        public Type beanRef(String ref, String method) {
1064            BeanRef answer = new BeanRef(ref, method);
1065            addOutput(answer);
1066            return (Type) this;
1067        }
1068    
1069        /**
1070         * Adds a processor which sets the body on the IN message
1071         */
1072        public ExpressionClause<ProcessorType<Type>> setBody() {
1073            ExpressionClause<ProcessorType<Type>> clause = new ExpressionClause<ProcessorType<Type>>((Type) this);
1074            process(ProcessorBuilder.setBody(clause));
1075            return clause;
1076        }
1077    
1078        /**
1079         * Adds a processor which sets the body on the IN message
1080         */
1081        public Type setBody(Expression expression) {
1082            return process(ProcessorBuilder.setBody(expression));
1083        }
1084    
1085        /**
1086         * Adds a processor which sets the body on the OUT message
1087         */
1088        public Type setOutBody(Expression expression) {
1089            return process(ProcessorBuilder.setOutBody(expression));
1090        }
1091    
1092        /**
1093         * Adds a processor which sets the body on the OUT message
1094         */
1095        public ExpressionClause<ProcessorType<Type>> setOutBody() {
1096            ExpressionClause<ProcessorType<Type>> clause = new ExpressionClause<ProcessorType<Type>>((Type) this);
1097            process(ProcessorBuilder.setOutBody(clause));
1098            return clause;
1099        }
1100    
1101        /**
1102         * Adds a processor which sets the body on the FAULT message
1103         */
1104        public Type setFaultBody(Expression expression) {
1105            return process(ProcessorBuilder.setFaultBody(expression));
1106        }
1107    
1108        /**
1109         * Adds a processor which sets the header on the IN message
1110         */
1111        public ExpressionClause<ProcessorType<Type>> setHeader(String name) {
1112            ExpressionClause<ProcessorType<Type>> clause = new ExpressionClause<ProcessorType<Type>>((Type) this);
1113            process(ProcessorBuilder.setHeader(name, clause));
1114            return clause;
1115        }
1116    
1117        /**
1118         * Adds a processor which sets the header on the IN message
1119         */
1120        public Type setHeader(String name, Expression expression) {
1121            return process(ProcessorBuilder.setHeader(name, expression));
1122        }
1123    
1124        /**
1125         * Adds a processor which sets the header on the IN message to the given value
1126         */
1127        public Type setHeader(String name, String value) {
1128            return (Type) setHeader(name).constant(value);
1129        }
1130    
1131        /**
1132         * Adds a processor which sets the header on the OUT message
1133         */
1134        public ExpressionClause<ProcessorType<Type>> setOutHeader(String name) {
1135            ExpressionClause<ProcessorType<Type>> clause = new ExpressionClause<ProcessorType<Type>>((Type) this);
1136            process(ProcessorBuilder.setOutHeader(name, clause));
1137            return clause;
1138        }
1139    
1140        /**
1141         * Adds a processor which sets the header on the OUT message
1142         */
1143        public Type setOutHeader(String name, Expression expression) {
1144            return process(ProcessorBuilder.setOutHeader(name, expression));
1145        }
1146    
1147        /**
1148         * Adds a processor which sets the header on the OUT message
1149         */
1150        public Type setOutHeader(String name, String value) {
1151            return (Type) setOutHeader(name).constant(value);
1152        }
1153    
1154        /**
1155         * Adds a processor which sets the header on the FAULT message
1156         */
1157        public Type setFaultHeader(String name, Expression expression) {
1158            return process(ProcessorBuilder.setFaultHeader(name, expression));
1159        }
1160    
1161        /**
1162         * Adds a processor which sets the exchange property
1163         */
1164        public Type setProperty(String name, Expression expression) {
1165            return process(ProcessorBuilder.setProperty(name, expression));
1166        }
1167    
1168    
1169        /**
1170         * Adds a processor which sets the exchange property
1171         */
1172        public ExpressionClause<ProcessorType<Type>> setProperty(String name) {
1173            ExpressionClause<ProcessorType<Type>> clause = new ExpressionClause<ProcessorType<Type>>((Type) this);
1174            process(ProcessorBuilder.setProperty(name, clause));
1175            return clause;
1176        }
1177    
1178        /**
1179         * Adds a processor which removes the header on the IN message
1180         */
1181        public Type removeHeader(String name) {
1182            return process(ProcessorBuilder.removeHeader(name));
1183        }
1184    
1185        /**
1186         * Adds a processor which removes the header on the OUT message
1187         */
1188        public Type removeOutHeader(String name) {
1189            return process(ProcessorBuilder.removeOutHeader(name));
1190        }
1191    
1192        /**
1193         * Adds a processor which removes the header on the FAULT message
1194         */
1195        public Type removeFaultHeader(String name) {
1196            return process(ProcessorBuilder.removeFaultHeader(name));
1197        }
1198    
1199        /**
1200         * Adds a processor which removes the exchange property
1201         */
1202        public Type removeProperty(String name) {
1203            return process(ProcessorBuilder.removeProperty(name));
1204        }
1205    
1206        /**
1207         * Converts the IN message body to the specified type
1208         */
1209        public Type convertBodyTo(Class type) {
1210            return process(new ConvertBodyProcessor(type));
1211        }
1212    
1213        /**
1214         * Converts the OUT message body to the specified type
1215         *
1216         * @deprecated Please use {@link #convertBodyTo(Class)} instead
1217         */
1218        public Type convertOutBodyTo(Class type) {
1219            // TODO deprecate method?
1220            //return process(ProcessorBuilder.setOutBody(Builder.outBody().convertTo(type)));
1221            return process(new ConvertBodyProcessor(type));
1222        }
1223    
1224        /**
1225         * Converts the FAULT message body to the specified type
1226         */
1227        public Type convertFaultBodyTo(Class type) {
1228            // TODO deprecate method?
1229            //return process(ProcessorBuilder.setFaultBody(Builder.faultBody().convertTo(type)));
1230            return process(new ConvertBodyProcessor(type));
1231        }
1232    
1233        // DataFormat support
1234        // -------------------------------------------------------------------------
1235    
1236        /**
1237         * Unmarshals the in body using a {@link DataFormat} expression to define
1238         * the format of the input message and the output will be set on the out message body.
1239         *
1240         * @return the expression to create the {@link DataFormat}
1241         */
1242        public DataFormatClause<ProcessorType<Type>> unmarshal() {
1243            return new DataFormatClause<ProcessorType<Type>>(this, DataFormatClause.Operation.Unmarshal);
1244        }
1245    
1246        /**
1247         * Unmarshals the in body using the specified {@link DataFormat}
1248         * and sets the output on the out message body.
1249         *
1250         * @return this object
1251         */
1252        public Type unmarshal(DataFormatType dataFormatType) {
1253            addOutput(new UnmarshalType(dataFormatType));
1254            return (Type) this;
1255        }
1256    
1257        /**
1258         * Unmarshals the in body using the specified {@link DataFormat}
1259         * and sets the output on the out message body.
1260         *
1261         * @return this object
1262         */
1263        public Type unmarshal(DataFormat dataFormat) {
1264            return unmarshal(new DataFormatType(dataFormat));
1265        }
1266    
1267        /**
1268         * Unmarshals the in body using the specified {@link DataFormat}
1269         * reference in the {@link Registry} and sets the output on the out message body.
1270         *
1271         * @return this object
1272         */
1273        public Type unmarshal(String dataTypeRef) {
1274            addOutput(new UnmarshalType(dataTypeRef));
1275            return (Type) this;
1276        }
1277    
1278        /**
1279         * Marshals the in body using a {@link DataFormat} expression to define
1280         * the format of the output which will be added to the out body.
1281         *
1282         * @return the expression to create the {@link DataFormat}
1283         */
1284        public DataFormatClause<ProcessorType<Type>> marshal() {
1285            return new DataFormatClause<ProcessorType<Type>>(this, DataFormatClause.Operation.Marshal);
1286        }
1287    
1288        /**
1289         * Marshals the in body using the specified {@link DataFormat}
1290         * and sets the output on the out message body.
1291         *
1292         * @return this object
1293         */
1294        public Type marshal(DataFormatType dataFormatType) {
1295            addOutput(new MarshalType(dataFormatType));
1296            return (Type) this;
1297        }
1298    
1299        /**
1300         * Marshals the in body using the specified {@link DataFormat}
1301         * and sets the output on the out message body.
1302         *
1303         * @return this object
1304         */
1305        public Type marshal(DataFormat dataFormat) {
1306            return marshal(new DataFormatType(dataFormat));
1307        }
1308    
1309        /**
1310         * Marshals the in body the specified {@link DataFormat}
1311         * reference in the {@link Registry} and sets the output on the out message body.
1312         *
1313         * @return this object
1314         */
1315        public Type marshal(String dataTypeRef) {
1316            addOutput(new MarshalType(dataTypeRef));
1317            return (Type) this;
1318        }
1319    
1320        // Properties
1321        // -------------------------------------------------------------------------
1322        @XmlTransient
1323        public ProcessorType<? extends ProcessorType> getParent() {
1324            return parent;
1325        }
1326    
1327        public void setParent(ProcessorType<? extends ProcessorType> parent) {
1328            this.parent = parent;
1329        }
1330    
1331        @XmlTransient
1332        public ErrorHandlerBuilder getErrorHandlerBuilder() {
1333            if (errorHandlerBuilder == null) {
1334                errorHandlerBuilder = createErrorHandlerBuilder();
1335            }
1336            return errorHandlerBuilder;
1337        }
1338    
1339        /**
1340         * Sets the error handler to use with processors created by this builder
1341         */
1342        public void setErrorHandlerBuilder(ErrorHandlerBuilder errorHandlerBuilder) {
1343            this.errorHandlerBuilder = errorHandlerBuilder;
1344        }
1345    
1346        @XmlTransient
1347        public boolean isInheritErrorHandler() {
1348            return ObjectConverter.toBoolean(getInheritErrorHandlerFlag());
1349        }
1350    
1351        @XmlAttribute(name = "inheritErrorHandler", required = false)
1352        public Boolean getInheritErrorHandlerFlag() {
1353            return inheritErrorHandlerFlag;
1354        }
1355    
1356        public void setInheritErrorHandlerFlag(Boolean inheritErrorHandlerFlag) {
1357            this.inheritErrorHandlerFlag = inheritErrorHandlerFlag;
1358        }
1359    
1360        @XmlTransient
1361        public NodeFactory getNodeFactory() {
1362            if (nodeFactory == null) {
1363                nodeFactory = new NodeFactory();
1364            }
1365            return nodeFactory;
1366        }
1367    
1368        public void setNodeFactory(NodeFactory nodeFactory) {
1369            this.nodeFactory = nodeFactory;
1370        }
1371    
1372        /**
1373         * Returns a label to describe this node such as the expression if some kind of expression node
1374         */
1375        public String getLabel() {
1376            return "";
1377        }
1378    
1379        // Implementation methods
1380        // -------------------------------------------------------------------------
1381    
1382        /**
1383         * Creates the processor and wraps it in any necessary interceptors and
1384         * error handlers
1385         */
1386        protected Processor makeProcessor(RouteContext routeContext) throws Exception {
1387            Processor processor = createProcessor(routeContext);
1388            return wrapProcessor(routeContext, processor);
1389        }
1390    
1391        /**
1392         * A strategy method which allows derived classes to wrap the child
1393         * processor in some kind of interceptor
1394         *
1395         * @param routeContext
1396         * @param target       the processor which can be wrapped
1397         * @return the original processor or a new wrapped interceptor
1398         */
1399        protected Processor wrapProcessorInInterceptors(RouteContext routeContext, Processor target) throws Exception {
1400            // The target is required.
1401            if (target == null) {
1402                throw new RuntimeCamelException("target provided.");
1403            }
1404    
1405            // Interceptors are optional
1406            DelegateProcessor first = null;
1407            DelegateProcessor last = null;
1408    /*
1409    
1410            List<InterceptorType> interceptors = new ArrayList<InterceptorType>(routeContext.getRoute()
1411                    .getInterceptors());
1412            List<InterceptorType> list = getInterceptors();
1413            for (InterceptorType interceptorType : list) {
1414                if (!interceptors.contains(interceptorType)) {
1415                    interceptors.add(interceptorType);
1416                }
1417            }
1418            for (InterceptorType interceptorRef : interceptors) {
1419                DelegateProcessor p = interceptorRef.createInterceptor(routeContext);
1420                if (first == null) {
1421                    first = p;
1422                }
1423                if (last != null) {
1424                    last.setProcessor(p);
1425                }
1426                last = p;
1427            }
1428    
1429            if (last != null) {
1430                last.setProcessor(target);
1431            }
1432    */
1433            return first == null ? target : first;
1434        }
1435    
1436        /**
1437         * A strategy method to allow newly created processors to be wrapped in an
1438         * error handler.
1439         */
1440        protected Processor wrapInErrorHandler(Processor processor) throws Exception {
1441            return getErrorHandlerBuilder().createErrorHandler(processor);
1442        }
1443    
1444        protected ErrorHandlerBuilder createErrorHandlerBuilder() {
1445            if (isInheritErrorHandler()) {
1446                return new DeadLetterChannelBuilder();
1447            } else {
1448                return new NoErrorHandlerBuilder();
1449            }
1450        }
1451    
1452        protected void configureChild(ProcessorType output) {
1453            output.setNodeFactory(getNodeFactory());
1454        }
1455    
1456        public void addOutput(ProcessorType processorType) {
1457            processorType.setParent(this);
1458            configureChild(processorType);
1459            if (blocks.isEmpty()) {
1460                getOutputs().add(processorType);
1461            } else {
1462                Block block = blocks.getLast();
1463                block.addOutput(processorType);
1464            }
1465        }
1466    
1467        /**
1468         * Creates a new instance of some kind of composite processor which defaults
1469         * to using a {@link Pipeline} but derived classes could change the
1470         * behaviour
1471         */
1472        protected Processor createCompositeProcessor(List<Processor> list) {
1473            // return new MulticastProcessor(list);
1474            return new Pipeline(list);
1475        }
1476    
1477        protected Processor createOutputsProcessor(RouteContext routeContext, Collection<ProcessorType<?>> outputs)
1478            throws Exception {
1479            List<Processor> list = new ArrayList<Processor>();
1480            for (ProcessorType output : outputs) {
1481                Processor processor = output.createProcessor(routeContext);
1482                list.add(processor);
1483            }
1484            Processor processor = null;
1485            if (!list.isEmpty()) {
1486                if (list.size() == 1) {
1487                    processor = list.get(0);
1488                } else {
1489                    processor = createCompositeProcessor(list);
1490                }
1491            }
1492            return processor;
1493        }
1494    
1495        public void clearOutput() {
1496            getOutputs().clear();
1497            blocks.clear();
1498        }
1499    }