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