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