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