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