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