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