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 */ 017 package org.apache.camel.builder; 018 019 import org.apache.camel.Endpoint; 020 import org.apache.camel.Exchange; 021 import org.apache.camel.Expression; 022 import org.apache.camel.LoggingLevel; 023 import org.apache.camel.Predicate; 024 import org.apache.camel.Processor; 025 import org.apache.camel.processor.DeadLetterChannel; 026 import org.apache.camel.processor.ErrorHandlerSupport; 027 import org.apache.camel.processor.Logger; 028 import org.apache.camel.processor.RecipientList; 029 import org.apache.camel.processor.RedeliveryPolicy; 030 import org.apache.camel.processor.SendProcessor; 031 import org.apache.camel.processor.exceptionpolicy.ExceptionPolicyStrategy; 032 import org.apache.camel.spi.RouteContext; 033 import org.apache.commons.logging.Log; 034 import org.apache.commons.logging.LogFactory; 035 import static org.apache.camel.builder.PredicateBuilder.toPredicate; 036 037 /** 038 * A builder of a <a 039 * href="http://camel.apache.org/dead-letter-channel.html">Dead Letter 040 * Channel</a> 041 * 042 * @version $Revision: 774230 $ 043 */ 044 public class DeadLetterChannelBuilder extends ErrorHandlerBuilderSupport { 045 private Logger logger = new Logger(LogFactory.getLog(DeadLetterChannel.class), LoggingLevel.ERROR); 046 private ExceptionPolicyStrategy exceptionPolicyStrategy = ErrorHandlerSupport.createDefaultExceptionPolicyStrategy(); 047 private RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy(); 048 private Processor onRedelivery; 049 private Processor failureProcessor; 050 private Endpoint deadLetter; 051 private String deadLetterUri; 052 private Predicate handledPolicy; 053 private boolean useOriginalBody; 054 055 /** 056 * Creates a default DeadLetterChannel with a default endpoint 057 */ 058 public DeadLetterChannelBuilder() { 059 this("log:org.apache.camel.DeadLetterChannel?level=error"); 060 } 061 062 /** 063 * Creates a DeadLetterChannel using the given endpoint 064 * 065 * @param deadLetter the dead letter queue 066 */ 067 public DeadLetterChannelBuilder(Endpoint deadLetter) { 068 setDeadLetter(deadLetter); 069 } 070 071 /** 072 * Creates a DeadLetterChannel using the given endpoint 073 * 074 * @param uri the dead letter queue 075 */ 076 public DeadLetterChannelBuilder(String uri) { 077 setDeadLetterUri(uri); 078 } 079 080 public Processor createErrorHandler(RouteContext routeContext, Processor processor) throws Exception { 081 DeadLetterChannel answer = new DeadLetterChannel(processor, getFailureProcessor(), deadLetterUri, onRedelivery, 082 getRedeliveryPolicy(), getLogger(), getExceptionPolicyStrategy(), getHandledPolicy(), isUseOriginalBody()); 083 // must enable stream cache as DeadLetterChannel can do redeliveries and 084 // thus it needs to be able to read the stream again 085 configure(answer); 086 return answer; 087 } 088 089 public boolean supportTransacted() { 090 return false; 091 } 092 093 // Builder methods 094 // ------------------------------------------------------------------------- 095 public DeadLetterChannelBuilder backOffMultiplier(double backOffMultiplier) { 096 getRedeliveryPolicy().backOffMultiplier(backOffMultiplier); 097 return this; 098 } 099 100 public DeadLetterChannelBuilder collisionAvoidancePercent(short collisionAvoidancePercent) { 101 getRedeliveryPolicy().collisionAvoidancePercent(collisionAvoidancePercent); 102 return this; 103 } 104 105 public DeadLetterChannelBuilder delay(long delay) { 106 getRedeliveryPolicy().delay(delay); 107 return this; 108 } 109 110 public DeadLetterChannelBuilder delayPattern(String delayPattern) { 111 getRedeliveryPolicy().delayPattern(delayPattern); 112 return this; 113 } 114 115 public DeadLetterChannelBuilder maximumRedeliveries(int maximumRedeliveries) { 116 getRedeliveryPolicy().maximumRedeliveries(maximumRedeliveries); 117 return this; 118 } 119 120 public DeadLetterChannelBuilder disableRedelivery() { 121 getRedeliveryPolicy().maximumRedeliveries(0); 122 return this; 123 } 124 125 public DeadLetterChannelBuilder maximumRedeliveryDelay(long maximumRedeliveryDelay) { 126 getRedeliveryPolicy().maximumRedeliveryDelay(maximumRedeliveryDelay); 127 return this; 128 } 129 130 public DeadLetterChannelBuilder useCollisionAvoidance() { 131 getRedeliveryPolicy().useCollisionAvoidance(); 132 return this; 133 } 134 135 public DeadLetterChannelBuilder useExponentialBackOff() { 136 getRedeliveryPolicy().useExponentialBackOff(); 137 return this; 138 } 139 140 public DeadLetterChannelBuilder retriesExhaustedLogLevel(LoggingLevel retriesExhaustedLogLevel) { 141 getRedeliveryPolicy().setRetriesExhaustedLogLevel(retriesExhaustedLogLevel); 142 return this; 143 } 144 145 public DeadLetterChannelBuilder retryAttemptedLogLevel(LoggingLevel retryAttemptedLogLevel) { 146 getRedeliveryPolicy().setRetryAttemptedLogLevel(retryAttemptedLogLevel); 147 return this; 148 } 149 150 public DeadLetterChannelBuilder logStackTrace(boolean logStackTrace) { 151 getRedeliveryPolicy().setLogStackTrace(logStackTrace); 152 return this; 153 } 154 155 /** 156 * Sets whether the exchange should be marked as handled or not. 157 * 158 * @param handled handled or not 159 * @return the builder 160 */ 161 public DeadLetterChannelBuilder handled(boolean handled) { 162 Expression expression = ExpressionBuilder.constantExpression(Boolean.toString(handled)); 163 return handled(expression); 164 } 165 166 /** 167 * Sets whether the exchange should be marked as handled or not. 168 * 169 * @param handled predicate that determines true or false 170 * @return the builder 171 */ 172 public DeadLetterChannelBuilder handled(Predicate handled) { 173 this.setHandledPolicy(handled); 174 return this; 175 } 176 177 /** 178 * Sets whether the exchange should be marked as handled or not. 179 * 180 * @param handled expression that determines true or false 181 * @return the builder 182 */ 183 public DeadLetterChannelBuilder handled(Expression handled) { 184 this.setHandledPolicy(toPredicate(handled)); 185 return this; 186 } 187 188 /** 189 * Sets the logger used for caught exceptions 190 * 191 * @param logger the logger 192 * @return the builder 193 */ 194 public DeadLetterChannelBuilder logger(Logger logger) { 195 setLogger(logger); 196 return this; 197 } 198 199 /** 200 * Sets the logging level of exceptions caught 201 * 202 * @param level the logging level 203 * @return the builder 204 */ 205 public DeadLetterChannelBuilder loggingLevel(LoggingLevel level) { 206 getLogger().setLevel(level); 207 return this; 208 } 209 210 /** 211 * Sets the log used for caught exceptions 212 * 213 * @param log the logger 214 * @return the builder 215 */ 216 public DeadLetterChannelBuilder log(Log log) { 217 getLogger().setLog(log); 218 return this; 219 } 220 221 /** 222 * Sets the log used for caught exceptions 223 * 224 * @param log the log name 225 * @return the builder 226 */ 227 public DeadLetterChannelBuilder log(String log) { 228 return log(LogFactory.getLog(log)); 229 } 230 231 /** 232 * Sets the log used for caught exceptions 233 * 234 * @param log the log class 235 * @return the builder 236 */ 237 public DeadLetterChannelBuilder log(Class log) { 238 return log(LogFactory.getLog(log)); 239 } 240 241 /** 242 * Sets the exception policy to use 243 * 244 * @return the builder 245 */ 246 public DeadLetterChannelBuilder exceptionPolicyStrategy(ExceptionPolicyStrategy exceptionPolicyStrategy) { 247 setExceptionPolicyStrategy(exceptionPolicyStrategy); 248 return this; 249 } 250 251 /** 252 * Sets a processor that should be processed <b>before</b> a redelivey attempt. 253 * <p/> 254 * Can be used to change the {@link org.apache.camel.Exchange} <b>before</b> its being redelivered. 255 * 256 * @return the builder 257 */ 258 public DeadLetterChannelBuilder onRedelivery(Processor processor) { 259 setOnRedelivery(processor); 260 return this; 261 } 262 263 /** 264 * Will use the original input body when an {@link Exchange} is moved to the dead letter queue. 265 * <p/> 266 * <b>Notice:</b> this only applies when all redeliveries attempt have failed and the {@link Exchange} is doomed for failure. 267 * <br/> 268 * Instead of using the current inprogress {@link Exchange} IN body we use the original IN body instead. This allows 269 * you to store the original input in the dead letter queue instead of the inprogress snapshot of the IN body. 270 * For instance if you route transform the IN body during routing and then failed. With the original exchange 271 * store in the dead letter queue it might be easier to manually re submit the {@link Exchange} again as the IN body 272 * is the same as when Camel received it. So you should be able to send the {@link Exchange} to the same input. 273 * <p/> 274 * By default this feature is off. 275 * 276 * @return the builder 277 */ 278 public DeadLetterChannelBuilder useOriginalBody() { 279 setUseOriginalBody(true); 280 return this; 281 } 282 283 // Properties 284 // ------------------------------------------------------------------------- 285 286 public Processor getFailureProcessor() { 287 if (failureProcessor == null) { 288 if (deadLetter != null) { 289 failureProcessor = new SendProcessor(deadLetter); 290 } else { 291 // use a recipient list since we only have an uri for the endpoint 292 failureProcessor = new RecipientList(new Expression() { 293 public Object evaluate(Exchange exchange) { 294 return deadLetterUri; 295 } 296 297 public <T> T evaluate(Exchange exchange, Class<T> type) { 298 return exchange.getContext().getTypeConverter().convertTo(type, deadLetterUri); 299 } 300 }); 301 } 302 } 303 return failureProcessor; 304 } 305 306 public void setFailureProcessor(Processor failureProcessor) { 307 this.failureProcessor = failureProcessor; 308 } 309 310 public String getDeadLetterUri() { 311 return deadLetterUri; 312 } 313 314 public void setDeadLetterUri(String deadLetterUri) { 315 this.deadLetter = null; 316 this.deadLetterUri = deadLetterUri; 317 } 318 319 public Endpoint getDeadLetter() { 320 return deadLetter; 321 } 322 323 public void setDeadLetter(Endpoint deadLetter) { 324 this.deadLetter = deadLetter; 325 this.deadLetterUri = deadLetter.getEndpointUri(); 326 } 327 328 public RedeliveryPolicy getRedeliveryPolicy() { 329 return redeliveryPolicy; 330 } 331 332 /** 333 * Sets the redelivery policy 334 */ 335 public void setRedeliveryPolicy(RedeliveryPolicy redeliveryPolicy) { 336 this.redeliveryPolicy = redeliveryPolicy; 337 } 338 339 public Logger getLogger() { 340 return logger; 341 } 342 343 public void setLogger(Logger logger) { 344 this.logger = logger; 345 } 346 347 /** 348 * Sets the exception policy strategy to use for resolving the {@link org.apache.camel.model.OnExceptionDefinition} 349 * to use for a given thrown exception 350 */ 351 public ExceptionPolicyStrategy getExceptionPolicyStrategy() { 352 return exceptionPolicyStrategy; 353 } 354 355 public void setExceptionPolicyStrategy(ExceptionPolicyStrategy exceptionPolicyStrategy) { 356 this.exceptionPolicyStrategy = exceptionPolicyStrategy; 357 } 358 359 public Processor getOnRedelivery() { 360 return onRedelivery; 361 } 362 363 public void setOnRedelivery(Processor onRedelivery) { 364 this.onRedelivery = onRedelivery; 365 } 366 367 public Predicate getHandledPolicy() { 368 return handledPolicy; 369 } 370 371 public void setHandledPolicy(Predicate handled) { 372 this.handledPolicy = handled; 373 } 374 375 /** 376 * Sets the handled using a boolean and thus easier to use for Spring XML configuration as well 377 */ 378 public void setHandled(boolean handled) { 379 handled(handled); 380 } 381 382 public boolean isUseOriginalBody() { 383 return useOriginalBody; 384 } 385 386 public void setUseOriginalBody(boolean useOriginalBody) { 387 this.useOriginalBody = useOriginalBody; 388 } 389 390 @Override 391 public String toString() { 392 return "DeadLetterChannelBuilder(" + deadLetterUri + ")"; 393 } 394 }