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.builder; 018 019import java.util.concurrent.ScheduledExecutorService; 020 021import org.apache.camel.CamelContext; 022import org.apache.camel.Endpoint; 023import org.apache.camel.Expression; 024import org.apache.camel.LoggingLevel; 025import org.apache.camel.Predicate; 026import org.apache.camel.Processor; 027import org.apache.camel.processor.DefaultErrorHandler; 028import org.apache.camel.processor.RedeliveryPolicy; 029import org.apache.camel.spi.ExecutorServiceManager; 030import org.apache.camel.spi.Language; 031import org.apache.camel.spi.RouteContext; 032import org.apache.camel.spi.ThreadPoolProfile; 033import org.apache.camel.util.CamelLogger; 034import org.apache.camel.util.ExpressionToPredicateAdapter; 035import org.slf4j.LoggerFactory; 036 037/** 038 * The default error handler builder. 039 * 040 * @version 041 */ 042public class DefaultErrorHandlerBuilder extends ErrorHandlerBuilderSupport { 043 044 protected CamelLogger logger; 045 protected RedeliveryPolicy redeliveryPolicy; 046 protected Processor onRedelivery; 047 protected Predicate retryWhile; 048 protected String retryWhileRef; 049 protected Processor failureProcessor; 050 protected Endpoint deadLetter; 051 protected String deadLetterUri; 052 protected boolean deadLetterHandleNewException = true; 053 protected boolean useOriginalMessage; 054 protected boolean asyncDelayedRedelivery; 055 protected String executorServiceRef; 056 protected ScheduledExecutorService executorService; 057 protected Processor onPrepareFailure; 058 protected Processor onExceptionOccurred; 059 060 public DefaultErrorHandlerBuilder() { 061 } 062 063 public Processor createErrorHandler(RouteContext routeContext, Processor processor) throws Exception { 064 DefaultErrorHandler answer = new DefaultErrorHandler(routeContext.getCamelContext(), processor, getLogger(), getOnRedelivery(), 065 getRedeliveryPolicy(), getExceptionPolicyStrategy(), getRetryWhilePolicy(routeContext.getCamelContext()), 066 getExecutorService(routeContext.getCamelContext()), getOnPrepareFailure(), getOnExceptionOccurred()); 067 // configure error handler before we can use it 068 configure(routeContext, answer); 069 return answer; 070 } 071 072 public boolean supportTransacted() { 073 return false; 074 } 075 076 @Override 077 public ErrorHandlerBuilder cloneBuilder() { 078 DefaultErrorHandlerBuilder answer = new DefaultErrorHandlerBuilder(); 079 cloneBuilder(answer); 080 return answer; 081 } 082 083 protected void cloneBuilder(DefaultErrorHandlerBuilder other) { 084 super.cloneBuilder(other); 085 086 if (logger != null) { 087 other.setLogger(logger); 088 } 089 if (redeliveryPolicy != null) { 090 other.setRedeliveryPolicy(redeliveryPolicy.copy()); 091 } 092 if (onRedelivery != null) { 093 other.setOnRedelivery(onRedelivery); 094 } 095 if (retryWhile != null) { 096 other.setRetryWhile(retryWhile); 097 } 098 if (retryWhileRef != null) { 099 other.setRetryWhileRef(retryWhileRef); 100 } 101 if (failureProcessor != null) { 102 other.setFailureProcessor(failureProcessor); 103 } 104 if (deadLetter != null) { 105 other.setDeadLetter(deadLetter); 106 } 107 if (deadLetterUri != null) { 108 other.setDeadLetterUri(deadLetterUri); 109 } 110 if (onPrepareFailure != null) { 111 other.setOnPrepareFailure(onPrepareFailure); 112 } 113 if (onExceptionOccurred != null) { 114 other.setOnExceptionOccurred(onExceptionOccurred); 115 } 116 other.setDeadLetterHandleNewException(deadLetterHandleNewException); 117 other.setUseOriginalMessage(useOriginalMessage); 118 other.setAsyncDelayedRedelivery(asyncDelayedRedelivery); 119 other.setExecutorServiceRef(executorServiceRef); 120 } 121 122 // Builder methods 123 // ------------------------------------------------------------------------- 124 public DefaultErrorHandlerBuilder backOffMultiplier(double backOffMultiplier) { 125 getRedeliveryPolicy().backOffMultiplier(backOffMultiplier); 126 return this; 127 } 128 129 public DefaultErrorHandlerBuilder collisionAvoidancePercent(double collisionAvoidancePercent) { 130 getRedeliveryPolicy().collisionAvoidancePercent(collisionAvoidancePercent); 131 return this; 132 } 133 134 /** 135 * @deprecated will be removed in the near future. Use {@link #redeliveryDelay(long)} instead 136 */ 137 @Deprecated 138 public DefaultErrorHandlerBuilder redeliverDelay(long delay) { 139 getRedeliveryPolicy().redeliveryDelay(delay); 140 return this; 141 } 142 143 public DefaultErrorHandlerBuilder redeliveryDelay(long delay) { 144 getRedeliveryPolicy().redeliveryDelay(delay); 145 return this; 146 } 147 148 public DefaultErrorHandlerBuilder delayPattern(String delayPattern) { 149 getRedeliveryPolicy().delayPattern(delayPattern); 150 return this; 151 } 152 153 public DefaultErrorHandlerBuilder maximumRedeliveries(int maximumRedeliveries) { 154 getRedeliveryPolicy().maximumRedeliveries(maximumRedeliveries); 155 return this; 156 } 157 158 public DefaultErrorHandlerBuilder disableRedelivery() { 159 getRedeliveryPolicy().maximumRedeliveries(0); 160 return this; 161 } 162 163 public DefaultErrorHandlerBuilder maximumRedeliveryDelay(long maximumRedeliveryDelay) { 164 getRedeliveryPolicy().maximumRedeliveryDelay(maximumRedeliveryDelay); 165 return this; 166 } 167 168 public DefaultErrorHandlerBuilder useCollisionAvoidance() { 169 getRedeliveryPolicy().useCollisionAvoidance(); 170 return this; 171 } 172 173 public DefaultErrorHandlerBuilder useExponentialBackOff() { 174 getRedeliveryPolicy().useExponentialBackOff(); 175 return this; 176 } 177 178 public DefaultErrorHandlerBuilder retriesExhaustedLogLevel(LoggingLevel retriesExhaustedLogLevel) { 179 getRedeliveryPolicy().setRetriesExhaustedLogLevel(retriesExhaustedLogLevel); 180 return this; 181 } 182 183 public DefaultErrorHandlerBuilder retryAttemptedLogLevel(LoggingLevel retryAttemptedLogLevel) { 184 getRedeliveryPolicy().setRetryAttemptedLogLevel(retryAttemptedLogLevel); 185 return this; 186 } 187 188 public DefaultErrorHandlerBuilder retryAttemptedLogInterval(int retryAttemptedLogInterval) { 189 getRedeliveryPolicy().setRetryAttemptedLogInterval(retryAttemptedLogInterval); 190 return this; 191 } 192 193 public DefaultErrorHandlerBuilder logStackTrace(boolean logStackTrace) { 194 getRedeliveryPolicy().setLogStackTrace(logStackTrace); 195 return this; 196 } 197 198 public DefaultErrorHandlerBuilder logRetryStackTrace(boolean logRetryStackTrace) { 199 getRedeliveryPolicy().setLogRetryStackTrace(logRetryStackTrace); 200 return this; 201 } 202 203 public DefaultErrorHandlerBuilder logHandled(boolean logHandled) { 204 getRedeliveryPolicy().setLogHandled(logHandled); 205 return this; 206 } 207 208 public DefaultErrorHandlerBuilder logNewException(boolean logNewException) { 209 getRedeliveryPolicy().setLogNewException(logNewException); 210 return this; 211 } 212 213 public DefaultErrorHandlerBuilder logExhausted(boolean logExhausted) { 214 getRedeliveryPolicy().setLogExhausted(logExhausted); 215 return this; 216 } 217 218 public DefaultErrorHandlerBuilder logRetryAttempted(boolean logRetryAttempted) { 219 getRedeliveryPolicy().setLogRetryAttempted(logRetryAttempted); 220 return this; 221 } 222 223 public DefaultErrorHandlerBuilder logExhaustedMessageHistory(boolean logExhaustedMessageHistory) { 224 getRedeliveryPolicy().setLogExhaustedMessageHistory(logExhaustedMessageHistory); 225 return this; 226 } 227 228 public DefaultErrorHandlerBuilder logExhaustedMessageBody(boolean logExhaustedMessageBody) { 229 getRedeliveryPolicy().setLogExhaustedMessageBody(logExhaustedMessageBody); 230 return this; 231 } 232 233 public DefaultErrorHandlerBuilder exchangeFormatterRef(String exchangeFormatterRef) { 234 getRedeliveryPolicy().setExchangeFormatterRef(exchangeFormatterRef); 235 return this; 236 } 237 238 /** 239 * Will allow asynchronous delayed redeliveries. The route, in particular the consumer's component, 240 * must support the Asynchronous Routing Engine (e.g. seda) 241 * 242 * @see org.apache.camel.processor.RedeliveryPolicy#setAsyncDelayedRedelivery(boolean) 243 * @return the builder 244 */ 245 public DefaultErrorHandlerBuilder asyncDelayedRedelivery() { 246 getRedeliveryPolicy().setAsyncDelayedRedelivery(true); 247 return this; 248 } 249 250 /** 251 * Controls whether to allow redelivery while stopping/shutting down a route that uses error handling. 252 * 253 * @param allowRedeliveryWhileStopping <tt>true</tt> to allow redelivery, <tt>false</tt> to reject redeliveries 254 * @return the builder 255 */ 256 public DefaultErrorHandlerBuilder allowRedeliveryWhileStopping(boolean allowRedeliveryWhileStopping) { 257 getRedeliveryPolicy().setAllowRedeliveryWhileStopping(allowRedeliveryWhileStopping); 258 return this; 259 } 260 261 /** 262 * Sets a reference to a thread pool to be used for redelivery. 263 * 264 * @param ref reference to a scheduled thread pool 265 * @return the builder. 266 */ 267 public DefaultErrorHandlerBuilder executorServiceRef(String ref) { 268 setExecutorServiceRef(ref); 269 return this; 270 } 271 272 /** 273 * Sets the logger used for caught exceptions 274 * 275 * @param logger the logger 276 * @return the builder 277 */ 278 public DefaultErrorHandlerBuilder logger(CamelLogger logger) { 279 setLogger(logger); 280 return this; 281 } 282 283 /** 284 * Sets the logging level of exceptions caught 285 * 286 * @param level the logging level 287 * @return the builder 288 */ 289 public DefaultErrorHandlerBuilder loggingLevel(LoggingLevel level) { 290 getLogger().setLevel(level); 291 return this; 292 } 293 294 /** 295 * Sets the log used for caught exceptions 296 * 297 * @param log the logger 298 * @return the builder 299 */ 300 public DefaultErrorHandlerBuilder log(org.slf4j.Logger log) { 301 getLogger().setLog(log); 302 return this; 303 } 304 305 /** 306 * Sets the log used for caught exceptions 307 * 308 * @param log the log name 309 * @return the builder 310 */ 311 public DefaultErrorHandlerBuilder log(String log) { 312 return log(LoggerFactory.getLogger(log)); 313 } 314 315 /** 316 * Sets the log used for caught exceptions 317 * 318 * @param log the log class 319 * @return the builder 320 */ 321 public DefaultErrorHandlerBuilder log(Class<?> log) { 322 return log(LoggerFactory.getLogger(log)); 323 } 324 325 /** 326 * Sets a processor that should be processed <b>before</b> a redelivery attempt. 327 * <p/> 328 * Can be used to change the {@link org.apache.camel.Exchange} <b>before</b> its being redelivered. 329 * 330 * @param processor the processor 331 * @return the builder 332 */ 333 public DefaultErrorHandlerBuilder onRedelivery(Processor processor) { 334 setOnRedelivery(processor); 335 return this; 336 } 337 338 /** 339 * Sets the retry while expression. 340 * <p/> 341 * Will continue retrying until expression evaluates to <tt>false</tt>. 342 * 343 * @param retryWhile expression that determines when to stop retrying 344 * @return the builder 345 */ 346 public DefaultErrorHandlerBuilder retryWhile(Expression retryWhile) { 347 setRetryWhile(ExpressionToPredicateAdapter.toPredicate(retryWhile)); 348 return this; 349 } 350 351 /** 352 * Will use the original input {@link org.apache.camel.Message} when an {@link org.apache.camel.Exchange} 353 * is moved to the dead letter queue. 354 * <p/> 355 * <b>Notice:</b> this only applies when all redeliveries attempt have failed and the {@link org.apache.camel.Exchange} 356 * is doomed for failure. 357 * <br/> 358 * Instead of using the current inprogress {@link org.apache.camel.Exchange} IN message we use the original 359 * IN message instead. This allows you to store the original input in the dead letter queue instead of the inprogress 360 * snapshot of the IN message. 361 * For instance if you route transform the IN body during routing and then failed. With the original exchange 362 * store in the dead letter queue it might be easier to manually re submit the {@link org.apache.camel.Exchange} 363 * again as the IN message is the same as when Camel received it. 364 * So you should be able to send the {@link org.apache.camel.Exchange} to the same input. 365 * <p/> 366 * By default this feature is off. 367 * 368 * @return the builder 369 */ 370 public DefaultErrorHandlerBuilder useOriginalMessage() { 371 setUseOriginalMessage(true); 372 return this; 373 } 374 375 /** 376 * Whether the dead letter channel should handle (and ignore) any new exception that may been thrown during sending the 377 * message to the dead letter endpoint. 378 * <p/> 379 * The default value is <tt>true</tt> which means any such kind of exception is handled and ignored. Set this to <tt>false</tt> 380 * to let the exception be propagated back on the {@link org.apache.camel.Exchange}. This can be used in situations 381 * where you use transactions, and want to use Camel's dead letter channel to deal with exceptions during routing, 382 * but if the dead letter channel itself fails because of a new exception being thrown, then by setting this to <tt>false</tt> 383 * the new exceptions is propagated back and set on the {@link org.apache.camel.Exchange}, which allows the transaction 384 * to detect the exception, and rollback. 385 * 386 * @param handleNewException <tt>true</tt> to handle (and ignore), <tt>false</tt> to catch and propagated the exception on the {@link org.apache.camel.Exchange} 387 * @return the builder 388 */ 389 public DefaultErrorHandlerBuilder deadLetterHandleNewException(boolean handleNewException) { 390 setDeadLetterHandleNewException(handleNewException); 391 return this; 392 } 393 394 /** 395 * @deprecated use {@link #deadLetterHandleNewException(boolean)}} with value <tt>false</tt> 396 */ 397 @Deprecated 398 public DefaultErrorHandlerBuilder checkException() { 399 setDeadLetterHandleNewException(false); 400 return this; 401 } 402 403 /** 404 * Sets a custom {@link org.apache.camel.Processor} to prepare the {@link org.apache.camel.Exchange} before 405 * handled by the failure processor / dead letter channel. This allows for example to enrich the message 406 * before sending to a dead letter queue. 407 * 408 * @param processor the processor 409 * @return the builder 410 */ 411 public DefaultErrorHandlerBuilder onPrepareFailure(Processor processor) { 412 setOnPrepareFailure(processor); 413 return this; 414 } 415 416 /** 417 * Sets a custom {@link org.apache.camel.Processor} to process the {@link org.apache.camel.Exchange} just after an exception was thrown. 418 * This allows to execute the processor at the same time the exception was thrown. 419 * <p/> 420 * Important: Any exception thrown from this processor will be ignored. 421 * 422 * @param processor the processor 423 * @return the builder 424 */ 425 public DefaultErrorHandlerBuilder onExceptionOccurred(Processor processor) { 426 setOnExceptionOccurred(processor); 427 return this; 428 } 429 430 // Properties 431 // ------------------------------------------------------------------------- 432 433 public Processor getFailureProcessor() { 434 return failureProcessor; 435 } 436 437 public void setFailureProcessor(Processor failureProcessor) { 438 this.failureProcessor = failureProcessor; 439 } 440 441 public RedeliveryPolicy getRedeliveryPolicy() { 442 if (redeliveryPolicy == null) { 443 redeliveryPolicy = createRedeliveryPolicy(); 444 } 445 return redeliveryPolicy; 446 } 447 448 /** 449 * Sets the redelivery policy 450 */ 451 public void setRedeliveryPolicy(RedeliveryPolicy redeliveryPolicy) { 452 this.redeliveryPolicy = redeliveryPolicy; 453 } 454 455 public CamelLogger getLogger() { 456 if (logger == null) { 457 logger = createLogger(); 458 } 459 return logger; 460 } 461 462 public void setLogger(CamelLogger logger) { 463 this.logger = logger; 464 } 465 466 public Processor getOnRedelivery() { 467 return onRedelivery; 468 } 469 470 public void setOnRedelivery(Processor onRedelivery) { 471 this.onRedelivery = onRedelivery; 472 } 473 474 public Predicate getRetryWhilePolicy(CamelContext context) { 475 Predicate answer = getRetryWhile(); 476 477 if (getRetryWhileRef() != null) { 478 // its a bean expression 479 Language bean = context.resolveLanguage("bean"); 480 answer = bean.createPredicate(getRetryWhileRef()); 481 } 482 483 return answer; 484 } 485 486 public Predicate getRetryWhile() { 487 return retryWhile; 488 } 489 490 public void setRetryWhile(Predicate retryWhile) { 491 this.retryWhile = retryWhile; 492 } 493 494 public String getRetryWhileRef() { 495 return retryWhileRef; 496 } 497 498 public void setRetryWhileRef(String retryWhileRef) { 499 this.retryWhileRef = retryWhileRef; 500 } 501 502 public String getDeadLetterUri() { 503 return deadLetterUri; 504 } 505 506 public void setDeadLetterUri(String deadLetterUri) { 507 this.deadLetter = null; 508 this.deadLetterUri = deadLetterUri; 509 } 510 511 public Endpoint getDeadLetter() { 512 return deadLetter; 513 } 514 515 public void setDeadLetter(Endpoint deadLetter) { 516 this.deadLetter = deadLetter; 517 this.deadLetterUri = deadLetter.getEndpointUri(); 518 } 519 520 public boolean isDeadLetterHandleNewException() { 521 return deadLetterHandleNewException; 522 } 523 524 public void setDeadLetterHandleNewException(boolean deadLetterHandleNewException) { 525 this.deadLetterHandleNewException = deadLetterHandleNewException; 526 } 527 528 public boolean isUseOriginalMessage() { 529 return useOriginalMessage; 530 } 531 532 public void setUseOriginalMessage(boolean useOriginalMessage) { 533 this.useOriginalMessage = useOriginalMessage; 534 } 535 536 public boolean isAsyncDelayedRedelivery() { 537 return asyncDelayedRedelivery; 538 } 539 540 public void setAsyncDelayedRedelivery(boolean asyncDelayedRedelivery) { 541 this.asyncDelayedRedelivery = asyncDelayedRedelivery; 542 } 543 544 public String getExecutorServiceRef() { 545 return executorServiceRef; 546 } 547 548 public void setExecutorServiceRef(String executorServiceRef) { 549 this.executorServiceRef = executorServiceRef; 550 } 551 552 public Processor getOnPrepareFailure() { 553 return onPrepareFailure; 554 } 555 556 public void setOnPrepareFailure(Processor onPrepareFailure) { 557 this.onPrepareFailure = onPrepareFailure; 558 } 559 560 public Processor getOnExceptionOccurred() { 561 return onExceptionOccurred; 562 } 563 564 public void setOnExceptionOccurred(Processor onExceptionOccurred) { 565 this.onExceptionOccurred = onExceptionOccurred; 566 } 567 568 protected RedeliveryPolicy createRedeliveryPolicy() { 569 RedeliveryPolicy policy = new RedeliveryPolicy(); 570 policy.disableRedelivery(); 571 return policy; 572 } 573 574 protected CamelLogger createLogger() { 575 return new CamelLogger(LoggerFactory.getLogger(DefaultErrorHandler.class), LoggingLevel.ERROR); 576 } 577 578 protected synchronized ScheduledExecutorService getExecutorService(CamelContext camelContext) { 579 if (executorService == null || executorService.isShutdown()) { 580 // camel context will shutdown the executor when it shutdown so no need to shut it down when stopping 581 if (executorServiceRef != null) { 582 executorService = camelContext.getRegistry().lookupByNameAndType(executorServiceRef, ScheduledExecutorService.class); 583 if (executorService == null) { 584 ExecutorServiceManager manager = camelContext.getExecutorServiceManager(); 585 ThreadPoolProfile profile = manager.getThreadPoolProfile(executorServiceRef); 586 executorService = manager.newScheduledThreadPool(this, executorServiceRef, profile); 587 } 588 if (executorService == null) { 589 throw new IllegalArgumentException("ExecutorServiceRef " + executorServiceRef + " not found in registry."); 590 } 591 } else { 592 // no explicit configured thread pool, so leave it up to the error handler to decide if it need 593 // a default thread pool from CamelContext#getErrorHandlerExecutorService 594 executorService = null; 595 } 596 } 597 return executorService; 598 } 599 600 @Override 601 public String toString() { 602 return "DefaultErrorHandlerBuilder"; 603 } 604 605}