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