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