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 */
017package org.apache.camel.model;
018
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024import javax.xml.bind.annotation.XmlAccessType;
025import javax.xml.bind.annotation.XmlAccessorType;
026import javax.xml.bind.annotation.XmlAttribute;
027import javax.xml.bind.annotation.XmlElement;
028import javax.xml.bind.annotation.XmlElementRef;
029import javax.xml.bind.annotation.XmlRootElement;
030import javax.xml.bind.annotation.XmlTransient;
031
032import org.apache.camel.CamelContext;
033import org.apache.camel.Expression;
034import org.apache.camel.LoggingLevel;
035import org.apache.camel.Predicate;
036import org.apache.camel.Processor;
037import org.apache.camel.Route;
038import org.apache.camel.builder.ErrorHandlerBuilder;
039import org.apache.camel.builder.ExpressionBuilder;
040import org.apache.camel.processor.CatchProcessor;
041import org.apache.camel.processor.FatalFallbackErrorHandler;
042import org.apache.camel.processor.RedeliveryPolicy;
043import org.apache.camel.spi.ClassResolver;
044import org.apache.camel.spi.RouteContext;
045import org.apache.camel.util.CamelContextHelper;
046import org.apache.camel.util.ExpressionToPredicateAdapter;
047import 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)
056public 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}