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