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