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