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