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.builder.DataFormatClause;
043 import org.apache.camel.builder.DeadLetterChannelBuilder;
044 import org.apache.camel.builder.ErrorHandlerBuilder;
045 import org.apache.camel.builder.ErrorHandlerBuilderRef;
046 import org.apache.camel.builder.ExpressionClause;
047 import org.apache.camel.builder.NoErrorHandlerBuilder;
048 import org.apache.camel.builder.ProcessorBuilder;
049 import org.apache.camel.impl.DefaultCamelContext;
050 import org.apache.camel.model.dataformat.DataFormatType;
051 import org.apache.camel.model.language.ConstantExpression;
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: 53082 $
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. The aggregation collection must
704 * be configued with the strategy and correlation expression that this aggregator should use.
705 * This avoids duplicating this configuration on both the collection and the aggregator itself.
706 *
707 * @param aggregationCollection the collection used to perform the aggregation
708 */
709 public AggregatorType aggregator(AggregationCollection aggregationCollection) {
710 AggregatorType answer = new AggregatorType();
711 answer.setAggregationCollection(aggregationCollection);
712 addOutput(answer);
713 return answer;
714 }
715
716 /**
717 * Creates an <a
718 * href="http://activemq.apache.org/camel/aggregator.html">Aggregator</a>
719 * pattern where a batch of messages are processed (up to a maximum amount
720 * or until some timeout is reached) and messages for the same correlation
721 * key are combined together using some kind of {@link AggregationStrategy}
722 * (by default the latest message is used) to compress many message exchanges
723 * into a smaller number of exchanges.
724 * <p/>
725 * A good example of this is stock market data; you may be receiving 30,000
726 * messages/second and you may want to throttle it right down so that multiple
727 * messages for the same stock are combined (or just the latest message is used
728 * and older prices are discarded). Another idea is to combine line item messages
729 * together into a single invoice message.
730 *
731 * @param correlationExpression the expression used to calculate the
732 * correlation key. For a JMS message this could be the
733 * expression <code>header("JMSDestination")</code> or
734 * <code>header("JMSCorrelationID")</code>
735 */
736 public AggregatorType aggregator(Expression correlationExpression) {
737 AggregatorType answer = new AggregatorType(correlationExpression);
738 addOutput(answer);
739 return answer;
740 }
741
742 /**
743 * Creates an <a
744 * href="http://activemq.apache.org/camel/aggregator.html">Aggregator</a>
745 * pattern where a batch of messages are processed (up to a maximum amount
746 * or until some timeout is reached) and messages for the same correlation
747 * key are combined together using some kind of {@link AggregationStrategy}
748 * (by default the latest message is used) to compress many message exchanges
749 * into a smaller number of exchanges.
750 * <p/>
751 * A good example of this is stock market data; you may be receiving 30,000
752 * messages/second and you may want to throttle it right down so that multiple
753 * messages for the same stock are combined (or just the latest message is used
754 * and older prices are discarded). Another idea is to combine line item messages
755 * together into a single invoice message.
756 *
757 * @param correlationExpression the expression used to calculate the
758 * correlation key. For a JMS message this could be the
759 * expression <code>header("JMSDestination")</code> or
760 * <code>header("JMSCorrelationID")</code>
761 */
762 public AggregatorType aggregator(Expression correlationExpression, AggregationStrategy aggregationStrategy) {
763 AggregatorType answer = new AggregatorType(correlationExpression, aggregationStrategy);
764 addOutput(answer);
765 return answer;
766 }
767
768 /**
769 * Creates the <a
770 * href="http://activemq.apache.org/camel/delayer.html">Delayer</a> pattern
771 * where an expression is used to calculate the time which the message will
772 * be dispatched on
773 *
774 * @param processAtExpression an expression to calculate the time at which
775 * the messages should be processed
776 * @return the builder
777 */
778 public DelayerType delayer(Expression<Exchange> processAtExpression) {
779 return delayer(processAtExpression, 0L);
780 }
781
782 /**
783 * Creates the <a
784 * href="http://activemq.apache.org/camel/delayer.html">Delayer</a> pattern
785 * where an expression is used to calculate the time which the message will
786 * be dispatched on
787 *
788 * @param processAtExpression an expression to calculate the time at which
789 * the messages should be processed
790 * @param delay the delay in milliseconds which is added to the
791 * processAtExpression to determine the time the message
792 * should be processed
793 * @return the builder
794 */
795 public DelayerType delayer(Expression<Exchange> processAtExpression, long delay) {
796 DelayerType answer = new DelayerType(processAtExpression, delay);
797 addOutput(answer);
798 return answer;
799 }
800
801 /**
802 * Creates the <a
803 * href="http://activemq.apache.org/camel/delayer.html">Delayer</a> pattern
804 * where an expression is used to calculate the time which the message will
805 * be dispatched on
806 * @return the expression clause to create the expression
807 */
808 public ExpressionClause<DelayerType> delayer() {
809 DelayerType answer = new DelayerType();
810 addOutput(answer);
811 return ExpressionClause.createAndSetExpression(answer);
812 }
813
814 /**
815 * Creates the <a
816 * href="http://activemq.apache.org/camel/delayer.html">Delayer</a> pattern
817 * where a fixed amount of milliseconds are used to delay processing of a
818 * message exchange
819 *
820 * @param delay the default delay in milliseconds
821 * @return the builder
822 */
823 public DelayerType delayer(long delay) {
824 return delayer(null, delay);
825 }
826
827 /**
828 * Creates the <a
829 * href="http://activemq.apache.org/camel/delayer.html">Delayer</a> pattern
830 * where an expression is used to calculate the time which the message will
831 * be dispatched on
832 *
833 * @return the builder
834 */
835 public ThrottlerType throttler(long maximumRequestCount) {
836 ThrottlerType answer = new ThrottlerType(maximumRequestCount);
837 addOutput(answer);
838 return answer;
839 }
840
841 /**
842 * Creates a expression which must evaluate to an integer that determines
843 * how many times the exchange should be sent down the rest of the route.
844 *
845 * @return the clause used to create the loop expression
846 */
847 public ExpressionClause<LoopType> loop() {
848 LoopType loop = new LoopType();
849 addOutput(loop);
850 return ExpressionClause.createAndSetExpression(loop);
851 }
852
853 public LoopType loop(Expression<?> expression) {
854 LoopType loop = getNodeFactory().createLoop();
855 loop.setExpression(expression);
856 addOutput(loop);
857 return loop;
858 }
859
860 public LoopType loop(int count) {
861 LoopType loop = getNodeFactory().createLoop();
862 loop.setExpression(new ConstantExpression(Integer.toString(count)));
863 addOutput(loop);
864 return loop;
865 }
866
867 public Type throwFault(Throwable fault) {
868 ThrowFaultType answer = new ThrowFaultType();
869 answer.setFault(fault);
870 addOutput(answer);
871 return (Type) this;
872 }
873
874 public Type throwFault(String message) {
875 return throwFault(new CamelException(message));
876 }
877
878 /**
879 * Intercepts outputs added to this node in the future (i.e. intercepts outputs added after this statement)
880 */
881 public Type interceptor(String ref) {
882 InterceptorRef interceptor = new InterceptorRef(ref);
883 intercept(interceptor);
884 return (Type) this;
885 }
886
887 /**
888 * Intercepts outputs added to this node in the future (i.e. intercepts outputs added after this statement)
889 */
890 public Type intercept(DelegateProcessor interceptor) {
891 intercept(new InterceptorRef(interceptor));
892 //lastInterceptor = interceptor;
893 return (Type) this;
894 }
895
896 /**
897 * Intercepts outputs added to this node in the future (i.e. intercepts outputs added after this statement)
898 */
899 public InterceptType intercept() {
900 InterceptType answer = new InterceptType();
901 addOutput(answer);
902 return answer;
903 }
904
905 /**
906 * Intercepts outputs added to this node in the future (i.e. intercepts outputs added after this statement)
907 */
908 public void intercept(InterceptorType interceptor) {
909 addOutput(interceptor);
910 pushBlock(interceptor);
911 }
912
913 /**
914 * Adds an interceptor around the whole of this nodes processing
915 *
916 * @param interceptor
917 */
918 public void addInterceptor(InterceptorType interceptor) {
919 interceptors.add(interceptor);
920 }
921
922 /**
923 * Adds an interceptor around the whole of this nodes processing
924 *
925 * @param interceptor
926 */
927 public void addInterceptor(DelegateProcessor interceptor) {
928 addInterceptor(new InterceptorRef(interceptor));
929 }
930
931 public void pushBlock(Block block) {
932 blocks.add(block);
933 }
934
935 public Block popBlock() {
936 return blocks.isEmpty() ? null : blocks.removeLast();
937 }
938
939 public Type proceed() {
940 ProceedType proceed = null;
941 ProcessorType currentProcessor = this;
942
943 if (currentProcessor instanceof InterceptType) {
944 proceed = ((InterceptType) currentProcessor).getProceed();
945 LOG.info("proceed() is the implied and hence not needed for an intercept()");
946 }
947 if (proceed == null) {
948 for (ProcessorType node = parent; node != null; node = node.getParent()) {
949 if (node instanceof InterceptType) {
950 InterceptType intercept = (InterceptType)node;
951 proceed = intercept.getProceed();
952 break;
953 }
954 }
955
956 if (proceed == null) {
957 throw new IllegalArgumentException("Cannot use proceed() without being within an intercept() block");
958 }
959
960 }
961
962 addOutput(proceed);
963 return (Type) this;
964 }
965
966 public Type stop() {
967 ProcessorType currentProcessor = this;
968
969 if (currentProcessor instanceof InterceptType) {
970 ((InterceptType) currentProcessor).stopIntercept();
971 } else {
972 ProcessorType node;
973 for (node = parent; node != null; node = node.getParent()) {
974 if (node instanceof InterceptType) {
975 ((InterceptType) node).stopIntercept();
976 break;
977 }
978 }
979 if (node == null) {
980 throw new IllegalArgumentException("Cannot use stop() without being within an intercept() block");
981 }
982 }
983
984 return (Type) this;
985 }
986
987 /**
988 * Catches an exception type.
989 *
990 * @deprecated Please use {@link #onException(Class)} instead. Will be removed in Camel 2.0.
991 */
992 public ExceptionType exception(Class exceptionType) {
993 return onException(exceptionType);
994 }
995
996 /**
997 * Catches an exception type.
998 */
999 public ExceptionType onException(Class exceptionType) {
1000 ExceptionType answer = new ExceptionType(exceptionType);
1001 addOutput(answer);
1002 return answer;
1003 }
1004
1005 /**
1006 * Apply an interceptor route if the predicate is true
1007 */
1008 public ChoiceType intercept(Predicate predicate) {
1009 InterceptType answer = new InterceptType();
1010 addOutput(answer);
1011 return answer.when(predicate);
1012 }
1013
1014 public Type interceptors(String... refs) {
1015 for (String ref : refs) {
1016 interceptor(ref);
1017 }
1018 return (Type) this;
1019 }
1020
1021 /**
1022 * Trace logs the exchange before it goes to the next processing step using
1023 * the {@link #DEFAULT_TRACE_CATEGORY} logging category.
1024 *
1025 * @deprecated Please use <a href="http://activemq.apache.org/camel/tracer.html>Tracer Support</a>
1026 * instead. Will be removed in Camel 2.0.
1027 */
1028 public Type trace() {
1029 return trace(DEFAULT_TRACE_CATEGORY);
1030 }
1031
1032 /**
1033 * Trace logs the exchange before it goes to the next processing step using
1034 * the specified logging category.
1035 *
1036 * @param category the logging category trace messages will sent to.
1037 *
1038 * @deprecated Please use <a href="http://activemq.apache.org/camel/tracer.html>Tracer Support</a>
1039 * instead. Will be removed in Camel 2.0.
1040 */
1041 public Type trace(String category) {
1042 final Log log = LogFactory.getLog(category);
1043 return intercept(new DelegateProcessor() {
1044 @Override
1045 public void process(Exchange exchange) throws Exception {
1046 log.trace(exchange);
1047 processNext(exchange);
1048 }
1049 });
1050 }
1051
1052 public PolicyRef policies() {
1053 PolicyRef answer = new PolicyRef();
1054 addOutput(answer);
1055 return answer;
1056 }
1057
1058 public PolicyRef policy(Policy policy) {
1059 PolicyRef answer = new PolicyRef(policy);
1060 addOutput(answer);
1061 return answer;
1062 }
1063
1064 /**
1065 * Forces handling of faults as exceptions
1066 *
1067 * @return the current builder with the fault handler configured
1068 */
1069 public Type handleFault() {
1070 intercept(new HandleFaultType());
1071 return (Type) this;
1072 }
1073
1074 /**
1075 * Installs the given error handler builder
1076 *
1077 * @param errorHandlerBuilder the error handler to be used by default for
1078 * all child routes
1079 * @return the current builder with the error handler configured
1080 */
1081 public Type errorHandler(ErrorHandlerBuilder errorHandlerBuilder) {
1082 setErrorHandlerBuilder(errorHandlerBuilder);
1083 return (Type) this;
1084 }
1085
1086 /**
1087 * Configures whether or not the error handler is inherited by every
1088 * processing node (or just the top most one)
1089 *
1090 * @param condition the flag as to whether error handlers should be
1091 * inherited or not
1092 * @return the current builder
1093 */
1094 public Type inheritErrorHandler(boolean condition) {
1095 setInheritErrorHandlerFlag(condition);
1096 return (Type) this;
1097 }
1098
1099 // Transformers
1100 // -------------------------------------------------------------------------
1101
1102 /**
1103 * Adds the custom processor to this destination which could be a final
1104 * destination, or could be a transformation in a pipeline
1105 */
1106 public Type process(Processor processor) {
1107 ProcessorRef answer = new ProcessorRef(processor);
1108 addOutput(answer);
1109 return (Type) this;
1110 }
1111
1112 /**
1113 * Adds the custom processor reference to this destination which could be a final
1114 * destination, or could be a transformation in a pipeline
1115 */
1116 public Type processRef(String ref) {
1117 ProcessorRef answer = new ProcessorRef();
1118 answer.setRef(ref);
1119 addOutput(answer);
1120 return (Type) this;
1121 }
1122
1123 /**
1124 * Adds a bean which is invoked which could be a final destination, or could
1125 * be a transformation in a pipeline
1126 */
1127 public Type bean(Object bean) {
1128 BeanRef answer = new BeanRef();
1129 answer.setBean(bean);
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 bean(Object bean, String method) {
1139 BeanRef answer = new BeanRef();
1140 answer.setBean(bean);
1141 answer.setMethod(method);
1142 addOutput(answer);
1143 return (Type) this;
1144 }
1145
1146 /**
1147 * Adds a bean by type which is invoked which could be a final destination, or could
1148 * be a transformation in a pipeline
1149 */
1150 public Type bean(Class beanType) {
1151 BeanRef answer = new BeanRef();
1152 answer.setBeanType(beanType);
1153 addOutput(answer);
1154 return (Type) this;
1155 }
1156
1157 /**
1158 * Adds a bean type and method which is invoked which could be a final
1159 * destination, or could be a transformation in a pipeline
1160 */
1161 public Type bean(Class beanType, String method) {
1162 BeanRef answer = new BeanRef();
1163 answer.setBeanType(beanType);
1164 answer.setMethod(method);
1165 addOutput(answer);
1166 return (Type) this;
1167 }
1168
1169 /**
1170 * Adds a bean which is invoked which could be a final destination, or could
1171 * be a transformation in a pipeline
1172 */
1173 public Type beanRef(String ref) {
1174 BeanRef answer = new BeanRef(ref);
1175 addOutput(answer);
1176 return (Type) this;
1177 }
1178
1179 /**
1180 * Adds a bean and method which is invoked which could be a final
1181 * destination, or could be a transformation in a pipeline
1182 */
1183 public Type beanRef(String ref, String method) {
1184 BeanRef answer = new BeanRef(ref, method);
1185 addOutput(answer);
1186 return (Type) this;
1187 }
1188
1189 /**
1190 * Adds a processor which sets the body on the IN message
1191 */
1192 public ExpressionClause<ProcessorType<Type>> setBody() {
1193 ExpressionClause<ProcessorType<Type>> clause = new ExpressionClause<ProcessorType<Type>>((Type) this);
1194 SetBodyType answer = new SetBodyType(clause);
1195 addOutput(answer);
1196 return clause;
1197 }
1198
1199 /**
1200 * Adds a processor which sets the body on the IN message
1201 */
1202 public Type setBody(Expression expression) {
1203 SetBodyType answer = new SetBodyType(expression);
1204 addOutput(answer);
1205 return (Type) this;
1206 }
1207
1208 /**
1209 * Adds a processor which sets the body on the OUT message
1210 *
1211 * @deprecated Please use {@link #transform(Expression)} instead. Will be removed in Camel 2.0.
1212 */
1213 @Deprecated
1214 public Type setOutBody(Expression expression) {
1215 return transform(expression);
1216 }
1217
1218 /**
1219 * Adds a processor which sets the body on the OUT message
1220 *
1221 * @deprecated Please use {@link #transform()} instead. Will be removed in Camel 2.0.
1222 */
1223 @Deprecated
1224 public ExpressionClause<ProcessorType<Type>> setOutBody() {
1225 return transform();
1226 }
1227
1228 /**
1229 * Adds a processor which sets the body on the OUT message
1230 */
1231 public Type transform(Expression expression) {
1232 TransformType answer = new TransformType(expression);
1233 addOutput(answer);
1234 return (Type) this;
1235 }
1236
1237 /**
1238 * Adds a processor which sets the body on the OUT message
1239 */
1240 public ExpressionClause<ProcessorType<Type>> transform() {
1241 ExpressionClause<ProcessorType<Type>> clause = new ExpressionClause<ProcessorType<Type>>((Type) this);
1242 TransformType answer = new TransformType(clause);
1243 addOutput(answer);
1244 return clause;
1245 }
1246
1247 /**
1248 * Adds a processor which sets the body on the FAULT message
1249 */
1250 public Type setFaultBody(Expression expression) {
1251 return process(ProcessorBuilder.setFaultBody(expression));
1252 }
1253
1254 /**
1255 * Adds a processor which sets the header on the IN message
1256 */
1257 public ExpressionClause<ProcessorType<Type>> setHeader(String name) {
1258 ExpressionClause<ProcessorType<Type>> clause = new ExpressionClause<ProcessorType<Type>>((Type) this);
1259 SetHeaderType answer = new SetHeaderType(name, clause);
1260 addOutput(answer);
1261 return clause;
1262 }
1263
1264 /**
1265 * Adds a processor which sets the header on the IN message
1266 */
1267 public Type setHeader(String name, Expression expression) {
1268 SetHeaderType answer = new SetHeaderType(name, expression);
1269 addOutput(answer);
1270 return (Type) this;
1271 }
1272
1273 /**
1274 * Adds a processor which sets the header on the IN message to the given value
1275 * @deprecated Please use {@link #setHeader(String, Expression)} instead. Will be removed in Camel 2.0.
1276 */
1277 public Type setHeader(String name, String value) {
1278 SetHeaderType answer = new SetHeaderType(name, value);
1279 addOutput(answer);
1280 return (Type) this;
1281 }
1282
1283 /**
1284 * Adds a processor which sets the header on the OUT message
1285 */
1286 public ExpressionClause<ProcessorType<Type>> setOutHeader(String name) {
1287 ExpressionClause<ProcessorType<Type>> clause = new ExpressionClause<ProcessorType<Type>>((Type) this);
1288 SetOutHeaderType answer = new SetOutHeaderType(name, clause);
1289 addOutput(answer);
1290 return clause;
1291 }
1292
1293 /**
1294 * Adds a processor which sets the header on the OUT message
1295 */
1296 public Type setOutHeader(String name, Expression expression) {
1297 SetOutHeaderType answer = new SetOutHeaderType(name, expression);
1298 addOutput(answer);
1299 return (Type) this;
1300 }
1301
1302 /**
1303 * Adds a processor which sets the header on the FAULT message
1304 */
1305 public Type setFaultHeader(String name, Expression expression) {
1306 return process(ProcessorBuilder.setFaultHeader(name, expression));
1307 }
1308
1309 /**
1310 * Adds a processor which sets the exchange property
1311 */
1312 public Type setProperty(String name, Expression expression) {
1313 SetPropertyType answer = new SetPropertyType(name, expression);
1314 addOutput(answer);
1315 return (Type) this;
1316 }
1317
1318
1319 /**
1320 * Adds a processor which sets the exchange property
1321 */
1322 public ExpressionClause<ProcessorType<Type>> setProperty(String name) {
1323 ExpressionClause<ProcessorType<Type>> clause = new ExpressionClause<ProcessorType<Type>>((Type) this);
1324 SetPropertyType answer = new SetPropertyType(name, clause);
1325 addOutput(answer);
1326 return clause;
1327 }
1328
1329 /**
1330 * Adds a processor which removes the header on the IN message
1331 */
1332 public Type removeHeader(String name) {
1333 RemoveHeaderType answer = new RemoveHeaderType(name);
1334 addOutput(answer);
1335 return (Type) this;
1336 }
1337
1338 /**
1339 * Adds a processor which removes the header on the FAULT message
1340 */
1341 public Type removeFaultHeader(String name) {
1342 return process(ProcessorBuilder.removeFaultHeader(name));
1343 }
1344
1345 /**
1346 * Adds a processor which removes the exchange property
1347 */
1348 public Type removeProperty(String name) {
1349 RemovePropertyType answer = new RemovePropertyType(name);
1350 addOutput(answer);
1351 return (Type) this;
1352 }
1353
1354 /**
1355 * Converts the IN message body to the specified type
1356 */
1357 public Type convertBodyTo(Class type) {
1358 addOutput(new ConvertBodyType(type));
1359 return (Type) this;
1360 }
1361
1362 /**
1363 * Converts the OUT message body to the specified type
1364 *
1365 * @deprecated Please use {@link #convertBodyTo(Class)} instead. Will be removed in Camel 2.0.
1366 */
1367 @Deprecated
1368 public Type convertOutBodyTo(Class type) {
1369 return process(new ConvertBodyProcessor(type));
1370 }
1371
1372 /**
1373 * Converts the FAULT message body to the specified type
1374 *
1375 * @deprecated Please use {@link #convertBodyTo(Class)} instead. Will be removed in Camel 2.0.
1376 */
1377 @Deprecated
1378 public Type convertFaultBodyTo(Class type) {
1379 return process(new ConvertBodyProcessor(type));
1380 }
1381
1382 // DataFormat support
1383 // -------------------------------------------------------------------------
1384
1385 /**
1386 * Unmarshals the in body using a {@link DataFormat} expression to define
1387 * the format of the input message and the output will be set on the out message body.
1388 *
1389 * @return the expression to create the {@link DataFormat}
1390 */
1391 public DataFormatClause<ProcessorType<Type>> unmarshal() {
1392 return new DataFormatClause<ProcessorType<Type>>(this, DataFormatClause.Operation.Unmarshal);
1393 }
1394
1395 /**
1396 * Unmarshals the in body using the specified {@link DataFormat}
1397 * and sets the output on the out message body.
1398 *
1399 * @return this object
1400 */
1401 public Type unmarshal(DataFormatType dataFormatType) {
1402 addOutput(new UnmarshalType(dataFormatType));
1403 return (Type) this;
1404 }
1405
1406 /**
1407 * Unmarshals the in body using the specified {@link DataFormat}
1408 * and sets the output on the out message body.
1409 *
1410 * @return this object
1411 */
1412 public Type unmarshal(DataFormat dataFormat) {
1413 return unmarshal(new DataFormatType(dataFormat));
1414 }
1415
1416 /**
1417 * Unmarshals the in body using the specified {@link DataFormat}
1418 * reference in the {@link org.apache.camel.spi.Registry} and sets
1419 * the output on the out message body.
1420 *
1421 * @return this object
1422 */
1423 public Type unmarshal(String dataTypeRef) {
1424 addOutput(new UnmarshalType(dataTypeRef));
1425 return (Type) this;
1426 }
1427
1428 /**
1429 * Marshals the in body using a {@link DataFormat} expression to define
1430 * the format of the output which will be added to the out body.
1431 *
1432 * @return the expression to create the {@link DataFormat}
1433 */
1434 public DataFormatClause<ProcessorType<Type>> marshal() {
1435 return new DataFormatClause<ProcessorType<Type>>(this, DataFormatClause.Operation.Marshal);
1436 }
1437
1438 /**
1439 * Marshals the in body using the specified {@link DataFormat}
1440 * and sets the output on the out message body.
1441 *
1442 * @return this object
1443 */
1444 public Type marshal(DataFormatType dataFormatType) {
1445 addOutput(new MarshalType(dataFormatType));
1446 return (Type) this;
1447 }
1448
1449 /**
1450 * Marshals the in body using the specified {@link DataFormat}
1451 * and sets the output on the out message body.
1452 *
1453 * @return this object
1454 */
1455 public Type marshal(DataFormat dataFormat) {
1456 return marshal(new DataFormatType(dataFormat));
1457 }
1458
1459 /**
1460 * Marshals the in body the specified {@link DataFormat}
1461 * reference in the {@link org.apache.camel.spi.Registry} and sets
1462 * the output on the out message body.
1463 *
1464 * @return this object
1465 */
1466 public Type marshal(String dataTypeRef) {
1467 addOutput(new MarshalType(dataTypeRef));
1468 return (Type) this;
1469 }
1470
1471 // Properties
1472 // -------------------------------------------------------------------------
1473 @XmlTransient
1474 public ProcessorType<? extends ProcessorType> getParent() {
1475 return parent;
1476 }
1477
1478 public void setParent(ProcessorType<? extends ProcessorType> parent) {
1479 this.parent = parent;
1480 }
1481
1482 @XmlTransient
1483 public ErrorHandlerBuilder getErrorHandlerBuilder() {
1484 if (errorHandlerBuilder == null) {
1485 errorHandlerBuilder = createErrorHandlerBuilder();
1486 }
1487 return errorHandlerBuilder;
1488 }
1489
1490 /**
1491 * Sets the error handler to use with processors created by this builder
1492 */
1493 public void setErrorHandlerBuilder(ErrorHandlerBuilder errorHandlerBuilder) {
1494 this.errorHandlerBuilder = errorHandlerBuilder;
1495 }
1496
1497 /**
1498 * Sets the error handler if one is not already set
1499 */
1500 protected void setErrorHandlerBuilderIfNull(ErrorHandlerBuilder errorHandlerBuilder) {
1501 if (this.errorHandlerBuilder == null) {
1502 setErrorHandlerBuilder(errorHandlerBuilder);
1503 }
1504 }
1505
1506 public String getErrorHandlerRef() {
1507 return errorHandlerRef;
1508 }
1509
1510 /**
1511 * Sets the bean ref name of the error handler builder to use on this route
1512 */
1513 @XmlAttribute(required = false)
1514 public void setErrorHandlerRef(String errorHandlerRef) {
1515 this.errorHandlerRef = errorHandlerRef;
1516 setErrorHandlerBuilder(new ErrorHandlerBuilderRef(errorHandlerRef));
1517 }
1518
1519 @XmlTransient
1520 public boolean isInheritErrorHandler() {
1521 return isInheritErrorHandler(getInheritErrorHandlerFlag());
1522 }
1523
1524 /**
1525 * Lets default the inherit value to be true if there is none specified
1526 */
1527 public static boolean isInheritErrorHandler(Boolean value) {
1528 return value == null || value.booleanValue();
1529 }
1530
1531 @XmlAttribute(name = "inheritErrorHandler", required = false)
1532 public Boolean getInheritErrorHandlerFlag() {
1533 return inheritErrorHandlerFlag;
1534 }
1535
1536 public void setInheritErrorHandlerFlag(Boolean inheritErrorHandlerFlag) {
1537 this.inheritErrorHandlerFlag = inheritErrorHandlerFlag;
1538 }
1539
1540 @XmlTransient
1541 public NodeFactory getNodeFactory() {
1542 if (nodeFactory == null) {
1543 nodeFactory = new NodeFactory();
1544 }
1545 return nodeFactory;
1546 }
1547
1548 public void setNodeFactory(NodeFactory nodeFactory) {
1549 this.nodeFactory = nodeFactory;
1550 }
1551
1552 /**
1553 * Returns a label to describe this node such as the expression if some kind of expression node
1554 */
1555 public String getLabel() {
1556 return "";
1557 }
1558
1559 // Implementation methods
1560 // -------------------------------------------------------------------------
1561
1562 /**
1563 * Creates the processor and wraps it in any necessary interceptors and
1564 * error handlers
1565 */
1566 protected Processor makeProcessor(RouteContext routeContext) throws Exception {
1567 Processor processor = createProcessor(routeContext);
1568 return wrapProcessor(routeContext, processor);
1569 }
1570
1571 /**
1572 * A strategy method which allows derived classes to wrap the child
1573 * processor in some kind of interceptor
1574 *
1575 * @param routeContext
1576 * @param target the processor which can be wrapped
1577 * @return the original processor or a new wrapped interceptor
1578 */
1579 protected Processor wrapProcessorInInterceptors(RouteContext routeContext, Processor target) throws Exception {
1580 // The target is required.
1581 if (target == null) {
1582 throw new IllegalArgumentException("target not provided on node: " + this);
1583 }
1584
1585 List<InterceptStrategy> strategies = new ArrayList<InterceptStrategy>();
1586 CamelContext camelContext = routeContext.getCamelContext();
1587 if (camelContext instanceof DefaultCamelContext) {
1588 DefaultCamelContext defaultCamelContext = (DefaultCamelContext) camelContext;
1589 strategies.addAll(defaultCamelContext.getInterceptStrategies());
1590 }
1591 strategies.addAll(routeContext.getInterceptStrategies());
1592 for (InterceptStrategy strategy : strategies) {
1593 if (strategy != null) {
1594 target = strategy.wrapProcessorInInterceptors(this, target);
1595 }
1596 }
1597
1598 List<InterceptorType> list = routeContext.getRoute().getInterceptors();
1599 if (interceptors != null) {
1600 list.addAll(interceptors);
1601 }
1602 // lets reverse the list so we apply the inner interceptors first
1603 Collections.reverse(list);
1604 Set<Processor> interceptors = new HashSet<Processor>();
1605 interceptors.add(target);
1606 for (InterceptorType interceptorType : list) {
1607 DelegateProcessor interceptor = interceptorType.createInterceptor(routeContext);
1608 if (!interceptors.contains(interceptor)) {
1609 interceptors.add(interceptor);
1610 if (interceptor.getProcessor() != null) {
1611 LOG.warn("Interceptor " + interceptor + " currently wraps target "
1612 + interceptor.getProcessor()
1613 + " is attempting to change target " + target
1614 + " new wrapping has been denied.");
1615 } else {
1616 interceptor.setProcessor(target);
1617 target = interceptor;
1618 }
1619 }
1620 }
1621 return target;
1622 }
1623
1624 /**
1625 * A strategy method to allow newly created processors to be wrapped in an
1626 * error handler.
1627 */
1628 protected Processor wrapInErrorHandler(RouteContext routeContext, Processor target) throws Exception {
1629 // The target is required.
1630 if (target == null) {
1631 throw new IllegalArgumentException("target not provided on node: " + this);
1632 }
1633
1634 ErrorHandlerWrappingStrategy strategy = routeContext.getErrorHandlerWrappingStrategy();
1635
1636 if (strategy != null) {
1637 return strategy.wrapProcessorInErrorHandler(routeContext, this, target);
1638 }
1639
1640 return getErrorHandlerBuilder().createErrorHandler(routeContext, target);
1641 }
1642
1643 protected ErrorHandlerBuilder createErrorHandlerBuilder() {
1644 if (errorHandlerRef != null) {
1645 return new ErrorHandlerBuilderRef(errorHandlerRef);
1646 }
1647 if (isInheritErrorHandler()) {
1648 return new DeadLetterChannelBuilder();
1649 } else {
1650 return new NoErrorHandlerBuilder();
1651 }
1652 }
1653
1654 protected void configureChild(ProcessorType output) {
1655 output.setNodeFactory(getNodeFactory());
1656 }
1657
1658 public void addOutput(ProcessorType processorType) {
1659 processorType.setParent(this);
1660 configureChild(processorType);
1661 if (blocks.isEmpty()) {
1662 getOutputs().add(processorType);
1663 } else {
1664 Block block = blocks.getLast();
1665 block.addOutput(processorType);
1666 }
1667 }
1668
1669 /**
1670 * Creates a new instance of some kind of composite processor which defaults
1671 * to using a {@link Pipeline} but derived classes could change the
1672 * behaviour
1673 */
1674 protected Processor createCompositeProcessor(RouteContext routeContext, List<Processor> list) {
1675 // return new MulticastProcessor(list);
1676 return new Pipeline(list);
1677 }
1678
1679 protected Processor createOutputsProcessor(RouteContext routeContext, Collection<ProcessorType<?>> outputs)
1680 throws Exception {
1681 List<Processor> list = new ArrayList<Processor>();
1682 for (ProcessorType output : outputs) {
1683 Processor processor = output.createProcessor(routeContext);
1684 // if the ProceedType create processor is null we keep on going
1685 if (output instanceof ProceedType && processor == null) {
1686 continue;
1687 }
1688 processor = output.wrapProcessorInInterceptors(routeContext, processor);
1689
1690 ProcessorType currentProcessor = this;
1691 if (!(currentProcessor instanceof ExceptionType || currentProcessor instanceof TryType)) {
1692 processor = output.wrapInErrorHandler(routeContext, processor);
1693 }
1694
1695 list.add(processor);
1696 }
1697 Processor processor = null;
1698 if (!list.isEmpty()) {
1699 if (list.size() == 1) {
1700 processor = list.get(0);
1701 } else {
1702 processor = createCompositeProcessor(routeContext, list);
1703 }
1704 }
1705 return processor;
1706 }
1707
1708 public void clearOutput() {
1709 getOutputs().clear();
1710 blocks.clear();
1711 }
1712 }