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