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