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 */ 017package org.apache.camel.model; 018 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import javax.xml.bind.annotation.XmlAccessType; 025import javax.xml.bind.annotation.XmlAccessorType; 026import javax.xml.bind.annotation.XmlAttribute; 027import javax.xml.bind.annotation.XmlElement; 028import javax.xml.bind.annotation.XmlElementRef; 029import javax.xml.bind.annotation.XmlRootElement; 030import javax.xml.bind.annotation.XmlTransient; 031 032import org.apache.camel.CamelContext; 033import org.apache.camel.Expression; 034import org.apache.camel.LoggingLevel; 035import org.apache.camel.Predicate; 036import org.apache.camel.Processor; 037import org.apache.camel.Route; 038import org.apache.camel.builder.ErrorHandlerBuilder; 039import org.apache.camel.builder.ExpressionBuilder; 040import org.apache.camel.processor.CatchProcessor; 041import org.apache.camel.processor.FatalFallbackErrorHandler; 042import org.apache.camel.processor.RedeliveryPolicy; 043import org.apache.camel.spi.AsPredicate; 044import org.apache.camel.spi.ClassResolver; 045import org.apache.camel.spi.Metadata; 046import org.apache.camel.spi.RouteContext; 047import org.apache.camel.util.CamelContextHelper; 048import org.apache.camel.util.ExpressionToPredicateAdapter; 049import org.apache.camel.util.ObjectHelper; 050 051/** 052 * Route to be executed when an exception is thrown 053 * 054 * @version 055 */ 056@Metadata(label = "error") 057@XmlRootElement(name = "onException") 058@XmlAccessorType(XmlAccessType.FIELD) 059public class OnExceptionDefinition extends ProcessorDefinition<OnExceptionDefinition> { 060 @XmlElement(name = "exception", required = true) 061 private List<String> exceptions = new ArrayList<String>(); 062 @XmlElement(name = "onWhen") @AsPredicate 063 private WhenDefinition onWhen; 064 @XmlElement(name = "retryWhile") @AsPredicate 065 private ExpressionSubElementDefinition retryWhile; 066 @XmlElement(name = "redeliveryPolicy") 067 private RedeliveryPolicyDefinition redeliveryPolicyType; 068 @XmlAttribute(name = "redeliveryPolicyRef") 069 private String redeliveryPolicyRef; 070 @XmlElement(name = "handled") @AsPredicate 071 private ExpressionSubElementDefinition handled; 072 @XmlElement(name = "continued") @AsPredicate 073 private ExpressionSubElementDefinition continued; 074 @XmlAttribute(name = "onRedeliveryRef") 075 private String onRedeliveryRef; 076 @XmlAttribute(name = "onExceptionOccurredRef") 077 private String onExceptionOccurredRef; 078 @XmlAttribute(name = "useOriginalMessage") 079 private Boolean useOriginalMessagePolicy; 080 @XmlElementRef 081 private List<ProcessorDefinition<?>> outputs = new ArrayList<ProcessorDefinition<?>>(); 082 @XmlTransient 083 private List<Class<? extends Throwable>> exceptionClasses; 084 @XmlTransient 085 private Predicate handledPolicy; 086 @XmlTransient 087 private Predicate continuedPolicy; 088 @XmlTransient 089 private Predicate retryWhilePolicy; 090 @XmlTransient 091 private Processor onRedelivery; 092 @XmlTransient 093 private Processor onExceptionOccurred; 094 @XmlTransient 095 private Boolean routeScoped; 096 // TODO: in Camel 3.0 the OnExceptionDefinition should not contain state and ErrorHandler processors 097 @XmlTransient 098 private final Map<String, Processor> errorHandlers = new HashMap<String, Processor>(); 099 @XmlTransient 100 private RedeliveryPolicy redeliveryPolicy; 101 102 public OnExceptionDefinition() { 103 } 104 105 public OnExceptionDefinition(List<Class<? extends Throwable>> exceptionClasses) { 106 this.exceptionClasses = exceptionClasses; 107 } 108 109 public OnExceptionDefinition(Class<? extends Throwable> exceptionType) { 110 exceptionClasses = new ArrayList<Class<? extends Throwable>>(); 111 exceptionClasses.add(exceptionType); 112 } 113 114 public void setRouteScoped(boolean routeScoped) { 115 this.routeScoped = routeScoped; 116 } 117 118 public boolean isRouteScoped() { 119 // is context scoped by default 120 return routeScoped != null ? routeScoped : false; 121 } 122 123 @Override 124 public String toString() { 125 return "OnException[" + description() + " -> " + getOutputs() + "]"; 126 } 127 128 protected String description() { 129 return getExceptionClasses() + (onWhen != null ? " " + onWhen : ""); 130 } 131 132 @Override 133 public String getLabel() { 134 return "onException[" + description() + "]"; 135 } 136 137 @Override 138 public boolean isAbstract() { 139 return true; 140 } 141 142 @Override 143 public boolean isTopLevelOnly() { 144 return true; 145 } 146 147 /** 148 * Allows an exception handler to create a new redelivery policy for this exception type 149 * 150 * @param context the camel context 151 * @param parentPolicy the current redelivery policy, is newer <tt>null</tt> 152 * @return a newly created redelivery policy, or return the original policy if no customization is required 153 * for this exception handler. 154 */ 155 public RedeliveryPolicy createRedeliveryPolicy(CamelContext context, RedeliveryPolicy parentPolicy) { 156 if (redeliveryPolicy != null) { 157 return redeliveryPolicy; 158 } else if (redeliveryPolicyRef != null) { 159 return CamelContextHelper.mandatoryLookup(context, redeliveryPolicyRef, RedeliveryPolicy.class); 160 } else if (redeliveryPolicyType != null) { 161 return redeliveryPolicyType.createRedeliveryPolicy(context, parentPolicy); 162 } else if (!outputs.isEmpty() && parentPolicy.getMaximumRedeliveries() != 0) { 163 // if we have outputs, then do not inherit parent maximumRedeliveries 164 // as you would have to explicit configure maximumRedeliveries on this onException to use it 165 // this is the behavior Camel has always had 166 RedeliveryPolicy answer = parentPolicy.copy(); 167 answer.setMaximumRedeliveries(0); 168 return answer; 169 } else { 170 return parentPolicy; 171 } 172 } 173 174 public void addRoutes(RouteContext routeContext, Collection<Route> routes) throws Exception { 175 // assign whether this was a route scoped onException or not 176 // we need to know this later when setting the parent, as only route scoped should have parent 177 // Note: this logic can possible be removed when the Camel routing engine decides at runtime 178 // to apply onException in a more dynamic fashion than current code base 179 // and therefore is in a better position to decide among context/route scoped OnException at runtime 180 if (routeScoped == null) { 181 routeScoped = super.getParent() != null; 182 } 183 184 setHandledFromExpressionType(routeContext); 185 setContinuedFromExpressionType(routeContext); 186 setRetryWhileFromExpressionType(routeContext); 187 setOnRedeliveryFromRedeliveryRef(routeContext); 188 setOnExceptionOccurredFromOnExceptionOccurredRef(routeContext); 189 190 // load exception classes 191 if (exceptions != null && !exceptions.isEmpty()) { 192 exceptionClasses = createExceptionClasses(routeContext.getCamelContext().getClassResolver()); 193 } 194 195 // must validate configuration before creating processor 196 validateConfiguration(); 197 198 if (useOriginalMessagePolicy != null && useOriginalMessagePolicy) { 199 // ensure allow original is turned on 200 routeContext.setAllowUseOriginalMessage(true); 201 } 202 203 // lets attach this on exception to the route error handler 204 Processor child = createOutputsProcessor(routeContext); 205 if (child != null) { 206 // wrap in our special safe fallback error handler if OnException have child output 207 Processor errorHandler = new FatalFallbackErrorHandler(child); 208 String id = routeContext.getRoute().getId(); 209 errorHandlers.put(id, errorHandler); 210 } 211 // lookup the error handler builder 212 ErrorHandlerBuilder builder = (ErrorHandlerBuilder)routeContext.getRoute().getErrorHandlerBuilder(); 213 // and add this as error handlers 214 builder.addErrorHandlers(routeContext, this); 215 } 216 217 @Override 218 public CatchProcessor createProcessor(RouteContext routeContext) throws Exception { 219 // load exception classes 220 if (exceptions != null && !exceptions.isEmpty()) { 221 exceptionClasses = createExceptionClasses(routeContext.getCamelContext().getClassResolver()); 222 } 223 224 if (useOriginalMessagePolicy != null && useOriginalMessagePolicy) { 225 // ensure allow original is turned on 226 routeContext.setAllowUseOriginalMessage(true); 227 } 228 229 // must validate configuration before creating processor 230 validateConfiguration(); 231 232 Processor childProcessor = this.createChildProcessor(routeContext, false); 233 234 Predicate when = null; 235 if (onWhen != null) { 236 when = onWhen.getExpression().createPredicate(routeContext); 237 } 238 239 Predicate handle = null; 240 if (handled != null) { 241 handle = handled.createPredicate(routeContext); 242 } 243 244 return new CatchProcessor(getExceptionClasses(), childProcessor, when, handle); 245 } 246 247 protected void validateConfiguration() { 248 if (isInheritErrorHandler() != null && isInheritErrorHandler()) { 249 throw new IllegalArgumentException(this + " cannot have the inheritErrorHandler option set to true"); 250 } 251 252 List<Class<? extends Throwable>> exceptions = getExceptionClasses(); 253 if (exceptions == null || exceptions.isEmpty()) { 254 throw new IllegalArgumentException("At least one exception must be configured on " + this); 255 } 256 257 // only one of handled or continued is allowed 258 if (getHandledPolicy() != null && getContinuedPolicy() != null) { 259 throw new IllegalArgumentException("Only one of handled or continued is allowed to be configured on: " + this); 260 } 261 262 // validate that at least some option is set as you cannot just have onException(Exception.class); 263 if (outputs == null || getOutputs().isEmpty()) { 264 // no outputs so there should be some sort of configuration 265 ObjectHelper.firstNotNull( 266 handledPolicy, 267 continuedPolicy, 268 retryWhilePolicy, 269 redeliveryPolicyType, 270 useOriginalMessagePolicy, 271 redeliveryPolicy, 272 onRedeliveryRef, 273 onRedelivery, 274 onExceptionOccurred 275 ).orElseThrow( 276 () -> new IllegalArgumentException(this + " is not configured.") 277 ); 278 } 279 } 280 281 // Fluent API 282 //------------------------------------------------------------------------- 283 284 @Override 285 public OnExceptionDefinition onException(Class<? extends Throwable> exceptionType) { 286 getExceptionClasses().add(exceptionType); 287 return this; 288 } 289 290 /** 291 * Sets whether the exchange should be marked as handled or not. 292 * 293 * @param handled handled or not 294 * @return the builder 295 */ 296 public OnExceptionDefinition handled(boolean handled) { 297 Expression expression = ExpressionBuilder.constantExpression(Boolean.toString(handled)); 298 return handled(expression); 299 } 300 301 /** 302 * Sets whether the exchange should be marked as handled or not. 303 * 304 * @param handled predicate that determines true or false 305 * @return the builder 306 */ 307 public OnExceptionDefinition handled(@AsPredicate Predicate handled) { 308 setHandledPolicy(handled); 309 return this; 310 } 311 312 /** 313 * Sets whether the exchange should be marked as handled or not. 314 * 315 * @param handled expression that determines true or false 316 * @return the builder 317 */ 318 public OnExceptionDefinition handled(@AsPredicate Expression handled) { 319 setHandledPolicy(ExpressionToPredicateAdapter.toPredicate(handled)); 320 return this; 321 } 322 323 /** 324 * Sets whether the exchange should handle and continue routing from the point of failure. 325 * <p/> 326 * If this option is enabled then its considered handled as well. 327 * 328 * @param continued continued or not 329 * @return the builder 330 */ 331 public OnExceptionDefinition continued(boolean continued) { 332 Expression expression = ExpressionBuilder.constantExpression(Boolean.toString(continued)); 333 return continued(expression); 334 } 335 336 /** 337 * Sets whether the exchange should be marked as handled or not. 338 * <p/> 339 * If this option is enabled then its considered handled as well. 340 * 341 * @param continued predicate that determines true or false 342 * @return the builder 343 */ 344 public OnExceptionDefinition continued(@AsPredicate Predicate continued) { 345 setContinuedPolicy(continued); 346 return this; 347 } 348 349 /** 350 * Sets whether the exchange should be marked as handled or not. 351 * <p/> 352 * If this option is enabled then its considered handled as well. 353 * 354 * @param continued expression that determines true or false 355 * @return the builder 356 */ 357 public OnExceptionDefinition continued(@AsPredicate Expression continued) { 358 setContinuedPolicy(ExpressionToPredicateAdapter.toPredicate(continued)); 359 return this; 360 } 361 362 /** 363 * Sets an additional predicate that should be true before the onException is triggered. 364 * <p/> 365 * To be used for fine grained controlling whether a thrown exception should be intercepted 366 * by this exception type or not. 367 * 368 * @param predicate predicate that determines true or false 369 * @return the builder 370 */ 371 public OnExceptionDefinition onWhen(@AsPredicate Predicate predicate) { 372 setOnWhen(new WhenDefinition(predicate)); 373 return this; 374 } 375 376 /** 377 * Sets the retry while predicate. 378 * <p/> 379 * Will continue retrying until predicate returns <tt>false</tt>. 380 * 381 * @param retryWhile predicate that determines when to stop retrying 382 * @return the builder 383 */ 384 public OnExceptionDefinition retryWhile(@AsPredicate Predicate retryWhile) { 385 setRetryWhilePolicy(retryWhile); 386 return this; 387 } 388 389 /** 390 * Sets the initial redelivery delay 391 * 392 * @param delay the initial redelivery delay 393 * @return the builder 394 * @deprecated will be removed in the near future. Instead use {@link #redeliveryDelay(String)} 395 */ 396 @Deprecated 397 public OnExceptionDefinition redeliverDelay(long delay) { 398 getOrCreateRedeliveryPolicy().redeliveryDelay(delay); 399 return this; 400 } 401 402 /** 403 * Sets the back off multiplier 404 * 405 * @param backOffMultiplier the back off multiplier 406 * @return the builder 407 */ 408 public OnExceptionDefinition backOffMultiplier(double backOffMultiplier) { 409 getOrCreateRedeliveryPolicy().useExponentialBackOff(); 410 getOrCreateRedeliveryPolicy().backOffMultiplier(backOffMultiplier); 411 return this; 412 } 413 414 /** 415 * Sets the back off multiplier (supports property placeholders) 416 * 417 * @param backOffMultiplier the back off multiplier 418 * @return the builder 419 */ 420 public OnExceptionDefinition backOffMultiplier(String backOffMultiplier) { 421 getOrCreateRedeliveryPolicy().useExponentialBackOff(); 422 getOrCreateRedeliveryPolicy().backOffMultiplier(backOffMultiplier); 423 return this; 424 } 425 426 /** 427 * Sets the collision avoidance factor 428 * 429 * @param collisionAvoidanceFactor the factor 430 * @return the builder 431 */ 432 public OnExceptionDefinition collisionAvoidanceFactor(double collisionAvoidanceFactor) { 433 getOrCreateRedeliveryPolicy().useCollisionAvoidance(); 434 getOrCreateRedeliveryPolicy().collisionAvoidanceFactor(collisionAvoidanceFactor); 435 return this; 436 } 437 438 /** 439 * Sets the collision avoidance factor (supports property placeholders) 440 * 441 * @param collisionAvoidanceFactor the factor 442 * @return the builder 443 */ 444 public OnExceptionDefinition collisionAvoidanceFactor(String collisionAvoidanceFactor) { 445 getOrCreateRedeliveryPolicy().useCollisionAvoidance(); 446 getOrCreateRedeliveryPolicy().collisionAvoidanceFactor(collisionAvoidanceFactor); 447 return this; 448 } 449 450 /** 451 * Sets the collision avoidance percentage 452 * 453 * @param collisionAvoidancePercent the percentage 454 * @return the builder 455 */ 456 public OnExceptionDefinition collisionAvoidancePercent(double collisionAvoidancePercent) { 457 getOrCreateRedeliveryPolicy().useCollisionAvoidance(); 458 getOrCreateRedeliveryPolicy().collisionAvoidancePercent(collisionAvoidancePercent); 459 return this; 460 } 461 462 /** 463 * Sets the initial redelivery delay 464 * 465 * @param delay delay in millis 466 * @return the builder 467 */ 468 public OnExceptionDefinition redeliveryDelay(long delay) { 469 getOrCreateRedeliveryPolicy().redeliveryDelay(delay); 470 return this; 471 } 472 473 /** 474 * Sets the initial redelivery delay (supports property placeholders) 475 * 476 * @param delay delay in millis 477 * @return the builder 478 */ 479 public OnExceptionDefinition redeliveryDelay(String delay) { 480 getOrCreateRedeliveryPolicy().redeliveryDelay(delay); 481 return this; 482 } 483 484 /** 485 * Allow synchronous delayed redelivery. 486 * 487 * @see org.apache.camel.processor.RedeliveryPolicy#setAsyncDelayedRedelivery(boolean) 488 * @return the builder 489 */ 490 public OnExceptionDefinition asyncDelayedRedelivery() { 491 getOrCreateRedeliveryPolicy().asyncDelayedRedelivery(); 492 return this; 493 } 494 495 /** 496 * Sets the logging level to use when retries has exhausted 497 * 498 * @param retriesExhaustedLogLevel the logging level 499 * @return the builder 500 */ 501 public OnExceptionDefinition retriesExhaustedLogLevel(LoggingLevel retriesExhaustedLogLevel) { 502 getOrCreateRedeliveryPolicy().retriesExhaustedLogLevel(retriesExhaustedLogLevel); 503 return this; 504 } 505 506 /** 507 * Sets the logging level to use for logging retry attempts 508 * 509 * @param retryAttemptedLogLevel the logging level 510 * @return the builder 511 */ 512 public OnExceptionDefinition retryAttemptedLogLevel(LoggingLevel retryAttemptedLogLevel) { 513 getOrCreateRedeliveryPolicy().retryAttemptedLogLevel(retryAttemptedLogLevel); 514 return this; 515 } 516 517 /** 518 * Sets whether to log stacktrace for failed messages. 519 */ 520 public OnExceptionDefinition logStackTrace(boolean logStackTrace) { 521 getOrCreateRedeliveryPolicy().logStackTrace(logStackTrace); 522 return this; 523 } 524 525 /** 526 * Sets whether to log stacktrace for failed messages (supports property placeholders) 527 */ 528 public OnExceptionDefinition logStackTrace(String logStackTrace) { 529 getOrCreateRedeliveryPolicy().logStackTrace(logStackTrace); 530 return this; 531 } 532 533 /** 534 * Sets whether to log stacktrace for failed redelivery attempts 535 */ 536 public OnExceptionDefinition logRetryStackTrace(boolean logRetryStackTrace) { 537 getOrCreateRedeliveryPolicy().logRetryStackTrace(logRetryStackTrace); 538 return this; 539 } 540 541 /** 542 * Sets whether to log stacktrace for failed redelivery attempts (supports property placeholders) 543 */ 544 public OnExceptionDefinition logRetryStackTrace(String logRetryStackTrace) { 545 getOrCreateRedeliveryPolicy().logRetryStackTrace(logRetryStackTrace); 546 return this; 547 } 548 549 /** 550 * Sets whether to log errors even if its handled 551 */ 552 public OnExceptionDefinition logHandled(boolean logHandled) { 553 getOrCreateRedeliveryPolicy().logHandled(logHandled); 554 return this; 555 } 556 557 /** 558 * Sets whether to log errors even if its handled (supports property placeholders) 559 */ 560 public OnExceptionDefinition logHandled(String logHandled) { 561 getOrCreateRedeliveryPolicy().logHandled(logHandled); 562 return this; 563 } 564 565 /** 566 * Sets whether new exceptions should be logged or not (supports property placeholders). 567 * Can be used to include or reduce verbose. 568 * <p/> 569 * A new exception is an exception that was thrown while handling a previous exception. 570 */ 571 public OnExceptionDefinition logNewException(boolean logNewException) { 572 getOrCreateRedeliveryPolicy().logNewException(logNewException); 573 return this; 574 } 575 576 /** 577 * Sets whether new exceptions should be logged or not (supports property placeholders). 578 * Can be used to include or reduce verbose. 579 * <p/> 580 * A new exception is an exception that was thrown while handling a previous exception. 581 */ 582 public OnExceptionDefinition logNewException(String logNewException) { 583 getOrCreateRedeliveryPolicy().logNewException(logNewException); 584 return this; 585 } 586 587 /** 588 * Sets whether to log errors even if its continued 589 */ 590 public OnExceptionDefinition logContinued(boolean logContinued) { 591 getOrCreateRedeliveryPolicy().logContinued(logContinued); 592 return this; 593 } 594 595 /** 596 * Sets whether to log errors even if its continued (supports property placeholders) 597 */ 598 public OnExceptionDefinition logContinued(String logContinued) { 599 getOrCreateRedeliveryPolicy().logContinued(logContinued); 600 return this; 601 } 602 603 /** 604 * Sets whether to log retry attempts 605 */ 606 public OnExceptionDefinition logRetryAttempted(boolean logRetryAttempted) { 607 getOrCreateRedeliveryPolicy().logRetryAttempted(logRetryAttempted); 608 return this; 609 } 610 611 /** 612 * Sets whether to log retry attempts (supports property placeholders) 613 */ 614 public OnExceptionDefinition logRetryAttempted(String logRetryAttempted) { 615 getOrCreateRedeliveryPolicy().logRetryAttempted(logRetryAttempted); 616 return this; 617 } 618 619 /** 620 * Sets whether to log exhausted exceptions 621 */ 622 public OnExceptionDefinition logExhausted(boolean logExhausted) { 623 getOrCreateRedeliveryPolicy().logExhausted(logExhausted); 624 return this; 625 } 626 627 /** 628 * Sets whether to log exhausted exceptions (supports property placeholders) 629 */ 630 public OnExceptionDefinition logExhausted(String logExhausted) { 631 getOrCreateRedeliveryPolicy().logExhausted(logExhausted); 632 return this; 633 } 634 635 /** 636 * Sets whether to log exhausted exceptions with message history 637 */ 638 public OnExceptionDefinition logExhaustedMessageHistory(boolean logExhaustedMessageHistory) { 639 getOrCreateRedeliveryPolicy().logExhaustedMessageHistory(logExhaustedMessageHistory); 640 return this; 641 } 642 643 /** 644 * Sets whether to log exhausted exceptions with message history 645 */ 646 public OnExceptionDefinition logExhaustedMessageHistory(String logExhaustedMessageHistory) { 647 getOrCreateRedeliveryPolicy().logExhaustedMessageHistory(logExhaustedMessageHistory); 648 return this; 649 } 650 651 /** 652 * Sets whether to log exhausted message body with message history. 653 * Requires <tt>logExhaustedMessageHistory</tt> to be enabled. 654 */ 655 public OnExceptionDefinition logExhaustedMessageBody(boolean logExhaustedMessageBody) { 656 getOrCreateRedeliveryPolicy().logExhaustedMessageBody(logExhaustedMessageBody); 657 return this; 658 } 659 660 /** 661 * Sets whether to log exhausted message body with message history. 662 * Requires <tt>logExhaustedMessageHistory</tt> to be enabled. 663 */ 664 public OnExceptionDefinition logExhaustedMessageBody(String logExhaustedMessageBody) { 665 getOrCreateRedeliveryPolicy().logExhaustedMessageBody(logExhaustedMessageBody); 666 return this; 667 } 668 669 /** 670 * Sets the maximum redeliveries 671 * <ul> 672 * <li>5 = default value</li> 673 * <li>0 = no redeliveries</li> 674 * <li>-1 = redeliver forever</li> 675 * </ul> 676 * 677 * @param maximumRedeliveries the value 678 * @return the builder 679 */ 680 public OnExceptionDefinition maximumRedeliveries(int maximumRedeliveries) { 681 getOrCreateRedeliveryPolicy().maximumRedeliveries(maximumRedeliveries); 682 return this; 683 } 684 685 /** 686 * Sets the maximum redeliveries (supports property placeholders) 687 * <ul> 688 * <li>5 = default value</li> 689 * <li>0 = no redeliveries</li> 690 * <li>-1 = redeliver forever</li> 691 * </ul> 692 * 693 * @param maximumRedeliveries the value 694 * @return the builder 695 */ 696 public OnExceptionDefinition maximumRedeliveries(String maximumRedeliveries) { 697 getOrCreateRedeliveryPolicy().maximumRedeliveries(maximumRedeliveries); 698 return this; 699 } 700 701 /** 702 * Turn on collision avoidance. 703 * 704 * @return the builder 705 */ 706 public OnExceptionDefinition useCollisionAvoidance() { 707 getOrCreateRedeliveryPolicy().useCollisionAvoidance(); 708 return this; 709 } 710 711 /** 712 * Turn on exponential backk off 713 * 714 * @return the builder 715 */ 716 public OnExceptionDefinition useExponentialBackOff() { 717 getOrCreateRedeliveryPolicy().useExponentialBackOff(); 718 return this; 719 } 720 721 /** 722 * Sets the maximum delay between redelivery 723 * 724 * @param maximumRedeliveryDelay the delay in millis 725 * @return the builder 726 */ 727 public OnExceptionDefinition maximumRedeliveryDelay(long maximumRedeliveryDelay) { 728 getOrCreateRedeliveryPolicy().maximumRedeliveryDelay(maximumRedeliveryDelay); 729 return this; 730 } 731 732 /** 733 * Sets the maximum delay between redelivery (supports property placeholders) 734 * 735 * @param maximumRedeliveryDelay the delay in millis 736 * @return the builder 737 */ 738 public OnExceptionDefinition maximumRedeliveryDelay(String maximumRedeliveryDelay) { 739 getOrCreateRedeliveryPolicy().maximumRedeliveryDelay(maximumRedeliveryDelay); 740 return this; 741 } 742 743 /** 744 * Set the {@link RedeliveryPolicy} to be used. 745 * 746 * @param redeliveryPolicy the redelivery policy 747 * @return the builder 748 */ 749 public OnExceptionDefinition redeliveryPolicy(RedeliveryPolicy redeliveryPolicy) { 750 this.redeliveryPolicy = redeliveryPolicy; 751 return this; 752 } 753 754 /** 755 * Sets a reference to a {@link RedeliveryPolicy} to lookup in the {@link org.apache.camel.spi.Registry} to be used. 756 * 757 * @param redeliveryPolicyRef reference to use for lookup 758 * @return the builder 759 */ 760 public OnExceptionDefinition redeliveryPolicyRef(String redeliveryPolicyRef) { 761 setRedeliveryPolicyRef(redeliveryPolicyRef); 762 return this; 763 } 764 765 /** 766 * Sets the delay pattern with delay intervals. 767 * 768 * @param delayPattern the delay pattern 769 * @return the builder 770 */ 771 public OnExceptionDefinition delayPattern(String delayPattern) { 772 getOrCreateRedeliveryPolicy().setDelayPattern(delayPattern); 773 return this; 774 } 775 776 /** 777 * @deprecated this method will be removed in Camel 3.0, please use {@link #useOriginalMessage()} 778 * @see #useOriginalMessage() 779 */ 780 @Deprecated 781 public OnExceptionDefinition useOriginalBody() { 782 setUseOriginalMessagePolicy(Boolean.TRUE); 783 return this; 784 } 785 786 /** 787 * Will use the original input message when an {@link org.apache.camel.Exchange} is moved to the dead letter queue. 788 * <p/> 789 * <b>Notice:</b> this only applies when all redeliveries attempt have failed and the {@link org.apache.camel.Exchange} is doomed for failure. 790 * <br/> 791 * Instead of using the current inprogress {@link org.apache.camel.Exchange} IN body we use the original IN body instead. This allows 792 * you to store the original input in the dead letter queue instead of the inprogress snapshot of the IN body. 793 * For instance if you route transform the IN body during routing and then failed. With the original exchange 794 * store in the dead letter queue it might be easier to manually re submit the {@link org.apache.camel.Exchange} again as the IN body 795 * is the same as when Camel received it. So you should be able to send the {@link org.apache.camel.Exchange} to the same input. 796 * <p/> 797 * By default this feature is off. 798 * 799 * @return the builder 800 */ 801 public OnExceptionDefinition useOriginalMessage() { 802 setUseOriginalMessagePolicy(Boolean.TRUE); 803 return this; 804 } 805 806 /** 807 * Sets a processor that should be processed <b>before</b> a redelivery attempt. 808 * <p/> 809 * Can be used to change the {@link org.apache.camel.Exchange} <b>before</b> its being redelivered. 810 */ 811 public OnExceptionDefinition onRedelivery(Processor processor) { 812 setOnRedelivery(processor); 813 return this; 814 } 815 816 /** 817 * Sets a reference to a processor that should be processed <b>before</b> a redelivery attempt. 818 * <p/> 819 * Can be used to change the {@link org.apache.camel.Exchange} <b>before</b> its being redelivered. 820 * 821 * @param ref reference to the processor 822 */ 823 public OnExceptionDefinition onRedeliveryRef(String ref) { 824 setOnRedeliveryRef(ref); 825 return this; 826 } 827 828 /** 829 * Sets a processor that should be processed <b>just after</b> an exception occurred. 830 * Can be used to perform custom logging about the occurred exception at the exact time it happened. 831 * <p/> 832 * Important: Any exception thrown from this processor will be ignored. 833 */ 834 public OnExceptionDefinition onExceptionOccurred(Processor processor) { 835 setOnExceptionOccurred(processor); 836 return this; 837 } 838 839 /** 840 * Sets a reference to a processor that should be processed <b>just after</b> an exception occurred. 841 * Can be used to perform custom logging about the occurred exception at the exact time it happened. 842 * <p/> 843 * Important: Any exception thrown from this processor will be ignored. 844 * 845 * @param ref reference to the processor 846 */ 847 public OnExceptionDefinition onExceptionOccurredRef(String ref) { 848 setOnExceptionOccurredRef(ref); 849 return this; 850 } 851 852 // Properties 853 //------------------------------------------------------------------------- 854 @Override 855 public List<ProcessorDefinition<?>> getOutputs() { 856 return outputs; 857 } 858 859 public void setOutputs(List<ProcessorDefinition<?>> outputs) { 860 this.outputs = outputs; 861 } 862 863 public boolean isOutputSupported() { 864 return true; 865 } 866 867 public List<Class<? extends Throwable>> getExceptionClasses() { 868 return exceptionClasses; 869 } 870 871 public void setExceptionClasses(List<Class<? extends Throwable>> exceptionClasses) { 872 this.exceptionClasses = exceptionClasses; 873 } 874 875 public List<String> getExceptions() { 876 return exceptions; 877 } 878 879 /** 880 * A set of exceptions to react upon. 881 */ 882 public void setExceptions(List<String> exceptions) { 883 this.exceptions = exceptions; 884 } 885 886 public Processor getErrorHandler(String routeId) { 887 return errorHandlers.get(routeId); 888 } 889 890 public Collection<Processor> getErrorHandlers() { 891 return errorHandlers.values(); 892 } 893 894 public RedeliveryPolicyDefinition getRedeliveryPolicy() { 895 return redeliveryPolicyType; 896 } 897 898 public void setRedeliveryPolicy(RedeliveryPolicyDefinition redeliveryPolicy) { 899 this.redeliveryPolicyType = redeliveryPolicy; 900 } 901 902 public RedeliveryPolicyDefinition getRedeliveryPolicyType() { 903 return redeliveryPolicyType; 904 } 905 906 public void setRedeliveryPolicyType(RedeliveryPolicyDefinition redeliveryPolicyType) { 907 this.redeliveryPolicyType = redeliveryPolicyType; 908 } 909 910 public String getRedeliveryPolicyRef() { 911 return redeliveryPolicyRef; 912 } 913 914 public void setRedeliveryPolicyRef(String redeliveryPolicyRef) { 915 this.redeliveryPolicyRef = redeliveryPolicyRef; 916 } 917 918 public Predicate getHandledPolicy() { 919 return handledPolicy; 920 } 921 922 public void setHandled(ExpressionSubElementDefinition handled) { 923 this.handled = handled; 924 } 925 926 public ExpressionSubElementDefinition getContinued() { 927 return continued; 928 } 929 930 public void setContinued(ExpressionSubElementDefinition continued) { 931 this.continued = continued; 932 } 933 934 public ExpressionSubElementDefinition getHandled() { 935 return handled; 936 } 937 938 public void setHandledPolicy(Predicate handledPolicy) { 939 this.handledPolicy = handledPolicy; 940 } 941 942 public Predicate getContinuedPolicy() { 943 return continuedPolicy; 944 } 945 946 public void setContinuedPolicy(Predicate continuedPolicy) { 947 this.continuedPolicy = continuedPolicy; 948 } 949 950 public WhenDefinition getOnWhen() { 951 return onWhen; 952 } 953 954 public void setOnWhen(WhenDefinition onWhen) { 955 this.onWhen = onWhen; 956 } 957 958 public ExpressionSubElementDefinition getRetryWhile() { 959 return retryWhile; 960 } 961 962 public void setRetryWhile(ExpressionSubElementDefinition retryWhile) { 963 this.retryWhile = retryWhile; 964 } 965 966 public Predicate getRetryWhilePolicy() { 967 return retryWhilePolicy; 968 } 969 970 public void setRetryWhilePolicy(Predicate retryWhilePolicy) { 971 this.retryWhilePolicy = retryWhilePolicy; 972 } 973 974 public Processor getOnRedelivery() { 975 return onRedelivery; 976 } 977 978 public void setOnRedelivery(Processor onRedelivery) { 979 this.onRedelivery = onRedelivery; 980 } 981 982 public String getOnRedeliveryRef() { 983 return onRedeliveryRef; 984 } 985 986 public void setOnRedeliveryRef(String onRedeliveryRef) { 987 this.onRedeliveryRef = onRedeliveryRef; 988 } 989 990 public Processor getOnExceptionOccurred() { 991 return onExceptionOccurred; 992 } 993 994 public void setOnExceptionOccurred(Processor onExceptionOccurred) { 995 this.onExceptionOccurred = onExceptionOccurred; 996 } 997 998 public String getOnExceptionOccurredRef() { 999 return onExceptionOccurredRef; 1000 } 1001 1002 public void setOnExceptionOccurredRef(String onExceptionOccurredRef) { 1003 this.onExceptionOccurredRef = onExceptionOccurredRef; 1004 } 1005 1006 public Boolean getUseOriginalMessagePolicy() { 1007 return useOriginalMessagePolicy; 1008 } 1009 1010 public void setUseOriginalMessagePolicy(Boolean useOriginalMessagePolicy) { 1011 this.useOriginalMessagePolicy = useOriginalMessagePolicy; 1012 } 1013 1014 // Implementation methods 1015 //------------------------------------------------------------------------- 1016 1017 protected boolean isAsyncDelayedRedelivery(CamelContext context) { 1018 if (getRedeliveryPolicy() != null) { 1019 return getRedeliveryPolicy().isAsyncDelayedRedelivery(context); 1020 } 1021 return false; 1022 } 1023 1024 protected RedeliveryPolicyDefinition getOrCreateRedeliveryPolicy() { 1025 if (redeliveryPolicyType == null) { 1026 redeliveryPolicyType = new RedeliveryPolicyDefinition(); 1027 } 1028 return redeliveryPolicyType; 1029 } 1030 1031 protected List<Class<? extends Throwable>> createExceptionClasses(ClassResolver resolver) throws ClassNotFoundException { 1032 List<String> list = getExceptions(); 1033 List<Class<? extends Throwable>> answer = new ArrayList<Class<? extends Throwable>>(list.size()); 1034 for (String name : list) { 1035 Class<? extends Throwable> type = resolver.resolveMandatoryClass(name, Throwable.class); 1036 answer.add(type); 1037 } 1038 return answer; 1039 } 1040 1041 private void setHandledFromExpressionType(RouteContext routeContext) { 1042 if (getHandled() != null && handledPolicy == null && routeContext != null) { 1043 handled(getHandled().createPredicate(routeContext)); 1044 } 1045 } 1046 1047 private void setContinuedFromExpressionType(RouteContext routeContext) { 1048 if (getContinued() != null && continuedPolicy == null && routeContext != null) { 1049 continued(getContinued().createPredicate(routeContext)); 1050 } 1051 } 1052 1053 private void setRetryWhileFromExpressionType(RouteContext routeContext) { 1054 if (getRetryWhile() != null && retryWhilePolicy == null && routeContext != null) { 1055 retryWhile(getRetryWhile().createPredicate(routeContext)); 1056 } 1057 } 1058 1059 private void setOnRedeliveryFromRedeliveryRef(RouteContext routeContext) { 1060 // lookup onRedelivery if ref is provided 1061 if (ObjectHelper.isNotEmpty(onRedeliveryRef)) { 1062 // if ref is provided then use mandatory lookup to fail if not found 1063 Processor onRedelivery = CamelContextHelper.mandatoryLookup(routeContext.getCamelContext(), onRedeliveryRef, Processor.class); 1064 setOnRedelivery(onRedelivery); 1065 } 1066 } 1067 1068 private void setOnExceptionOccurredFromOnExceptionOccurredRef(RouteContext routeContext) { 1069 // lookup onRedelivery if ref is provided 1070 if (ObjectHelper.isNotEmpty(onExceptionOccurredRef)) { 1071 // if ref is provided then use mandatory lookup to fail if not found 1072 Processor onExceptionOccurred = CamelContextHelper.mandatoryLookup(routeContext.getCamelContext(), onExceptionOccurredRef, Processor.class); 1073 setOnExceptionOccurred(onExceptionOccurred); 1074 } 1075 } 1076 1077}