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 public void setRedeliveryPolicyType(RedeliveryPolicyDefinition redeliveryPolicyType) { 896 this.redeliveryPolicyType = redeliveryPolicyType; 897 } 898 899 public String getRedeliveryPolicyRef() { 900 return redeliveryPolicyRef; 901 } 902 903 public void setRedeliveryPolicyRef(String redeliveryPolicyRef) { 904 this.redeliveryPolicyRef = redeliveryPolicyRef; 905 } 906 907 public Predicate getHandledPolicy() { 908 return handledPolicy; 909 } 910 911 public void setHandled(ExpressionSubElementDefinition handled) { 912 this.handled = handled; 913 } 914 915 public ExpressionSubElementDefinition getContinued() { 916 return continued; 917 } 918 919 public void setContinued(ExpressionSubElementDefinition continued) { 920 this.continued = continued; 921 } 922 923 public ExpressionSubElementDefinition getHandled() { 924 return handled; 925 } 926 927 public void setHandledPolicy(Predicate handledPolicy) { 928 this.handledPolicy = handledPolicy; 929 } 930 931 public Predicate getContinuedPolicy() { 932 return continuedPolicy; 933 } 934 935 public void setContinuedPolicy(Predicate continuedPolicy) { 936 this.continuedPolicy = continuedPolicy; 937 } 938 939 public WhenDefinition getOnWhen() { 940 return onWhen; 941 } 942 943 public void setOnWhen(WhenDefinition onWhen) { 944 this.onWhen = onWhen; 945 } 946 947 public ExpressionSubElementDefinition getRetryWhile() { 948 return retryWhile; 949 } 950 951 public void setRetryWhile(ExpressionSubElementDefinition retryWhile) { 952 this.retryWhile = retryWhile; 953 } 954 955 public Predicate getRetryWhilePolicy() { 956 return retryWhilePolicy; 957 } 958 959 public void setRetryWhilePolicy(Predicate retryWhilePolicy) { 960 this.retryWhilePolicy = retryWhilePolicy; 961 } 962 963 public Processor getOnRedelivery() { 964 return onRedelivery; 965 } 966 967 public void setOnRedelivery(Processor onRedelivery) { 968 this.onRedelivery = onRedelivery; 969 } 970 971 public String getOnRedeliveryRef() { 972 return onRedeliveryRef; 973 } 974 975 public void setOnRedeliveryRef(String onRedeliveryRef) { 976 this.onRedeliveryRef = onRedeliveryRef; 977 } 978 979 public Processor getOnExceptionOccurred() { 980 return onExceptionOccurred; 981 } 982 983 public void setOnExceptionOccurred(Processor onExceptionOccurred) { 984 this.onExceptionOccurred = onExceptionOccurred; 985 } 986 987 public String getOnExceptionOccurredRef() { 988 return onExceptionOccurredRef; 989 } 990 991 public void setOnExceptionOccurredRef(String onExceptionOccurredRef) { 992 this.onExceptionOccurredRef = onExceptionOccurredRef; 993 } 994 995 public Boolean getUseOriginalMessagePolicy() { 996 return useOriginalMessagePolicy; 997 } 998 999 public void setUseOriginalMessagePolicy(Boolean useOriginalMessagePolicy) { 1000 this.useOriginalMessagePolicy = useOriginalMessagePolicy; 1001 } 1002 1003 // Implementation methods 1004 //------------------------------------------------------------------------- 1005 1006 protected boolean isAsyncDelayedRedelivery(CamelContext context) { 1007 if (getRedeliveryPolicy() != null) { 1008 return getRedeliveryPolicy().isAsyncDelayedRedelivery(context); 1009 } 1010 return false; 1011 } 1012 1013 protected RedeliveryPolicyDefinition getOrCreateRedeliveryPolicy() { 1014 if (redeliveryPolicyType == null) { 1015 redeliveryPolicyType = new RedeliveryPolicyDefinition(); 1016 } 1017 return redeliveryPolicyType; 1018 } 1019 1020 protected List<Class<? extends Throwable>> createExceptionClasses(ClassResolver resolver) throws ClassNotFoundException { 1021 List<String> list = getExceptions(); 1022 List<Class<? extends Throwable>> answer = new ArrayList<>(list.size()); 1023 for (String name : list) { 1024 Class<? extends Throwable> type = resolver.resolveMandatoryClass(name, Throwable.class); 1025 answer.add(type); 1026 } 1027 return answer; 1028 } 1029 1030 private void setHandledFromExpressionType(RouteContext routeContext) { 1031 if (getHandled() != null && handledPolicy == null && routeContext != null) { 1032 handled(getHandled().createPredicate(routeContext)); 1033 } 1034 } 1035 1036 private void setContinuedFromExpressionType(RouteContext routeContext) { 1037 if (getContinued() != null && continuedPolicy == null && routeContext != null) { 1038 continued(getContinued().createPredicate(routeContext)); 1039 } 1040 } 1041 1042 private void setRetryWhileFromExpressionType(RouteContext routeContext) { 1043 if (getRetryWhile() != null && retryWhilePolicy == null && routeContext != null) { 1044 retryWhile(getRetryWhile().createPredicate(routeContext)); 1045 } 1046 } 1047 1048 private void setOnRedeliveryFromRedeliveryRef(RouteContext routeContext) { 1049 // lookup onRedelivery if ref is provided 1050 if (ObjectHelper.isNotEmpty(onRedeliveryRef)) { 1051 // if ref is provided then use mandatory lookup to fail if not found 1052 Processor onRedelivery = CamelContextHelper.mandatoryLookup(routeContext.getCamelContext(), onRedeliveryRef, Processor.class); 1053 setOnRedelivery(onRedelivery); 1054 } 1055 } 1056 1057 private void setOnExceptionOccurredFromOnExceptionOccurredRef(RouteContext routeContext) { 1058 // lookup onRedelivery if ref is provided 1059 if (ObjectHelper.isNotEmpty(onExceptionOccurredRef)) { 1060 // if ref is provided then use mandatory lookup to fail if not found 1061 Processor onExceptionOccurred = CamelContextHelper.mandatoryLookup(routeContext.getCamelContext(), onExceptionOccurredRef, Processor.class); 1062 setOnExceptionOccurred(onExceptionOccurred); 1063 } 1064 } 1065 1066}