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<>(); 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<>(); 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<>(); 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<>(); 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(() -> new IllegalArgumentException(this + " is not configured.")); 276 } 277 } 278 279 // Fluent API 280 //------------------------------------------------------------------------- 281 282 @Override 283 public OnExceptionDefinition onException(Class<? extends Throwable> exceptionType) { 284 getExceptionClasses().add(exceptionType); 285 return this; 286 } 287 288 /** 289 * Sets whether the exchange should be marked as handled or not. 290 * 291 * @param handled handled or not 292 * @return the builder 293 */ 294 public OnExceptionDefinition handled(boolean handled) { 295 Expression expression = ExpressionBuilder.constantExpression(Boolean.toString(handled)); 296 return handled(expression); 297 } 298 299 /** 300 * Sets whether the exchange should be marked as handled or not. 301 * 302 * @param handled predicate that determines true or false 303 * @return the builder 304 */ 305 public OnExceptionDefinition handled(@AsPredicate Predicate handled) { 306 setHandledPolicy(handled); 307 return this; 308 } 309 310 /** 311 * Sets whether the exchange should be marked as handled or not. 312 * 313 * @param handled expression that determines true or false 314 * @return the builder 315 */ 316 public OnExceptionDefinition handled(@AsPredicate Expression handled) { 317 setHandledPolicy(ExpressionToPredicateAdapter.toPredicate(handled)); 318 return this; 319 } 320 321 /** 322 * Sets whether the exchange should handle and continue routing from the point of failure. 323 * <p/> 324 * If this option is enabled then its considered handled as well. 325 * 326 * @param continued continued or not 327 * @return the builder 328 */ 329 public OnExceptionDefinition continued(boolean continued) { 330 Expression expression = ExpressionBuilder.constantExpression(Boolean.toString(continued)); 331 return continued(expression); 332 } 333 334 /** 335 * Sets whether the exchange should be marked as handled or not. 336 * <p/> 337 * If this option is enabled then its considered handled as well. 338 * 339 * @param continued predicate that determines true or false 340 * @return the builder 341 */ 342 public OnExceptionDefinition continued(@AsPredicate Predicate continued) { 343 setContinuedPolicy(continued); 344 return this; 345 } 346 347 /** 348 * Sets whether the exchange should be marked as handled or not. 349 * <p/> 350 * If this option is enabled then its considered handled as well. 351 * 352 * @param continued expression that determines true or false 353 * @return the builder 354 */ 355 public OnExceptionDefinition continued(@AsPredicate Expression continued) { 356 setContinuedPolicy(ExpressionToPredicateAdapter.toPredicate(continued)); 357 return this; 358 } 359 360 /** 361 * Sets an additional predicate that should be true before the onException is triggered. 362 * <p/> 363 * To be used for fine grained controlling whether a thrown exception should be intercepted 364 * by this exception type or not. 365 * 366 * @param predicate predicate that determines true or false 367 * @return the builder 368 */ 369 public OnExceptionDefinition onWhen(@AsPredicate Predicate predicate) { 370 setOnWhen(new WhenDefinition(predicate)); 371 return this; 372 } 373 374 /** 375 * Sets the retry while predicate. 376 * <p/> 377 * Will continue retrying until predicate returns <tt>false</tt>. 378 * 379 * @param retryWhile predicate that determines when to stop retrying 380 * @return the builder 381 */ 382 public OnExceptionDefinition retryWhile(@AsPredicate Predicate retryWhile) { 383 setRetryWhilePolicy(retryWhile); 384 return this; 385 } 386 387 /** 388 * Sets the initial redelivery delay 389 * 390 * @param delay the initial redelivery delay 391 * @return the builder 392 * @deprecated will be removed in the near future. Instead use {@link #redeliveryDelay(String)} 393 */ 394 @Deprecated 395 public OnExceptionDefinition redeliverDelay(long delay) { 396 getOrCreateRedeliveryPolicy().redeliveryDelay(delay); 397 return this; 398 } 399 400 /** 401 * Sets the back off multiplier 402 * 403 * @param backOffMultiplier the back off multiplier 404 * @return the builder 405 */ 406 public OnExceptionDefinition backOffMultiplier(double backOffMultiplier) { 407 getOrCreateRedeliveryPolicy().useExponentialBackOff(); 408 getOrCreateRedeliveryPolicy().backOffMultiplier(backOffMultiplier); 409 return this; 410 } 411 412 /** 413 * Sets the back off multiplier (supports property placeholders) 414 * 415 * @param backOffMultiplier the back off multiplier 416 * @return the builder 417 */ 418 public OnExceptionDefinition backOffMultiplier(String backOffMultiplier) { 419 getOrCreateRedeliveryPolicy().useExponentialBackOff(); 420 getOrCreateRedeliveryPolicy().backOffMultiplier(backOffMultiplier); 421 return this; 422 } 423 424 /** 425 * Sets the collision avoidance factor 426 * 427 * @param collisionAvoidanceFactor the factor 428 * @return the builder 429 */ 430 public OnExceptionDefinition collisionAvoidanceFactor(double collisionAvoidanceFactor) { 431 getOrCreateRedeliveryPolicy().useCollisionAvoidance(); 432 getOrCreateRedeliveryPolicy().collisionAvoidanceFactor(collisionAvoidanceFactor); 433 return this; 434 } 435 436 /** 437 * Sets the collision avoidance factor (supports property placeholders) 438 * 439 * @param collisionAvoidanceFactor the factor 440 * @return the builder 441 */ 442 public OnExceptionDefinition collisionAvoidanceFactor(String collisionAvoidanceFactor) { 443 getOrCreateRedeliveryPolicy().useCollisionAvoidance(); 444 getOrCreateRedeliveryPolicy().collisionAvoidanceFactor(collisionAvoidanceFactor); 445 return this; 446 } 447 448 /** 449 * Sets the collision avoidance percentage 450 * 451 * @param collisionAvoidancePercent the percentage 452 * @return the builder 453 */ 454 public OnExceptionDefinition collisionAvoidancePercent(double collisionAvoidancePercent) { 455 getOrCreateRedeliveryPolicy().useCollisionAvoidance(); 456 getOrCreateRedeliveryPolicy().collisionAvoidancePercent(collisionAvoidancePercent); 457 return this; 458 } 459 460 /** 461 * Sets the initial redelivery delay 462 * 463 * @param delay delay in millis 464 * @return the builder 465 */ 466 public OnExceptionDefinition redeliveryDelay(long delay) { 467 getOrCreateRedeliveryPolicy().redeliveryDelay(delay); 468 return this; 469 } 470 471 /** 472 * Sets the initial redelivery delay (supports property placeholders) 473 * 474 * @param delay delay in millis 475 * @return the builder 476 */ 477 public OnExceptionDefinition redeliveryDelay(String delay) { 478 getOrCreateRedeliveryPolicy().redeliveryDelay(delay); 479 return this; 480 } 481 482 /** 483 * Allow synchronous delayed redelivery. 484 * 485 * @see org.apache.camel.processor.RedeliveryPolicy#setAsyncDelayedRedelivery(boolean) 486 * @return the builder 487 */ 488 public OnExceptionDefinition asyncDelayedRedelivery() { 489 getOrCreateRedeliveryPolicy().asyncDelayedRedelivery(); 490 return this; 491 } 492 493 /** 494 * Sets the logging level to use when retries has exhausted 495 * 496 * @param retriesExhaustedLogLevel the logging level 497 * @return the builder 498 */ 499 public OnExceptionDefinition retriesExhaustedLogLevel(LoggingLevel retriesExhaustedLogLevel) { 500 getOrCreateRedeliveryPolicy().retriesExhaustedLogLevel(retriesExhaustedLogLevel); 501 return this; 502 } 503 504 /** 505 * Sets the logging level to use for logging retry attempts 506 * 507 * @param retryAttemptedLogLevel the logging level 508 * @return the builder 509 */ 510 public OnExceptionDefinition retryAttemptedLogLevel(LoggingLevel retryAttemptedLogLevel) { 511 getOrCreateRedeliveryPolicy().retryAttemptedLogLevel(retryAttemptedLogLevel); 512 return this; 513 } 514 515 /** 516 * Sets whether to log stacktrace for failed messages. 517 */ 518 public OnExceptionDefinition logStackTrace(boolean logStackTrace) { 519 getOrCreateRedeliveryPolicy().logStackTrace(logStackTrace); 520 return this; 521 } 522 523 /** 524 * Sets whether to log stacktrace for failed messages (supports property placeholders) 525 */ 526 public OnExceptionDefinition logStackTrace(String logStackTrace) { 527 getOrCreateRedeliveryPolicy().logStackTrace(logStackTrace); 528 return this; 529 } 530 531 /** 532 * Sets whether to log stacktrace for failed redelivery attempts 533 */ 534 public OnExceptionDefinition logRetryStackTrace(boolean logRetryStackTrace) { 535 getOrCreateRedeliveryPolicy().logRetryStackTrace(logRetryStackTrace); 536 return this; 537 } 538 539 /** 540 * Sets whether to log stacktrace for failed redelivery attempts (supports property placeholders) 541 */ 542 public OnExceptionDefinition logRetryStackTrace(String logRetryStackTrace) { 543 getOrCreateRedeliveryPolicy().logRetryStackTrace(logRetryStackTrace); 544 return this; 545 } 546 547 /** 548 * Sets whether to log errors even if its handled 549 */ 550 public OnExceptionDefinition logHandled(boolean logHandled) { 551 getOrCreateRedeliveryPolicy().logHandled(logHandled); 552 return this; 553 } 554 555 /** 556 * Sets whether to log errors even if its handled (supports property placeholders) 557 */ 558 public OnExceptionDefinition logHandled(String logHandled) { 559 getOrCreateRedeliveryPolicy().logHandled(logHandled); 560 return this; 561 } 562 563 /** 564 * Sets whether new exceptions should be logged or not (supports property placeholders). 565 * Can be used to include or reduce verbose. 566 * <p/> 567 * A new exception is an exception that was thrown while handling a previous exception. 568 */ 569 public OnExceptionDefinition logNewException(boolean logNewException) { 570 getOrCreateRedeliveryPolicy().logNewException(logNewException); 571 return this; 572 } 573 574 /** 575 * Sets whether new exceptions should be logged or not (supports property placeholders). 576 * Can be used to include or reduce verbose. 577 * <p/> 578 * A new exception is an exception that was thrown while handling a previous exception. 579 */ 580 public OnExceptionDefinition logNewException(String logNewException) { 581 getOrCreateRedeliveryPolicy().logNewException(logNewException); 582 return this; 583 } 584 585 /** 586 * Sets whether to log errors even if its continued 587 */ 588 public OnExceptionDefinition logContinued(boolean logContinued) { 589 getOrCreateRedeliveryPolicy().logContinued(logContinued); 590 return this; 591 } 592 593 /** 594 * Sets whether to log errors even if its continued (supports property placeholders) 595 */ 596 public OnExceptionDefinition logContinued(String logContinued) { 597 getOrCreateRedeliveryPolicy().logContinued(logContinued); 598 return this; 599 } 600 601 /** 602 * Sets whether to log retry attempts 603 */ 604 public OnExceptionDefinition logRetryAttempted(boolean logRetryAttempted) { 605 getOrCreateRedeliveryPolicy().logRetryAttempted(logRetryAttempted); 606 return this; 607 } 608 609 /** 610 * Sets whether to log retry attempts (supports property placeholders) 611 */ 612 public OnExceptionDefinition logRetryAttempted(String logRetryAttempted) { 613 getOrCreateRedeliveryPolicy().logRetryAttempted(logRetryAttempted); 614 return this; 615 } 616 617 /** 618 * Sets whether to log exhausted exceptions 619 */ 620 public OnExceptionDefinition logExhausted(boolean logExhausted) { 621 getOrCreateRedeliveryPolicy().logExhausted(logExhausted); 622 return this; 623 } 624 625 /** 626 * Sets whether to log exhausted exceptions (supports property placeholders) 627 */ 628 public OnExceptionDefinition logExhausted(String logExhausted) { 629 getOrCreateRedeliveryPolicy().logExhausted(logExhausted); 630 return this; 631 } 632 633 /** 634 * Sets whether to log exhausted exceptions with message history 635 */ 636 public OnExceptionDefinition logExhaustedMessageHistory(boolean logExhaustedMessageHistory) { 637 getOrCreateRedeliveryPolicy().logExhaustedMessageHistory(logExhaustedMessageHistory); 638 return this; 639 } 640 641 /** 642 * Sets whether to log exhausted exceptions with message history 643 */ 644 public OnExceptionDefinition logExhaustedMessageHistory(String logExhaustedMessageHistory) { 645 getOrCreateRedeliveryPolicy().logExhaustedMessageHistory(logExhaustedMessageHistory); 646 return this; 647 } 648 649 /** 650 * Sets whether to log exhausted message body with message history. 651 * Requires <tt>logExhaustedMessageHistory</tt> to be enabled. 652 */ 653 public OnExceptionDefinition logExhaustedMessageBody(boolean logExhaustedMessageBody) { 654 getOrCreateRedeliveryPolicy().logExhaustedMessageBody(logExhaustedMessageBody); 655 return this; 656 } 657 658 /** 659 * Sets whether to log exhausted message body with message history. 660 * Requires <tt>logExhaustedMessageHistory</tt> to be enabled. 661 */ 662 public OnExceptionDefinition logExhaustedMessageBody(String logExhaustedMessageBody) { 663 getOrCreateRedeliveryPolicy().logExhaustedMessageBody(logExhaustedMessageBody); 664 return this; 665 } 666 667 /** 668 * Sets the maximum redeliveries 669 * <ul> 670 * <li>5 = default value</li> 671 * <li>0 = no redeliveries</li> 672 * <li>-1 = redeliver forever</li> 673 * </ul> 674 * 675 * @param maximumRedeliveries the value 676 * @return the builder 677 */ 678 public OnExceptionDefinition maximumRedeliveries(int maximumRedeliveries) { 679 getOrCreateRedeliveryPolicy().maximumRedeliveries(maximumRedeliveries); 680 return this; 681 } 682 683 /** 684 * Sets the maximum redeliveries (supports property placeholders) 685 * <ul> 686 * <li>5 = default value</li> 687 * <li>0 = no redeliveries</li> 688 * <li>-1 = redeliver forever</li> 689 * </ul> 690 * 691 * @param maximumRedeliveries the value 692 * @return the builder 693 */ 694 public OnExceptionDefinition maximumRedeliveries(String maximumRedeliveries) { 695 getOrCreateRedeliveryPolicy().maximumRedeliveries(maximumRedeliveries); 696 return this; 697 } 698 699 /** 700 * Turn on collision avoidance. 701 * 702 * @return the builder 703 */ 704 public OnExceptionDefinition useCollisionAvoidance() { 705 getOrCreateRedeliveryPolicy().useCollisionAvoidance(); 706 return this; 707 } 708 709 /** 710 * Turn on exponential back off 711 * 712 * @return the builder 713 */ 714 public OnExceptionDefinition useExponentialBackOff() { 715 getOrCreateRedeliveryPolicy().useExponentialBackOff(); 716 return this; 717 } 718 719 /** 720 * Sets the maximum delay between redelivery 721 * 722 * @param maximumRedeliveryDelay the delay in millis 723 * @return the builder 724 */ 725 public OnExceptionDefinition maximumRedeliveryDelay(long maximumRedeliveryDelay) { 726 getOrCreateRedeliveryPolicy().maximumRedeliveryDelay(maximumRedeliveryDelay); 727 return this; 728 } 729 730 /** 731 * Sets the maximum delay between redelivery (supports property placeholders) 732 * 733 * @param maximumRedeliveryDelay the delay in millis 734 * @return the builder 735 */ 736 public OnExceptionDefinition maximumRedeliveryDelay(String maximumRedeliveryDelay) { 737 getOrCreateRedeliveryPolicy().maximumRedeliveryDelay(maximumRedeliveryDelay); 738 return this; 739 } 740 741 /** 742 * Set the {@link RedeliveryPolicy} to be used. 743 * 744 * @param redeliveryPolicy the redelivery policy 745 * @return the builder 746 */ 747 public OnExceptionDefinition redeliveryPolicy(RedeliveryPolicy redeliveryPolicy) { 748 this.redeliveryPolicy = redeliveryPolicy; 749 return this; 750 } 751 752 /** 753 * Sets a reference to a {@link RedeliveryPolicy} to lookup in the {@link org.apache.camel.spi.Registry} to be used. 754 * 755 * @param redeliveryPolicyRef reference to use for lookup 756 * @return the builder 757 */ 758 public OnExceptionDefinition redeliveryPolicyRef(String redeliveryPolicyRef) { 759 setRedeliveryPolicyRef(redeliveryPolicyRef); 760 return this; 761 } 762 763 /** 764 * Sets the delay pattern with delay intervals. 765 * 766 * @param delayPattern the delay pattern 767 * @return the builder 768 */ 769 public OnExceptionDefinition delayPattern(String delayPattern) { 770 getOrCreateRedeliveryPolicy().setDelayPattern(delayPattern); 771 return this; 772 } 773 774 /** 775 * @deprecated this method will be removed in Camel 3.0, please use {@link #useOriginalMessage()} 776 * @see #useOriginalMessage() 777 */ 778 @Deprecated 779 public OnExceptionDefinition useOriginalBody() { 780 setUseOriginalMessagePolicy(Boolean.TRUE); 781 return this; 782 } 783 784 /** 785 * Will use the original input message when an {@link org.apache.camel.Exchange} is moved to the dead letter queue. 786 * <p/> 787 * <b>Notice:</b> this only applies when all redeliveries attempt have failed and the {@link org.apache.camel.Exchange} is doomed for failure. 788 * <br/> 789 * Instead of using the current in-progress {@link org.apache.camel.Exchange} IN body we use the original IN body instead. This allows 790 * you to store the original input in the dead letter queue instead of the in-progress snapshot of the IN body. 791 * For instance if you route transform the IN body during routing and then failed. With the original exchange 792 * 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 793 * 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. 794 * <p/> 795 * By default this feature is off. 796 * 797 * @return the builder 798 */ 799 public OnExceptionDefinition useOriginalMessage() { 800 setUseOriginalMessagePolicy(Boolean.TRUE); 801 return this; 802 } 803 804 /** 805 * Sets a processor that should be processed <b>before</b> a redelivery attempt. 806 * <p/> 807 * Can be used to change the {@link org.apache.camel.Exchange} <b>before</b> its being redelivered. 808 */ 809 public OnExceptionDefinition onRedelivery(Processor processor) { 810 setOnRedelivery(processor); 811 return this; 812 } 813 814 /** 815 * Sets a reference to a processor that should be processed <b>before</b> a redelivery attempt. 816 * <p/> 817 * Can be used to change the {@link org.apache.camel.Exchange} <b>before</b> its being redelivered. 818 * 819 * @param ref reference to the processor 820 */ 821 public OnExceptionDefinition onRedeliveryRef(String ref) { 822 setOnRedeliveryRef(ref); 823 return this; 824 } 825 826 /** 827 * Sets a processor that should be processed <b>just after</b> an exception occurred. 828 * Can be used to perform custom logging about the occurred exception at the exact time it happened. 829 * <p/> 830 * Important: Any exception thrown from this processor will be ignored. 831 */ 832 public OnExceptionDefinition onExceptionOccurred(Processor processor) { 833 setOnExceptionOccurred(processor); 834 return this; 835 } 836 837 /** 838 * Sets a reference to a processor that should be processed <b>just after</b> an exception occurred. 839 * Can be used to perform custom logging about the occurred exception at the exact time it happened. 840 * <p/> 841 * Important: Any exception thrown from this processor will be ignored. 842 * 843 * @param ref reference to the processor 844 */ 845 public OnExceptionDefinition onExceptionOccurredRef(String ref) { 846 setOnExceptionOccurredRef(ref); 847 return this; 848 } 849 850 // Properties 851 //------------------------------------------------------------------------- 852 @Override 853 public List<ProcessorDefinition<?>> getOutputs() { 854 return outputs; 855 } 856 857 public void setOutputs(List<ProcessorDefinition<?>> outputs) { 858 this.outputs = outputs; 859 } 860 861 public boolean isOutputSupported() { 862 return true; 863 } 864 865 public List<Class<? extends Throwable>> getExceptionClasses() { 866 return exceptionClasses; 867 } 868 869 public void setExceptionClasses(List<Class<? extends Throwable>> exceptionClasses) { 870 this.exceptionClasses = exceptionClasses; 871 } 872 873 public List<String> getExceptions() { 874 return exceptions; 875 } 876 877 /** 878 * A set of exceptions to react upon. 879 */ 880 public void setExceptions(List<String> exceptions) { 881 this.exceptions = exceptions; 882 } 883 884 public Processor getErrorHandler(String routeId) { 885 return errorHandlers.get(routeId); 886 } 887 888 public Collection<Processor> getErrorHandlers() { 889 return errorHandlers.values(); 890 } 891 892 public RedeliveryPolicyDefinition getRedeliveryPolicy() { 893 return redeliveryPolicyType; 894 } 895 896 public void setRedeliveryPolicy(RedeliveryPolicyDefinition redeliveryPolicy) { 897 this.redeliveryPolicyType = redeliveryPolicy; 898 } 899 900 public RedeliveryPolicyDefinition getRedeliveryPolicyType() { 901 return redeliveryPolicyType; 902 } 903 904 public void setRedeliveryPolicyType(RedeliveryPolicyDefinition redeliveryPolicyType) { 905 this.redeliveryPolicyType = redeliveryPolicyType; 906 } 907 908 public String getRedeliveryPolicyRef() { 909 return redeliveryPolicyRef; 910 } 911 912 public void setRedeliveryPolicyRef(String redeliveryPolicyRef) { 913 this.redeliveryPolicyRef = redeliveryPolicyRef; 914 } 915 916 public Predicate getHandledPolicy() { 917 return handledPolicy; 918 } 919 920 public void setHandled(ExpressionSubElementDefinition handled) { 921 this.handled = handled; 922 } 923 924 public ExpressionSubElementDefinition getContinued() { 925 return continued; 926 } 927 928 public void setContinued(ExpressionSubElementDefinition continued) { 929 this.continued = continued; 930 } 931 932 public ExpressionSubElementDefinition getHandled() { 933 return handled; 934 } 935 936 public void setHandledPolicy(Predicate handledPolicy) { 937 this.handledPolicy = handledPolicy; 938 } 939 940 public Predicate getContinuedPolicy() { 941 return continuedPolicy; 942 } 943 944 public void setContinuedPolicy(Predicate continuedPolicy) { 945 this.continuedPolicy = continuedPolicy; 946 } 947 948 public WhenDefinition getOnWhen() { 949 return onWhen; 950 } 951 952 public void setOnWhen(WhenDefinition onWhen) { 953 this.onWhen = onWhen; 954 } 955 956 public ExpressionSubElementDefinition getRetryWhile() { 957 return retryWhile; 958 } 959 960 public void setRetryWhile(ExpressionSubElementDefinition retryWhile) { 961 this.retryWhile = retryWhile; 962 } 963 964 public Predicate getRetryWhilePolicy() { 965 return retryWhilePolicy; 966 } 967 968 public void setRetryWhilePolicy(Predicate retryWhilePolicy) { 969 this.retryWhilePolicy = retryWhilePolicy; 970 } 971 972 public Processor getOnRedelivery() { 973 return onRedelivery; 974 } 975 976 public void setOnRedelivery(Processor onRedelivery) { 977 this.onRedelivery = onRedelivery; 978 } 979 980 public String getOnRedeliveryRef() { 981 return onRedeliveryRef; 982 } 983 984 public void setOnRedeliveryRef(String onRedeliveryRef) { 985 this.onRedeliveryRef = onRedeliveryRef; 986 } 987 988 public Processor getOnExceptionOccurred() { 989 return onExceptionOccurred; 990 } 991 992 public void setOnExceptionOccurred(Processor onExceptionOccurred) { 993 this.onExceptionOccurred = onExceptionOccurred; 994 } 995 996 public String getOnExceptionOccurredRef() { 997 return onExceptionOccurredRef; 998 } 999 1000 public void setOnExceptionOccurredRef(String onExceptionOccurredRef) { 1001 this.onExceptionOccurredRef = onExceptionOccurredRef; 1002 } 1003 1004 public Boolean getUseOriginalMessagePolicy() { 1005 return useOriginalMessagePolicy; 1006 } 1007 1008 public void setUseOriginalMessagePolicy(Boolean useOriginalMessagePolicy) { 1009 this.useOriginalMessagePolicy = useOriginalMessagePolicy; 1010 } 1011 1012 // Implementation methods 1013 //------------------------------------------------------------------------- 1014 1015 protected boolean isAsyncDelayedRedelivery(CamelContext context) { 1016 if (getRedeliveryPolicy() != null) { 1017 return getRedeliveryPolicy().isAsyncDelayedRedelivery(context); 1018 } 1019 return false; 1020 } 1021 1022 protected RedeliveryPolicyDefinition getOrCreateRedeliveryPolicy() { 1023 if (redeliveryPolicyType == null) { 1024 redeliveryPolicyType = new RedeliveryPolicyDefinition(); 1025 } 1026 return redeliveryPolicyType; 1027 } 1028 1029 protected List<Class<? extends Throwable>> createExceptionClasses(ClassResolver resolver) throws ClassNotFoundException { 1030 List<String> list = getExceptions(); 1031 List<Class<? extends Throwable>> answer = new ArrayList<>(list.size()); 1032 for (String name : list) { 1033 Class<? extends Throwable> type = resolver.resolveMandatoryClass(name, Throwable.class); 1034 answer.add(type); 1035 } 1036 return answer; 1037 } 1038 1039 private void setHandledFromExpressionType(RouteContext routeContext) { 1040 if (getHandled() != null && handledPolicy == null && routeContext != null) { 1041 handled(getHandled().createPredicate(routeContext)); 1042 } 1043 } 1044 1045 private void setContinuedFromExpressionType(RouteContext routeContext) { 1046 if (getContinued() != null && continuedPolicy == null && routeContext != null) { 1047 continued(getContinued().createPredicate(routeContext)); 1048 } 1049 } 1050 1051 private void setRetryWhileFromExpressionType(RouteContext routeContext) { 1052 if (getRetryWhile() != null && retryWhilePolicy == null && routeContext != null) { 1053 retryWhile(getRetryWhile().createPredicate(routeContext)); 1054 } 1055 } 1056 1057 private void setOnRedeliveryFromRedeliveryRef(RouteContext routeContext) { 1058 // lookup onRedelivery if ref is provided 1059 if (ObjectHelper.isNotEmpty(onRedeliveryRef)) { 1060 // if ref is provided then use mandatory lookup to fail if not found 1061 Processor onRedelivery = CamelContextHelper.mandatoryLookup(routeContext.getCamelContext(), onRedeliveryRef, Processor.class); 1062 setOnRedelivery(onRedelivery); 1063 } 1064 } 1065 1066 private void setOnExceptionOccurredFromOnExceptionOccurredRef(RouteContext routeContext) { 1067 // lookup onRedelivery if ref is provided 1068 if (ObjectHelper.isNotEmpty(onExceptionOccurredRef)) { 1069 // if ref is provided then use mandatory lookup to fail if not found 1070 Processor onExceptionOccurred = CamelContextHelper.mandatoryLookup(routeContext.getCamelContext(), onExceptionOccurredRef, Processor.class); 1071 setOnExceptionOccurred(onExceptionOccurred); 1072 } 1073 } 1074 1075}