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