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 }