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