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