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