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