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.model;
018    
019    import java.util.ArrayList;
020    import java.util.Collection;
021    import java.util.HashMap;
022    import java.util.List;
023    import java.util.Map;
024    import javax.xml.bind.annotation.XmlAccessType;
025    import javax.xml.bind.annotation.XmlAccessorType;
026    import javax.xml.bind.annotation.XmlAttribute;
027    import javax.xml.bind.annotation.XmlElement;
028    import javax.xml.bind.annotation.XmlElementRef;
029    import javax.xml.bind.annotation.XmlRootElement;
030    import javax.xml.bind.annotation.XmlTransient;
031    
032    import org.apache.camel.CamelContext;
033    import org.apache.camel.Expression;
034    import org.apache.camel.LoggingLevel;
035    import org.apache.camel.Predicate;
036    import org.apache.camel.Processor;
037    import org.apache.camel.Route;
038    import org.apache.camel.builder.ErrorHandlerBuilder;
039    import org.apache.camel.builder.ExpressionBuilder;
040    import org.apache.camel.processor.CatchProcessor;
041    import org.apache.camel.processor.FatalFallbackErrorHandler;
042    import org.apache.camel.processor.RedeliveryPolicy;
043    import org.apache.camel.spi.ClassResolver;
044    import org.apache.camel.spi.RouteContext;
045    import org.apache.camel.util.CamelContextHelper;
046    import org.apache.camel.util.ExpressionToPredicateAdapter;
047    import org.apache.camel.util.ObjectHelper;
048    
049    /**
050     * Represents an XML <onException/> element
051     *
052     * @version 
053     */
054    @XmlRootElement(name = "onException")
055    @XmlAccessorType(XmlAccessType.FIELD)
056    public class OnExceptionDefinition extends ProcessorDefinition<OnExceptionDefinition> {
057        @XmlElement(name = "exception", required = true)
058        private List<String> exceptions = new ArrayList<String>();
059        @XmlElement(name = "onWhen")
060        private WhenDefinition onWhen;
061        @XmlElement(name = "retryWhile")
062        private ExpressionSubElementDefinition retryWhile;
063        @XmlElement(name = "redeliveryPolicy")
064        private RedeliveryPolicyDefinition redeliveryPolicy;
065        @XmlAttribute(name = "redeliveryPolicyRef")
066        private String redeliveryPolicyRef;
067        @XmlElement(name = "handled")
068        private ExpressionSubElementDefinition handled;
069        @XmlElement(name = "continued")
070        private ExpressionSubElementDefinition continued;
071        @XmlAttribute(name = "onRedeliveryRef")
072        private String onRedeliveryRef;
073        @XmlAttribute(name = "useOriginalMessage")
074        private Boolean useOriginalMessagePolicy;
075        @XmlElementRef
076        private List<ProcessorDefinition<?>> outputs = new ArrayList<ProcessorDefinition<?>>();
077        @XmlTransient
078        private List<Class<? extends Throwable>> exceptionClasses;
079        @XmlTransient
080        private Predicate handledPolicy;
081        @XmlTransient
082        private Predicate continuedPolicy;
083        @XmlTransient
084        private Predicate retryWhilePolicy;
085        @XmlTransient
086        private Processor onRedelivery;
087        @XmlTransient
088        private Boolean routeScoped;
089        // TODO: in Camel 3.0 the OnExceptionDefinition should not contain state and ErrorHandler processors
090        @XmlTransient
091        private final Map<String, Processor> errorHandlers = new HashMap<String, Processor>();
092    
093        public OnExceptionDefinition() {
094        }
095    
096        public OnExceptionDefinition(List<Class<? extends Throwable>> exceptionClasses) {
097            this.exceptionClasses = exceptionClasses;
098        }
099    
100        public OnExceptionDefinition(Class<? extends Throwable> exceptionType) {
101            exceptionClasses = new ArrayList<Class<? extends Throwable>>();
102            exceptionClasses.add(exceptionType);
103        }
104    
105        public void setRouteScoped(boolean routeScoped) {
106            this.routeScoped = routeScoped;
107        }
108    
109        public boolean isRouteScoped() {
110            // is context scoped by default
111            return routeScoped != null ? routeScoped : false;
112        }
113    
114        @Override
115        public String getShortName() {
116            return "onException";
117        }
118    
119        @Override
120        public String toString() {
121            return "OnException[" + description() + " -> " + getOutputs() + "]";
122        }
123        
124        protected String description() {
125            return getExceptionClasses() + (onWhen != null ? " " + onWhen : "");
126        }
127    
128        @Override
129        public String getLabel() {
130            return "onException[" + description() + "]";
131        }
132        
133        @Override
134        public boolean isAbstract() {
135            return true;
136        }
137    
138        @Override
139        public boolean isTopLevelOnly() {
140            return true;
141        }
142    
143        /**
144         * Allows an exception handler to create a new redelivery policy for this exception type
145         *
146         * @param context      the camel context
147         * @param parentPolicy the current redelivery policy, is newer <tt>null</tt>
148         * @return a newly created redelivery policy, or return the original policy if no customization is required
149         *         for this exception handler.
150         */
151        public RedeliveryPolicy createRedeliveryPolicy(CamelContext context, RedeliveryPolicy parentPolicy) {
152            if (redeliveryPolicyRef != null) {
153                return CamelContextHelper.mandatoryLookup(context, redeliveryPolicyRef, RedeliveryPolicy.class);
154            } else if (redeliveryPolicy != null) {
155                return redeliveryPolicy.createRedeliveryPolicy(context, parentPolicy);
156            } else if (!outputs.isEmpty() && parentPolicy.getMaximumRedeliveries() != 0) {
157                // if we have outputs, then do not inherit parent maximumRedeliveries
158                // as you would have to explicit configure maximumRedeliveries on this onException to use it
159                // this is the behavior Camel has always had
160                RedeliveryPolicy answer = parentPolicy.copy();
161                answer.setMaximumRedeliveries(0);
162                return answer;
163            } else {
164                return parentPolicy;
165            }
166        }
167    
168        public void addRoutes(RouteContext routeContext, Collection<Route> routes) throws Exception {
169            // assign whether this was a route scoped onException or not
170            // we need to know this later when setting the parent, as only route scoped should have parent
171            // Note: this logic can possible be removed when the Camel routing engine decides at runtime
172            // to apply onException in a more dynamic fashion than current code base
173            // and therefore is in a better position to decide among context/route scoped OnException at runtime
174            if (routeScoped == null) {
175                routeScoped = super.getParent() != null;
176            }
177    
178            setHandledFromExpressionType(routeContext);
179            setContinuedFromExpressionType(routeContext);
180            setRetryWhileFromExpressionType(routeContext);
181            setOnRedeliveryFromRedeliveryRef(routeContext);
182    
183            // load exception classes
184            if (exceptions != null && !exceptions.isEmpty()) {
185                exceptionClasses = createExceptionClasses(routeContext.getCamelContext().getClassResolver());
186            }
187    
188            // must validate configuration before creating processor
189            validateConfiguration();
190    
191            // lets attach this on exception to the route error handler
192            Processor child = createOutputsProcessor(routeContext);
193            if (child != null) {
194                // wrap in our special safe fallback error handler if OnException have child output
195                Processor errorHandler = new FatalFallbackErrorHandler(child);
196                String id = routeContext.getRoute().getId();
197                errorHandlers.put(id, errorHandler);
198            }
199            // lookup the error handler builder
200            ErrorHandlerBuilder builder = (ErrorHandlerBuilder)routeContext.getRoute().getErrorHandlerBuilder();
201            // and add this as error handlers
202            builder.addErrorHandlers(routeContext, this);
203        }
204    
205        @Override
206        public CatchProcessor createProcessor(RouteContext routeContext) throws Exception {
207            // load exception classes
208            if (exceptions != null && !exceptions.isEmpty()) {
209                exceptionClasses = createExceptionClasses(routeContext.getCamelContext().getClassResolver());
210            }
211    
212            // must validate configuration before creating processor
213            validateConfiguration();
214    
215            Processor childProcessor = this.createChildProcessor(routeContext, false);
216    
217            Predicate when = null;
218            if (onWhen != null) {
219                when = onWhen.getExpression().createPredicate(routeContext);
220            }
221    
222            Predicate handle = null;
223            if (handled != null) {
224                handle = handled.createPredicate(routeContext);
225            }
226    
227            return new CatchProcessor(getExceptionClasses(), childProcessor, when, handle);
228        }
229    
230        protected void validateConfiguration() {
231            if (isInheritErrorHandler() != null && isInheritErrorHandler()) {
232                throw new IllegalArgumentException(this + " cannot have the inheritErrorHandler option set to true");
233            }
234    
235            List<Class<? extends Throwable>> exceptions = getExceptionClasses();
236            if (exceptions == null || exceptions.isEmpty()) {
237                throw new IllegalArgumentException("At least one exception must be configured on " + this);
238            }
239    
240            // only one of handled or continued is allowed
241            if (getHandledPolicy() != null && getContinuedPolicy() != null) {
242                throw new IllegalArgumentException("Only one of handled or continued is allowed to be configured on: " + this);
243            }
244    
245            // validate that at least some option is set as you cannot just have onException(Exception.class);
246            if (outputs == null || getOutputs().isEmpty()) {
247                // no outputs so there should be some sort of configuration
248                if (handledPolicy == null && continuedPolicy == null && retryWhilePolicy == null
249                        && redeliveryPolicy == null && useOriginalMessagePolicy == null && onRedelivery == null) {
250                    throw new IllegalArgumentException(this + " is not configured.");
251                }
252            }
253        }
254    
255        // Fluent API
256        //-------------------------------------------------------------------------
257    
258        @Override
259        public OnExceptionDefinition onException(Class<? extends Throwable> exceptionType) {
260            getExceptionClasses().add(exceptionType);
261            return this;
262        }
263    
264        /**
265         * Sets whether the exchange should be marked as handled or not.
266         *
267         * @param handled handled or not
268         * @return the builder
269         */
270        public OnExceptionDefinition handled(boolean handled) {
271            Expression expression = ExpressionBuilder.constantExpression(Boolean.toString(handled));
272            return handled(expression);
273        }
274    
275        /**
276         * Sets whether the exchange should be marked as handled or not.
277         *
278         * @param handled predicate that determines true or false
279         * @return the builder
280         */
281        public OnExceptionDefinition handled(Predicate handled) {
282            setHandledPolicy(handled);
283            return this;
284        }
285    
286        /**
287         * Sets whether the exchange should be marked as handled or not.
288         *
289         * @param handled expression that determines true or false
290         * @return the builder
291         */
292        public OnExceptionDefinition handled(Expression handled) {
293            setHandledPolicy(ExpressionToPredicateAdapter.toPredicate(handled));
294            return this;
295        }
296    
297        /**
298         * Sets whether the exchange should handle and continue routing from the point of failure.
299         * <p/>
300         * If this option is enabled then its considered handled as well.
301         *
302         * @param continued continued or not
303         * @return the builder
304         */
305        public OnExceptionDefinition continued(boolean continued) {
306            Expression expression = ExpressionBuilder.constantExpression(Boolean.toString(continued));
307            return continued(expression);
308        }
309    
310        /**
311         * Sets whether the exchange should be marked as handled or not.
312         * <p/>
313         * If this option is enabled then its considered handled as well.
314         *
315         * @param continued predicate that determines true or false
316         * @return the builder
317         */
318        public OnExceptionDefinition continued(Predicate continued) {
319            setContinuedPolicy(continued);
320            return this;
321        }
322    
323        /**
324         * Sets whether the exchange should be marked as handled or not.
325         * <p/>
326         * If this option is enabled then its considered handled as well.
327         *
328         * @param continued expression that determines true or false
329         * @return the builder
330         */
331        public OnExceptionDefinition continued(Expression continued) {
332            setContinuedPolicy(ExpressionToPredicateAdapter.toPredicate(continued));
333            return this;
334        }
335    
336        /**
337         * Sets an additional predicate that should be true before the onException is triggered.
338         * <p/>
339         * To be used for fine grained controlling whether a thrown exception should be intercepted
340         * by this exception type or not.
341         *
342         * @param predicate predicate that determines true or false
343         * @return the builder
344         */
345        public OnExceptionDefinition onWhen(Predicate predicate) {
346            setOnWhen(new WhenDefinition(predicate));
347            return this;
348        }
349    
350        /**
351         * Sets the retry while predicate.
352         * <p/>
353         * Will continue retrying until predicate returns <tt>false</tt>.
354         *
355         * @param retryWhile predicate that determines when to stop retrying
356         * @return the builder
357         */
358        public OnExceptionDefinition retryWhile(Predicate retryWhile) {
359            setRetryWhilePolicy(retryWhile);
360            return this;
361        }
362    
363        /**
364         * Sets the initial redelivery delay
365         *
366         * @param delay the initial redelivery delay
367         * @return the builder
368         * @deprecated will be removed in the near future. Instead use {@link #redeliveryDelay(String)}
369         */
370        @Deprecated
371        public OnExceptionDefinition redeliverDelay(long delay) {
372            getOrCreateRedeliveryPolicy().redeliveryDelay(delay);
373            return this;
374        }
375    
376        /**
377         * Sets the back off multiplier
378         *
379         * @param backOffMultiplier the back off multiplier
380         * @return the builder
381         */
382        public OnExceptionDefinition backOffMultiplier(double backOffMultiplier) {
383            getOrCreateRedeliveryPolicy().useExponentialBackOff();
384            getOrCreateRedeliveryPolicy().backOffMultiplier(backOffMultiplier);
385            return this;
386        }
387    
388        /**
389         * Sets the back off multiplier (supports property placeholders)
390         *
391         * @param backOffMultiplier the back off multiplier
392         * @return the builder
393         */
394        public OnExceptionDefinition backOffMultiplier(String backOffMultiplier) {
395            getOrCreateRedeliveryPolicy().useExponentialBackOff();
396            getOrCreateRedeliveryPolicy().backOffMultiplier(backOffMultiplier);
397            return this;
398        }
399    
400        /**
401         * Sets the collision avoidance factor
402         *
403         * @param collisionAvoidanceFactor the factor
404         * @return the builder
405         */
406        public OnExceptionDefinition collisionAvoidanceFactor(double collisionAvoidanceFactor) {
407            getOrCreateRedeliveryPolicy().useCollisionAvoidance();
408            getOrCreateRedeliveryPolicy().collisionAvoidanceFactor(collisionAvoidanceFactor);
409            return this;
410        }
411    
412        /**
413         * Sets the collision avoidance factor (supports property placeholders)
414         *
415         * @param collisionAvoidanceFactor the factor
416         * @return the builder
417         */
418        public OnExceptionDefinition collisionAvoidanceFactor(String collisionAvoidanceFactor) {
419            getOrCreateRedeliveryPolicy().useCollisionAvoidance();
420            getOrCreateRedeliveryPolicy().collisionAvoidanceFactor(collisionAvoidanceFactor);
421            return this;
422        }
423    
424        /**
425         * Sets the collision avoidance percentage
426         *
427         * @param collisionAvoidancePercent the percentage
428         * @return the builder
429         */
430        public OnExceptionDefinition collisionAvoidancePercent(double collisionAvoidancePercent) {
431            getOrCreateRedeliveryPolicy().useCollisionAvoidance();
432            getOrCreateRedeliveryPolicy().collisionAvoidancePercent(collisionAvoidancePercent);
433            return this;
434        }
435    
436        /**
437         * Sets the initial redelivery delay
438         *
439         * @param delay delay in millis
440         * @return the builder
441         */
442        public OnExceptionDefinition redeliveryDelay(long delay) {
443            getOrCreateRedeliveryPolicy().redeliveryDelay(delay);
444            return this;
445        }
446    
447        /**
448         * Sets the initial redelivery delay (supports property placeholders)
449         *
450         * @param delay delay in millis
451         * @return the builder
452         */
453        public OnExceptionDefinition redeliveryDelay(String delay) {
454            getOrCreateRedeliveryPolicy().redeliveryDelay(delay);
455            return this;
456        }
457    
458        /**
459         * Allow synchronous delayed redelivery.
460         *
461         * @see org.apache.camel.processor.RedeliveryPolicy#setAsyncDelayedRedelivery(boolean)
462         * @return the builder
463         */
464        public OnExceptionDefinition asyncDelayedRedelivery() {
465            getOrCreateRedeliveryPolicy().asyncDelayedRedelivery();
466            return this;
467        }
468    
469        /**
470         * Sets the logging level to use when retries has exhausted
471         *
472         * @param retriesExhaustedLogLevel the logging level
473         * @return the builder
474         */
475        public OnExceptionDefinition retriesExhaustedLogLevel(LoggingLevel retriesExhaustedLogLevel) {
476            getOrCreateRedeliveryPolicy().retriesExhaustedLogLevel(retriesExhaustedLogLevel);
477            return this;
478        }
479    
480        /**
481         * Sets the logging level to use for logging retry attempts
482         *
483         * @param retryAttemptedLogLevel the logging level
484         * @return the builder
485         */
486        public OnExceptionDefinition retryAttemptedLogLevel(LoggingLevel retryAttemptedLogLevel) {
487            getOrCreateRedeliveryPolicy().retryAttemptedLogLevel(retryAttemptedLogLevel);
488            return this;
489        }
490    
491        /**
492         * Sets whether to log stacktrace for failed messages.
493         */
494        public OnExceptionDefinition logStackTrace(boolean logStackTrace) {
495            getOrCreateRedeliveryPolicy().logStackTrace(logStackTrace);
496            return this;
497        }
498    
499        /**
500         * Sets whether to log stacktrace for failed messages (supports property placeholders)
501         */
502        public OnExceptionDefinition logStackTrace(String logStackTrace) {
503            getOrCreateRedeliveryPolicy().logStackTrace(logStackTrace);
504            return this;
505        }
506    
507        /**
508         * Sets whether to log stacktrace for failed redelivery attempts
509         */
510        public OnExceptionDefinition logRetryStackTrace(boolean logRetryStackTrace) {
511            getOrCreateRedeliveryPolicy().logRetryStackTrace(logRetryStackTrace);
512            return this;
513        }
514    
515        /**
516         * Sets whether to log stacktrace for failed redelivery attempts (supports property placeholders)
517         */
518        public OnExceptionDefinition logRetryStackTrace(String logRetryStackTrace) {
519            getOrCreateRedeliveryPolicy().logRetryStackTrace(logRetryStackTrace);
520            return this;
521        }
522    
523        /**
524         * Sets whether to log errors even if its handled
525         */
526        public OnExceptionDefinition logHandled(boolean logHandled) {
527            getOrCreateRedeliveryPolicy().logHandled(logHandled);
528            return this;
529        }
530    
531        /**
532         * Sets whether to log errors even if its handled (supports property placeholders)
533         */
534        public OnExceptionDefinition logHandled(String logHandled) {
535            getOrCreateRedeliveryPolicy().logHandled(logHandled);
536            return this;
537        }
538    
539        /**
540         * Sets whether to log errors even if its continued
541         */
542        public OnExceptionDefinition logContinued(boolean logContinued) {
543            getOrCreateRedeliveryPolicy().logContinued(logContinued);
544            return this;
545        }
546    
547        /**
548         * Sets whether to log errors even if its continued (supports property placeholders)
549         */
550        public OnExceptionDefinition logContinued(String logContinued) {
551            getOrCreateRedeliveryPolicy().logContinued(logContinued);
552            return this;
553        }
554    
555        /**
556         * Sets whether to log retry attempts
557         */
558        public OnExceptionDefinition logRetryAttempted(boolean logRetryAttempted) {
559            getOrCreateRedeliveryPolicy().logRetryAttempted(logRetryAttempted);
560            return this;
561        }
562    
563        /**
564         * Sets whether to log retry attempts (supports property placeholders)
565         */
566        public OnExceptionDefinition logRetryAttempted(String logRetryAttempted) {
567            getOrCreateRedeliveryPolicy().logRetryAttempted(logRetryAttempted);
568            return this;
569        }
570    
571        /**
572         * Sets whether to log exhausted exceptions
573         */
574        public OnExceptionDefinition logExhausted(boolean logExhausted) {
575            getOrCreateRedeliveryPolicy().logExhausted(logExhausted);
576            return this;
577        }
578    
579        /**
580         * Sets whether to log exhausted exceptions (supports property placeholders)
581         */
582        public OnExceptionDefinition logExhausted(String logExhausted) {
583            getOrCreateRedeliveryPolicy().logExhausted(logExhausted);
584            return this;
585        }
586    
587        /**
588         * Sets whether to log exhausted exceptions with message history
589         */
590        public OnExceptionDefinition logExhaustedMessageHistory(boolean logExhaustedMessageHistory) {
591            getOrCreateRedeliveryPolicy().logExhaustedMessageHistory(logExhaustedMessageHistory);
592            return this;
593        }
594    
595        /**
596         * Sets whether to log exhausted exceptions with message history
597         */
598        public OnExceptionDefinition logExhaustedMessageHistory(String logExhaustedMessageHistory) {
599            getOrCreateRedeliveryPolicy().logExhaustedMessageHistory(logExhaustedMessageHistory);
600            return this;
601        }
602    
603        /**
604         * Sets the maximum redeliveries
605         * <ul>
606         * <li>5 = default value</li>
607         * <li>0 = no redeliveries</li>
608         * <li>-1 = redeliver forever</li>
609         * </ul>
610         *
611         * @param maximumRedeliveries the value
612         * @return the builder
613         */
614        public OnExceptionDefinition maximumRedeliveries(int maximumRedeliveries) {
615            getOrCreateRedeliveryPolicy().maximumRedeliveries(maximumRedeliveries);
616            return this;
617        }
618    
619        /**
620         * Sets the maximum redeliveries (supports property placeholders)
621         * <ul>
622         * <li>5 = default value</li>
623         * <li>0 = no redeliveries</li>
624         * <li>-1 = redeliver forever</li>
625         * </ul>
626         *
627         * @param maximumRedeliveries the value
628         * @return the builder
629         */
630        public OnExceptionDefinition maximumRedeliveries(String maximumRedeliveries) {
631            getOrCreateRedeliveryPolicy().maximumRedeliveries(maximumRedeliveries);
632            return this;
633        }
634    
635        /**
636         * Turn on collision avoidance.
637         *
638         * @return the builder
639         */
640        public OnExceptionDefinition useCollisionAvoidance() {
641            getOrCreateRedeliveryPolicy().useCollisionAvoidance();
642            return this;
643        }
644    
645        /**
646         * Turn on exponential backk off
647         *
648         * @return the builder
649         */
650        public OnExceptionDefinition useExponentialBackOff() {
651            getOrCreateRedeliveryPolicy().useExponentialBackOff();
652            return this;
653        }
654    
655        /**
656         * Sets the maximum delay between redelivery
657         *
658         * @param maximumRedeliveryDelay the delay in millis
659         * @return the builder
660         */
661        public OnExceptionDefinition maximumRedeliveryDelay(long maximumRedeliveryDelay) {
662            getOrCreateRedeliveryPolicy().maximumRedeliveryDelay(maximumRedeliveryDelay);
663            return this;
664        }
665    
666        /**
667         * Sets the maximum delay between redelivery (supports property placeholders)
668         *
669         * @param maximumRedeliveryDelay the delay in millis
670         * @return the builder
671         */
672        public OnExceptionDefinition maximumRedeliveryDelay(String maximumRedeliveryDelay) {
673            getOrCreateRedeliveryPolicy().maximumRedeliveryDelay(maximumRedeliveryDelay);
674            return this;
675        }
676    
677        /**
678         * Sets a reference to a {@link RedeliveryPolicy} to lookup in the {@link org.apache.camel.spi.Registry} to be used.
679         *
680         * @param redeliveryPolicyRef reference to use for lookup
681         * @return the builder
682         */
683        public OnExceptionDefinition redeliveryPolicyRef(String redeliveryPolicyRef) {
684            setRedeliveryPolicyRef(redeliveryPolicyRef);
685            return this;
686        }
687    
688        /**
689         * Sets the delay pattern with delay intervals.
690         *
691         * @param delayPattern the delay pattern
692         * @return the builder
693         */
694        public OnExceptionDefinition delayPattern(String delayPattern) {
695            getOrCreateRedeliveryPolicy().setDelayPattern(delayPattern);
696            return this;
697        }
698    
699        /**
700         * @deprecated this method will be removed in Camel 3.0, please use {@link #useOriginalMessage()}
701         * @see #useOriginalMessage()
702         */
703        @Deprecated
704        public OnExceptionDefinition useOriginalBody() {
705            setUseOriginalMessagePolicy(Boolean.TRUE);
706            return this;
707        }
708    
709        /**
710         * Will use the original input message when an {@link org.apache.camel.Exchange} is moved to the dead letter queue.
711         * <p/>
712         * <b>Notice:</b> this only applies when all redeliveries attempt have failed and the {@link org.apache.camel.Exchange} is doomed for failure.
713         * <br/>
714         * Instead of using the current inprogress {@link org.apache.camel.Exchange} IN body we use the original IN body instead. This allows
715         * you to store the original input in the dead letter queue instead of the inprogress snapshot of the IN body.
716         * For instance if you route transform the IN body during routing and then failed. With the original exchange
717         * store in the dead letter queue it might be easier to manually re submit the {@link org.apache.camel.Exchange} again as the IN body
718         * is the same as when Camel received it. So you should be able to send the {@link org.apache.camel.Exchange} to the same input.
719         * <p/>
720         * By default this feature is off.
721         *
722         * @return the builder
723         */
724        public OnExceptionDefinition useOriginalMessage() {
725            setUseOriginalMessagePolicy(Boolean.TRUE);
726            return this;
727        }
728    
729        /**
730         * Sets a processor that should be processed <b>before</b> a redelivery attempt.
731         * <p/>
732         * Can be used to change the {@link org.apache.camel.Exchange} <b>before</b> its being redelivered.
733         */
734        public OnExceptionDefinition onRedelivery(Processor processor) {
735            setOnRedelivery(processor);
736            return this;
737        }
738    
739        // Properties
740        //-------------------------------------------------------------------------
741        @Override
742        public List<ProcessorDefinition<?>> getOutputs() {
743            return outputs;
744        }
745    
746        public void setOutputs(List<ProcessorDefinition<?>> outputs) {
747            this.outputs = outputs;
748        }
749    
750        public boolean isOutputSupported() {
751            return true;
752        }
753    
754        public List<Class<? extends Throwable>> getExceptionClasses() {
755            return exceptionClasses;
756        }
757    
758        public void setExceptionClasses(List<Class<? extends Throwable>> exceptionClasses) {
759            this.exceptionClasses = exceptionClasses;
760        }
761    
762        public List<String> getExceptions() {
763            return exceptions;
764        }
765    
766        public void setExceptions(List<String> exceptions) {
767            this.exceptions = exceptions;
768        }
769    
770        public Processor getErrorHandler(String routeId) {
771            return errorHandlers.get(routeId);
772        }
773        
774        public Collection<Processor> getErrorHandlers() {
775            return errorHandlers.values();
776        }
777    
778        public RedeliveryPolicyDefinition getRedeliveryPolicy() {
779            return redeliveryPolicy;
780        }
781    
782        public void setRedeliveryPolicy(RedeliveryPolicyDefinition redeliveryPolicy) {
783            this.redeliveryPolicy = redeliveryPolicy;
784        }
785    
786        public String getRedeliveryPolicyRef() {
787            return redeliveryPolicyRef;
788        }
789    
790        public void setRedeliveryPolicyRef(String redeliveryPolicyRef) {
791            this.redeliveryPolicyRef = redeliveryPolicyRef;
792        }
793    
794        public Predicate getHandledPolicy() {
795            return handledPolicy;
796        }
797    
798        public void setHandled(ExpressionSubElementDefinition handled) {
799            this.handled = handled;
800        }
801    
802        public ExpressionSubElementDefinition getContinued() {
803            return continued;
804        }
805    
806        public void setContinued(ExpressionSubElementDefinition continued) {
807            this.continued = continued;
808        }
809    
810        public ExpressionSubElementDefinition getHandled() {
811            return handled;
812        }
813    
814        public void setHandledPolicy(Predicate handledPolicy) {
815            this.handledPolicy = handledPolicy;
816        }
817    
818        public Predicate getContinuedPolicy() {
819            return continuedPolicy;
820        }
821    
822        public void setContinuedPolicy(Predicate continuedPolicy) {
823            this.continuedPolicy = continuedPolicy;
824        }
825    
826        public WhenDefinition getOnWhen() {
827            return onWhen;
828        }
829    
830        public void setOnWhen(WhenDefinition onWhen) {
831            this.onWhen = onWhen;
832        }
833    
834        public ExpressionSubElementDefinition getRetryWhile() {
835            return retryWhile;
836        }
837    
838        public void setRetryWhile(ExpressionSubElementDefinition retryWhile) {
839            this.retryWhile = retryWhile;
840        }
841    
842        public Predicate getRetryWhilePolicy() {
843            return retryWhilePolicy;
844        }
845    
846        public void setRetryWhilePolicy(Predicate retryWhilePolicy) {
847            this.retryWhilePolicy = retryWhilePolicy;
848        }
849    
850        public Processor getOnRedelivery() {
851            return onRedelivery;
852        }
853    
854        public void setOnRedelivery(Processor onRedelivery) {
855            this.onRedelivery = onRedelivery;
856        }
857    
858        public String getOnRedeliveryRef() {
859            return onRedeliveryRef;
860        }
861    
862        public void setOnRedeliveryRef(String onRedeliveryRef) {
863            this.onRedeliveryRef = onRedeliveryRef;
864        }
865    
866        public Boolean getUseOriginalMessagePolicy() {
867            return useOriginalMessagePolicy;
868        }
869    
870        public void setUseOriginalMessagePolicy(Boolean useOriginalMessagePolicy) {
871            this.useOriginalMessagePolicy = useOriginalMessagePolicy;
872        }
873    
874        public boolean isUseOriginalMessage() {
875            return useOriginalMessagePolicy != null && useOriginalMessagePolicy;
876        }
877    
878        public boolean isAsyncDelayedRedelivery(CamelContext context) {
879            if (getRedeliveryPolicy() != null) {
880                return getRedeliveryPolicy().isAsyncDelayedRedelivery(context);
881            }
882            return false;
883        }
884    
885        // Implementation methods
886        //-------------------------------------------------------------------------
887    
888        protected RedeliveryPolicyDefinition getOrCreateRedeliveryPolicy() {
889            if (redeliveryPolicy == null) {
890                redeliveryPolicy = new RedeliveryPolicyDefinition();
891            }
892            return redeliveryPolicy;
893        }
894    
895        protected List<Class<? extends Throwable>> createExceptionClasses(ClassResolver resolver) throws ClassNotFoundException {
896            List<String> list = getExceptions();
897            List<Class<? extends Throwable>> answer = new ArrayList<Class<? extends Throwable>>(list.size());
898            for (String name : list) {
899                Class<? extends Throwable> type = resolver.resolveMandatoryClass(name, Throwable.class);
900                answer.add(type);
901            }
902            return answer;
903        }
904    
905        private void setHandledFromExpressionType(RouteContext routeContext) {
906            if (getHandled() != null && handledPolicy == null && routeContext != null) {
907                handled(getHandled().createPredicate(routeContext));
908            }
909        }
910    
911        private void setContinuedFromExpressionType(RouteContext routeContext) {
912            if (getContinued() != null && continuedPolicy == null && routeContext != null) {
913                continued(getContinued().createPredicate(routeContext));
914            }
915        }
916    
917        private void setRetryWhileFromExpressionType(RouteContext routeContext) {
918            if (getRetryWhile() != null && retryWhilePolicy == null && routeContext != null) {
919                retryWhile(getRetryWhile().createPredicate(routeContext));
920            }
921        }
922    
923        private void setOnRedeliveryFromRedeliveryRef(RouteContext routeContext) {
924            // lookup onRedelivery if ref is provided
925            if (ObjectHelper.isNotEmpty(onRedeliveryRef)) {
926                // if ref is provided then use mandatory lookup to fail if not found
927                Processor onRedelivery = CamelContextHelper.mandatoryLookup(routeContext.getCamelContext(), onRedeliveryRef, Processor.class);
928                setOnRedelivery(onRedelivery);
929            }
930        }
931    
932    }