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