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