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