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.List;
022    import java.util.StringTokenizer;
023    import java.util.concurrent.atomic.AtomicBoolean;
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.XmlElementRef;
028    import javax.xml.bind.annotation.XmlRootElement;
029    import javax.xml.bind.annotation.XmlTransient;
030    import javax.xml.bind.annotation.XmlType;
031    
032    import org.apache.camel.CamelContext;
033    import org.apache.camel.Endpoint;
034    import org.apache.camel.ErrorHandlerFactory;
035    import org.apache.camel.FailedToCreateRouteException;
036    import org.apache.camel.NoSuchEndpointException;
037    import org.apache.camel.Route;
038    import org.apache.camel.ServiceStatus;
039    import org.apache.camel.ShutdownRoute;
040    import org.apache.camel.ShutdownRunningTask;
041    import org.apache.camel.StatefulService;
042    import org.apache.camel.builder.AdviceWithRouteBuilder;
043    import org.apache.camel.builder.AdviceWithTask;
044    import org.apache.camel.builder.ErrorHandlerBuilderRef;
045    import org.apache.camel.builder.RouteBuilder;
046    import org.apache.camel.impl.DefaultRouteContext;
047    import org.apache.camel.processor.interceptor.Delayer;
048    import org.apache.camel.processor.interceptor.HandleFault;
049    import org.apache.camel.processor.interceptor.StreamCaching;
050    import org.apache.camel.spi.LifecycleStrategy;
051    import org.apache.camel.spi.RouteContext;
052    import org.apache.camel.spi.RoutePolicy;
053    import org.apache.camel.util.CamelContextHelper;
054    import org.apache.camel.util.ObjectHelper;
055    
056    /**
057     * Represents an XML <route/> element
058     *
059     * @version 
060     */
061    @XmlRootElement(name = "route")
062    @XmlType(propOrder = {"inputs", "outputs"})
063    @XmlAccessorType(XmlAccessType.PROPERTY)
064    public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
065        private final AtomicBoolean prepared = new AtomicBoolean(false);
066        private List<FromDefinition> inputs = new ArrayList<FromDefinition>();
067        private List<ProcessorDefinition<?>> outputs = new ArrayList<ProcessorDefinition<?>>();
068        private String group;
069        private String streamCache;
070        private String trace;
071        private String handleFault;
072        private String delayer;
073        private String autoStartup;
074        private Integer startupOrder;
075        private List<RoutePolicy> routePolicies;
076        private String routePolicyRef;
077        private ShutdownRoute shutdownRoute;
078        private ShutdownRunningTask shutdownRunningTask;
079        private String errorHandlerRef;
080        private ErrorHandlerFactory errorHandlerBuilder;
081        // keep state whether the error handler is context scoped or not
082        // (will by default be context scoped of no explicit error handler configured)
083        private boolean contextScopedErrorHandler = true;
084    
085        public RouteDefinition() {
086        }
087    
088        public RouteDefinition(String uri) {
089            from(uri);
090        }
091    
092        public RouteDefinition(Endpoint endpoint) {
093            from(endpoint);
094        }
095    
096        /**
097         * Prepares the route definition to be ready to be added to {@link CamelContext}
098         *
099         * @param context the camel context
100         */
101        public void prepare(ModelCamelContext context) {
102            if (prepared.compareAndSet(false, true)) {
103                RouteDefinitionHelper.prepareRoute(context, this);
104            }
105        }
106    
107        /**
108         * Marks the route definition as prepared.
109         * <p/>
110         * This is needed if routes have been created by components such as
111         * <tt>camel-spring</tt> or <tt>camel-blueprint</tt>.
112         * Usually they share logic in the <tt>camel-core-xml</tt> module which prepares the routes.
113         */
114        public void markPrepared() {
115            prepared.set(true);
116        }
117    
118        @Override
119        public String toString() {
120            return "Route[" + inputs + " -> " + outputs + "]";
121        }
122    
123        @Override
124        public String getShortName() {
125            return "route";
126        }
127    
128        /**
129         * Returns the status of the route if it has been registered with a {@link CamelContext}
130         */
131        public ServiceStatus getStatus(CamelContext camelContext) {
132            if (camelContext != null) {
133                ServiceStatus answer = camelContext.getRouteStatus(this.getId());
134                if (answer == null) {
135                    answer = ServiceStatus.Stopped;
136                }
137                return answer;
138            }
139            return null;
140        }
141    
142        public boolean isStartable(CamelContext camelContext) {
143            ServiceStatus status = getStatus(camelContext);
144            if (status == null) {
145                return true;
146            } else {
147                return status.isStartable();
148            }
149        }
150    
151        public boolean isStoppable(CamelContext camelContext) {
152            ServiceStatus status = getStatus(camelContext);
153            if (status == null) {
154                return false;
155            } else {
156                return status.isStoppable();
157            }
158        }
159    
160        public List<RouteContext> addRoutes(ModelCamelContext camelContext, Collection<Route> routes) throws Exception {
161            List<RouteContext> answer = new ArrayList<RouteContext>();
162    
163            @SuppressWarnings("deprecation")
164            ErrorHandlerFactory handler = camelContext.getErrorHandlerBuilder();
165            if (handler != null) {
166                setErrorHandlerBuilderIfNull(handler);
167            }
168    
169            for (FromDefinition fromType : inputs) {
170                RouteContext routeContext;
171                try {
172                    routeContext = addRoutes(camelContext, routes, fromType);
173                } catch (FailedToCreateRouteException e) {
174                    throw e;
175                } catch (Exception e) {
176                    // wrap in exception which provide more details about which route was failing
177                    throw new FailedToCreateRouteException(getId(), toString(), e);
178                }
179                answer.add(routeContext);
180            }
181            return answer;
182        }
183    
184    
185        public Endpoint resolveEndpoint(CamelContext camelContext, String uri) throws NoSuchEndpointException {
186            ObjectHelper.notNull(camelContext, "CamelContext");
187            return CamelContextHelper.getMandatoryEndpoint(camelContext, uri);
188        }
189        
190        @Deprecated
191        public RouteDefinition adviceWith(CamelContext camelContext, RouteBuilder builder) throws Exception {
192            return adviceWith((ModelCamelContext)camelContext, builder);
193        }
194    
195        /**
196         * Advices this route with the route builder.
197         * <p/>
198         * <b>Important:</b> It is recommended to only advice a given route once (you can of course advice multiple routes).
199         * If you do it multiple times, then it may not work as expected, especially when any kind of error handling is involved.
200         * The Camel team plan for Camel 3.0 to support this as internal refactorings in the routing engine is needed to support this properly.
201         * <p/>
202         * You can use a regular {@link RouteBuilder} but the specialized {@link org.apache.camel.builder.AdviceWithRouteBuilder}
203         * has additional features when using the <a href="http://camel.apache.org/advicewith.html">advice with</a> feature.
204         * We therefore suggest you to use the {@link org.apache.camel.builder.AdviceWithRouteBuilder}.
205         * <p/>
206         * The advice process will add the interceptors, on exceptions, on completions etc. configured
207         * from the route builder to this route.
208         * <p/>
209         * This is mostly used for testing purpose to add interceptors and the likes to an existing route.
210         * <p/>
211         * Will stop and remove the old route from camel context and add and start this new advised route.
212         *
213         * @param camelContext the camel context
214         * @param builder      the route builder
215         * @return a new route which is this route merged with the route builder
216         * @throws Exception can be thrown from the route builder
217         * @see AdviceWithRouteBuilder
218         */
219        @SuppressWarnings("deprecation")
220        public RouteDefinition adviceWith(ModelCamelContext camelContext, RouteBuilder builder) throws Exception {
221            ObjectHelper.notNull(camelContext, "CamelContext");
222            ObjectHelper.notNull(builder, "RouteBuilder");
223    
224            log.debug("AdviceWith route before: {}", this);
225    
226            // inject this route into the advice route builder so it can access this route
227            // and offer features to manipulate the route directly
228            if (builder instanceof AdviceWithRouteBuilder) {
229                ((AdviceWithRouteBuilder) builder).setOriginalRoute(this);
230            }
231    
232            // configure and prepare the routes from the builder
233            RoutesDefinition routes = builder.configureRoutes(camelContext);
234    
235            log.debug("AdviceWith routes: {}", routes);
236    
237            // we can only advice with a route builder without any routes
238            if (!builder.getRouteCollection().getRoutes().isEmpty()) {
239                throw new IllegalArgumentException("You can only advice from a RouteBuilder which has no existing routes."
240                        + " Remove all routes from the route builder.");
241            }
242            // we can not advice with error handlers (if you added a new error handler in the route builder)
243            // we must check the error handler on builder is not the same as on camel context, as that would be the default
244            // context scoped error handler, in case no error handlers was configured
245            if (builder.getRouteCollection().getErrorHandlerBuilder() != null
246                    && camelContext.getErrorHandlerBuilder() != builder.getRouteCollection().getErrorHandlerBuilder()) {
247                throw new IllegalArgumentException("You can not advice with error handlers. Remove the error handlers from the route builder.");
248            }
249    
250            // stop and remove this existing route
251            camelContext.removeRouteDefinition(this);
252    
253            // any advice with tasks we should execute first?
254            if (builder instanceof AdviceWithRouteBuilder) {
255                List<AdviceWithTask> tasks = ((AdviceWithRouteBuilder) builder).getAdviceWithTasks();
256                for (AdviceWithTask task : tasks) {
257                    task.task();
258                }
259            }
260    
261            // now merge which also ensures that interceptors and the likes get mixed in correctly as well
262            RouteDefinition merged = routes.route(this);
263    
264            // add the new merged route
265            camelContext.getRouteDefinitions().add(0, merged);
266    
267            // log the merged route at info level to make it easier to end users to spot any mistakes they may have made
268            log.info("AdviceWith route after: " + merged);
269    
270            // If the camel context is started then we start the route
271            if (camelContext instanceof StatefulService) {
272                StatefulService service = (StatefulService) camelContext;
273                if (service.isStarted()) {
274                    camelContext.startRoute(merged);
275                }
276            }
277            return merged;
278        }
279    
280        // Fluent API
281        // -----------------------------------------------------------------------
282    
283        /**
284         * Creates an input to the route
285         *
286         * @param uri the from uri
287         * @return the builder
288         */
289        public RouteDefinition from(String uri) {
290            getInputs().add(new FromDefinition(uri));
291            return this;
292        }
293    
294        /**
295         * Creates an input to the route
296         *
297         * @param endpoint the from endpoint
298         * @return the builder
299         */
300        public RouteDefinition from(Endpoint endpoint) {
301            getInputs().add(new FromDefinition(endpoint));
302            return this;
303        }
304    
305        /**
306         * Creates inputs to the route
307         *
308         * @param uris the from uris
309         * @return the builder
310         */
311        public RouteDefinition from(String... uris) {
312            for (String uri : uris) {
313                getInputs().add(new FromDefinition(uri));
314            }
315            return this;
316        }
317    
318        /**
319         * Creates inputs to the route
320         *
321         * @param endpoints the from endpoints
322         * @return the builder
323         */
324        public RouteDefinition from(Endpoint... endpoints) {
325            for (Endpoint endpoint : endpoints) {
326                getInputs().add(new FromDefinition(endpoint));
327            }
328            return this;
329        }
330    
331        /**
332         * Set the group name for this route
333         *
334         * @param name the group name
335         * @return the builder
336         */
337        public RouteDefinition group(String name) {
338            setGroup(name);
339            return this;
340        }
341    
342        /**
343         * Set the route id for this route
344         *
345         * @param id the route id
346         * @return the builder
347         */
348        public RouteDefinition routeId(String id) {
349            setId(id);
350            return this;
351        }
352    
353        /**
354         * Disable stream caching for this route.
355         *
356         * @return the builder
357         */
358        public RouteDefinition noStreamCaching() {
359            setStreamCache("false");
360            StreamCaching.noStreamCaching(getInterceptStrategies());
361            return this;
362        }
363    
364        /**
365         * Enable stream caching for this route.
366         *
367         * @return the builder
368         */
369        public RouteDefinition streamCaching() {
370            setStreamCache("true");
371            StreamCaching cache = StreamCaching.getStreamCaching(getInterceptStrategies());
372            if (cache == null) {
373                cache = new StreamCaching();
374            }
375    
376            getInterceptStrategies().add(cache);
377            return this;
378        }
379    
380        /**
381         * Disable tracing for this route.
382         *
383         * @return the builder
384         */
385        public RouteDefinition noTracing() {
386            setTrace("false");
387            return this;
388        }
389    
390        /**
391         * Enable tracing for this route.
392         *
393         * @return the builder
394         */
395        public RouteDefinition tracing() {
396            setTrace("true");
397            return this;
398        }
399    
400        /**
401         * Disable handle fault for this route.
402         *
403         * @return the builder
404         */
405        public RouteDefinition noHandleFault() {
406            setHandleFault("false");
407            return this;
408        }
409    
410        /**
411         * Enable handle fault for this route.
412         *
413         * @return the builder
414         */
415        public RouteDefinition handleFault() {
416            setHandleFault("true");
417            return this;
418        }
419    
420        /**
421         * Disable delayer for this route.
422         *
423         * @return the builder
424         */
425        public RouteDefinition noDelayer() {
426            setDelayer("0");
427            return this;
428        }
429    
430        /**
431         * Enable delayer for this route.
432         *
433         * @param delay delay in millis
434         * @return the builder
435         */
436        public RouteDefinition delayer(long delay) {
437            setDelayer("" + delay);
438            return this;
439        }
440    
441        /**
442         * Installs the given <a href="http://camel.apache.org/error-handler.html">error handler</a> builder.
443         *
444         * @param errorHandlerBuilder the error handler to be used by default for all child routes
445         * @return the current builder with the error handler configured
446         */
447        public RouteDefinition errorHandler(ErrorHandlerFactory errorHandlerBuilder) {
448            setErrorHandlerBuilder(errorHandlerBuilder);
449            // we are now using a route scoped error handler
450            contextScopedErrorHandler = false;
451            return this;
452        }
453    
454        /**
455         * Disables this route from being auto started when Camel starts.
456         *
457         * @return the builder
458         */
459        public RouteDefinition noAutoStartup() {
460            setAutoStartup("false");
461            return this;
462        }
463    
464        /**
465         * Sets the auto startup property on this route.
466         *
467         * @param autoStartup - String indicator ("true" or "false")
468         * @return the builder
469         */
470        public RouteDefinition autoStartup(String autoStartup) {
471            setAutoStartup(autoStartup);
472            return this;
473        }
474    
475        /**
476         * Sets the auto startup property on this route.
477         *
478         * @param autoStartup - boolean indicator
479         * @return the builder
480         */
481        public RouteDefinition autoStartup(boolean autoStartup) {
482            setAutoStartup(Boolean.toString(autoStartup));
483            return this;
484        }
485    
486        /**
487         * Configures the startup order for this route
488         * <p/>
489         * Camel will reorder routes and star them ordered by 0..N where 0 is the lowest number and N the highest number.
490         * Camel will stop routes in reverse order when its stopping.
491         *
492         * @param order the order represented as a number
493         * @return the builder
494         */
495        public RouteDefinition startupOrder(int order) {
496            setStartupOrder(order);
497            return this;
498        }
499    
500        /**
501         * Configures route policies for this route
502         *
503         * @param policies the route policies
504         * @return the builder
505         */
506        public RouteDefinition routePolicy(RoutePolicy... policies) {
507            if (routePolicies == null) {
508                routePolicies = new ArrayList<RoutePolicy>();
509            }
510            for (RoutePolicy policy : policies) {
511                routePolicies.add(policy);
512            }
513            return this;
514        }
515    
516        /**
517         * Configures a route policy for this route
518         *
519         * @param routePolicyRef reference to a {@link RoutePolicy} to lookup and use.
520         *                       You can specify multiple references by separating using comma.
521         * @return the builder
522         */
523        public RouteDefinition routePolicyRef(String routePolicyRef) {
524            setRoutePolicyRef(routePolicyRef);
525            return this;
526        }
527    
528        /**
529         * Configures a shutdown route option.
530         *
531         * @param shutdownRoute the option to use when shutting down this route
532         * @return the builder
533         */
534        public RouteDefinition shutdownRoute(ShutdownRoute shutdownRoute) {
535            setShutdownRoute(shutdownRoute);
536            return this;
537        }
538    
539        /**
540         * Configures a shutdown running task option.
541         *
542         * @param shutdownRunningTask the option to use when shutting down and how to act upon running tasks.
543         * @return the builder
544         */
545        public RouteDefinition shutdownRunningTask(ShutdownRunningTask shutdownRunningTask) {
546            setShutdownRunningTask(shutdownRunningTask);
547            return this;
548        }
549    
550        // Properties
551        // -----------------------------------------------------------------------
552    
553        public List<FromDefinition> getInputs() {
554            return inputs;
555        }
556    
557        @XmlElementRef
558        public void setInputs(List<FromDefinition> inputs) {
559            this.inputs = inputs;
560        }
561    
562        public List<ProcessorDefinition<?>> getOutputs() {
563            return outputs;
564        }
565    
566        @XmlElementRef
567        public void setOutputs(List<ProcessorDefinition<?>> outputs) {
568            this.outputs = outputs;
569    
570            if (outputs != null) {
571                for (ProcessorDefinition<?> output : outputs) {
572                    configureChild(output);
573                }
574            }
575        }
576    
577        public boolean isOutputSupported() {
578            return true;
579        }
580    
581        /**
582         * The group that this route belongs to; could be the name of the RouteBuilder class
583         * or be explicitly configured in the XML.
584         * <p/>
585         * May be null.
586         */
587        public String getGroup() {
588            return group;
589        }
590    
591        @XmlAttribute
592        public void setGroup(String group) {
593            this.group = group;
594        }
595    
596        public String getStreamCache() {
597            return streamCache;
598        }
599    
600        @XmlAttribute
601        public void setStreamCache(String streamCache) {
602            this.streamCache = streamCache;
603        }
604    
605        public String getTrace() {
606            return trace;
607        }
608    
609        @XmlAttribute
610        public void setTrace(String trace) {
611            this.trace = trace;
612        }
613    
614        public String getHandleFault() {
615            return handleFault;
616        }
617    
618        @XmlAttribute
619        public void setHandleFault(String handleFault) {
620            this.handleFault = handleFault;
621        }
622    
623        public String getDelayer() {
624            return delayer;
625        }
626    
627        @XmlAttribute
628        public void setDelayer(String delayer) {
629            this.delayer = delayer;
630        }
631    
632        public String getAutoStartup() {
633            return autoStartup;
634        }
635    
636        public boolean isAutoStartup(CamelContext camelContext) throws Exception {
637            if (getAutoStartup() == null) {
638                // should auto startup by default
639                return true;
640            }
641            Boolean isAutoStartup = CamelContextHelper.parseBoolean(camelContext, getAutoStartup());
642            return isAutoStartup != null && isAutoStartup;
643        }
644    
645        @XmlAttribute
646        public void setAutoStartup(String autoStartup) {
647            this.autoStartup = autoStartup;
648        }
649    
650        public Integer getStartupOrder() {
651            return startupOrder;
652        }
653    
654        @XmlAttribute
655        public void setStartupOrder(Integer startupOrder) {
656            this.startupOrder = startupOrder;
657        }
658    
659        /**
660         * Sets the bean ref name of the error handler builder to use on this route
661         */
662        @XmlAttribute
663        public void setErrorHandlerRef(String errorHandlerRef) {
664            this.errorHandlerRef = errorHandlerRef;
665            // we use an specific error handler ref (from Spring DSL) then wrap that
666            // with a error handler build ref so Camel knows its not just the default one
667            setErrorHandlerBuilder(new ErrorHandlerBuilderRef(errorHandlerRef));
668        }
669    
670        public String getErrorHandlerRef() {
671            return errorHandlerRef;
672        }
673    
674        /**
675         * Sets the error handler if one is not already set
676         */
677        public void setErrorHandlerBuilderIfNull(ErrorHandlerFactory errorHandlerBuilder) {
678            if (this.errorHandlerBuilder == null) {
679                setErrorHandlerBuilder(errorHandlerBuilder);
680            }
681        }
682    
683        @XmlAttribute
684        public void setRoutePolicyRef(String routePolicyRef) {
685            this.routePolicyRef = routePolicyRef;
686        }
687    
688        public String getRoutePolicyRef() {
689            return routePolicyRef;
690        }
691    
692        public List<RoutePolicy> getRoutePolicies() {
693            return routePolicies;
694        }
695    
696        @XmlTransient
697        public void setRoutePolicies(List<RoutePolicy> routePolicies) {
698            this.routePolicies = routePolicies;
699        }
700    
701        public ShutdownRoute getShutdownRoute() {
702            return shutdownRoute;
703        }
704    
705        @XmlAttribute
706        public void setShutdownRoute(ShutdownRoute shutdownRoute) {
707            this.shutdownRoute = shutdownRoute;
708        }
709    
710        public ShutdownRunningTask getShutdownRunningTask() {
711            return shutdownRunningTask;
712        }
713    
714        @XmlAttribute
715        public void setShutdownRunningTask(ShutdownRunningTask shutdownRunningTask) {
716            this.shutdownRunningTask = shutdownRunningTask;
717        }
718        
719        private ErrorHandlerFactory createErrorHandlerBuilder() {
720            if (errorHandlerRef != null) {
721                return new ErrorHandlerBuilderRef(errorHandlerRef);
722            }
723    
724            // return a reference to the default error handler
725            return new ErrorHandlerBuilderRef(ErrorHandlerBuilderRef.DEFAULT_ERROR_HANDLER_BUILDER);
726        }
727    
728        @XmlTransient
729        public ErrorHandlerFactory getErrorHandlerBuilder() {
730            if (errorHandlerBuilder == null) {
731                errorHandlerBuilder = createErrorHandlerBuilder();
732            }
733            return errorHandlerBuilder;
734        }
735    
736        /**
737         * Sets the error handler to use with processors created by this builder
738         */
739        public void setErrorHandlerBuilder(ErrorHandlerFactory errorHandlerBuilder) {
740            this.errorHandlerBuilder = errorHandlerBuilder;
741        }
742    
743        @SuppressWarnings("deprecation")
744        public boolean isContextScopedErrorHandler(CamelContext context) {
745            if (!contextScopedErrorHandler) {
746                return false;
747            }
748            // if error handler ref is configured it may refer to a context scoped, so we need to check this first
749            // the XML DSL will configure error handlers using refs, so we need this additional test
750            if (errorHandlerRef != null) {
751                ErrorHandlerFactory routeScoped = getErrorHandlerBuilder();
752                ErrorHandlerFactory contextScoped = context.getErrorHandlerBuilder();
753                return routeScoped != null && contextScoped != null && routeScoped == contextScoped;
754            }
755    
756            return contextScopedErrorHandler;
757        }
758    
759        // Implementation methods
760        // -------------------------------------------------------------------------
761        protected RouteContext addRoutes(CamelContext camelContext, Collection<Route> routes, FromDefinition fromType) throws Exception {
762            RouteContext routeContext = new DefaultRouteContext(camelContext, this, fromType, routes);
763    
764            // configure tracing
765            if (trace != null) {
766                Boolean isTrace = CamelContextHelper.parseBoolean(camelContext, getTrace());
767                if (isTrace != null) {
768                    routeContext.setTracing(isTrace);
769                    if (isTrace) {
770                        log.debug("Tracing is enabled on route: {}", getId());
771                        // tracing is added in the DefaultChannel so we can enable it on the fly
772                    }
773                }
774            }
775    
776            // configure stream caching
777            if (streamCache != null) {
778                Boolean isStreamCache = CamelContextHelper.parseBoolean(camelContext, getStreamCache());
779                if (isStreamCache != null) {
780                    routeContext.setStreamCaching(isStreamCache);
781                    if (isStreamCache) {
782                        log.debug("StreamCaching is enabled on route: {}", getId());
783                        // only add a new stream cache if not already a global configured on camel context
784                        if (StreamCaching.getStreamCaching(camelContext) == null) {
785                            addInterceptStrategy(new StreamCaching());
786                        }
787                    }
788                }
789            }
790    
791            // configure handle fault
792            if (handleFault != null) {
793                Boolean isHandleFault = CamelContextHelper.parseBoolean(camelContext, getHandleFault());
794                if (isHandleFault != null) {
795                    routeContext.setHandleFault(isHandleFault);
796                    if (isHandleFault) {
797                        log.debug("HandleFault is enabled on route: {}", getId());
798                        // only add a new handle fault if not already a global configured on camel context
799                        if (HandleFault.getHandleFault(camelContext) == null) {
800                            addInterceptStrategy(new HandleFault());
801                        }
802                    }
803                }
804            }
805    
806            // configure delayer
807            if (delayer != null) {
808                Long delayer = CamelContextHelper.parseLong(camelContext, getDelayer());
809                if (delayer != null) {
810                    routeContext.setDelayer(delayer);
811                    if (delayer > 0) {
812                        log.debug("Delayer is enabled with: {} ms. on route: {}", delayer, getId());
813                        addInterceptStrategy(new Delayer(delayer));
814                    } else {
815                        log.debug("Delayer is disabled on route: {}", getId());
816                    }
817                }
818            }
819    
820            // configure route policy
821            if (routePolicies != null && !routePolicies.isEmpty()) {
822                for (RoutePolicy policy : routePolicies) {
823                    log.debug("RoutePolicy is enabled: {} on route: {}", policy, getId());
824                    routeContext.getRoutePolicyList().add(policy);
825                }
826            }
827            if (routePolicyRef != null) {
828                StringTokenizer policyTokens = new StringTokenizer(routePolicyRef, ",");
829                while (policyTokens.hasMoreTokens()) {
830                    String ref = policyTokens.nextToken().trim();
831                    RoutePolicy policy = CamelContextHelper.mandatoryLookup(camelContext, ref, RoutePolicy.class);
832                    log.debug("RoutePolicy is enabled: {} on route: {}", policy, getId());
833                    routeContext.getRoutePolicyList().add(policy);
834                }
835            }
836    
837            // configure auto startup
838            Boolean isAutoStartup = CamelContextHelper.parseBoolean(camelContext, getAutoStartup());
839            if (isAutoStartup != null) {
840                log.debug("Using AutoStartup {} on route: {}", isAutoStartup, getId());
841                routeContext.setAutoStartup(isAutoStartup);
842            }
843    
844            // configure shutdown
845            if (shutdownRoute != null) {
846                log.debug("Using ShutdownRoute {} on route: {}", getShutdownRoute(), getId());
847                routeContext.setShutdownRoute(getShutdownRoute());
848            }
849            if (shutdownRunningTask != null) {
850                log.debug("Using ShutdownRunningTask {} on route: {}", getShutdownRunningTask(), getId());
851                routeContext.setShutdownRunningTask(getShutdownRunningTask());
852            }
853    
854            // should inherit the intercept strategies we have defined
855            routeContext.setInterceptStrategies(this.getInterceptStrategies());
856            // force endpoint resolution
857            routeContext.getEndpoint();
858            if (camelContext != null) {
859                for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) {
860                    strategy.onRouteContextCreate(routeContext);
861                }
862            }
863    
864            // validate route has output processors
865            if (!ProcessorDefinitionHelper.hasOutputs(outputs, true)) {
866                RouteDefinition route = routeContext.getRoute();
867                String at = fromType.toString();
868                Exception cause = new IllegalArgumentException("Route " + route.getId() + " has no output processors."
869                        + " You need to add outputs to the route such as to(\"log:foo\").");
870                throw new FailedToCreateRouteException(route.getId(), route.toString(), at, cause);
871            }
872    
873            List<ProcessorDefinition<?>> list = new ArrayList<ProcessorDefinition<?>>(outputs);
874            for (ProcessorDefinition<?> output : list) {
875                try {
876                    output.addRoutes(routeContext, routes);
877                } catch (Exception e) {
878                    RouteDefinition route = routeContext.getRoute();
879                    throw new FailedToCreateRouteException(route.getId(), route.toString(), output.toString(), e);
880                }
881            }
882    
883            routeContext.commit();
884            return routeContext;
885        }
886    }