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