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