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