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.impl;
018
019import java.util.Collection;
020import java.util.HashMap;
021import java.util.HashSet;
022import java.util.List;
023import java.util.Map;
024import java.util.Properties;
025import java.util.Set;
026import java.util.function.Function;
027
028import org.apache.camel.CamelContext;
029import org.apache.camel.Expression;
030import org.apache.camel.ExtendedCamelContext;
031import org.apache.camel.FailedToStartRouteException;
032import org.apache.camel.Predicate;
033import org.apache.camel.Processor;
034import org.apache.camel.Route;
035import org.apache.camel.RouteTemplateContext;
036import org.apache.camel.StartupStep;
037import org.apache.camel.ValueHolder;
038import org.apache.camel.api.management.JmxSystemPropertyKeys;
039import org.apache.camel.builder.AdviceWith;
040import org.apache.camel.builder.AdviceWithRouteBuilder;
041import org.apache.camel.impl.engine.DefaultExecutorServiceManager;
042import org.apache.camel.impl.engine.RouteService;
043import org.apache.camel.impl.engine.SimpleCamelContext;
044import org.apache.camel.impl.engine.TransformerKey;
045import org.apache.camel.impl.engine.ValidatorKey;
046import org.apache.camel.impl.scan.AssignableToPackageScanFilter;
047import org.apache.camel.impl.scan.InvertingPackageScanFilter;
048import org.apache.camel.model.DataFormatDefinition;
049import org.apache.camel.model.FaultToleranceConfigurationDefinition;
050import org.apache.camel.model.HystrixConfigurationDefinition;
051import org.apache.camel.model.Model;
052import org.apache.camel.model.ModelCamelContext;
053import org.apache.camel.model.ModelLifecycleStrategy;
054import org.apache.camel.model.ProcessorDefinition;
055import org.apache.camel.model.ProcessorDefinitionHelper;
056import org.apache.camel.model.Resilience4jConfigurationDefinition;
057import org.apache.camel.model.RouteDefinition;
058import org.apache.camel.model.RouteDefinitionHelper;
059import org.apache.camel.model.RouteTemplateDefinition;
060import org.apache.camel.model.RouteTemplatesDefinition;
061import org.apache.camel.model.RoutesDefinition;
062import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
063import org.apache.camel.model.language.ExpressionDefinition;
064import org.apache.camel.model.rest.RestDefinition;
065import org.apache.camel.model.rest.RestsDefinition;
066import org.apache.camel.model.transformer.TransformerDefinition;
067import org.apache.camel.model.validator.ValidatorDefinition;
068import org.apache.camel.spi.BeanRepository;
069import org.apache.camel.spi.DataFormat;
070import org.apache.camel.spi.DataType;
071import org.apache.camel.spi.ExecutorServiceManager;
072import org.apache.camel.spi.LocalBeanRepositoryAware;
073import org.apache.camel.spi.ModelReifierFactory;
074import org.apache.camel.spi.ModelToXMLDumper;
075import org.apache.camel.spi.PackageScanClassResolver;
076import org.apache.camel.spi.PropertiesComponent;
077import org.apache.camel.spi.Registry;
078import org.apache.camel.spi.StartupStepRecorder;
079import org.apache.camel.spi.Transformer;
080import org.apache.camel.spi.UuidGenerator;
081import org.apache.camel.spi.Validator;
082import org.apache.camel.support.CamelContextHelper;
083import org.apache.camel.support.DefaultRegistry;
084import org.apache.camel.support.LocalBeanRegistry;
085import org.apache.camel.support.SimpleUuidGenerator;
086import org.apache.camel.util.ObjectHelper;
087import org.apache.camel.util.StopWatch;
088import org.apache.camel.util.StringHelper;
089import org.slf4j.Logger;
090import org.slf4j.LoggerFactory;
091
092/**
093 * Represents the context used to configure routes and the policies to use.
094 */
095public class DefaultCamelContext extends SimpleCamelContext implements ModelCamelContext {
096
097    protected static final ThreadLocal<OptionHolder> OPTIONS = ThreadLocal.withInitial(OptionHolder::new);
098    private static final Logger LOG = LoggerFactory.getLogger(DefaultCamelContext.class);
099    private static final UuidGenerator UUID = new SimpleUuidGenerator();
100
101    private Model model = new DefaultModel(this);
102
103    /**
104     * Creates the {@link ModelCamelContext} using {@link org.apache.camel.support.DefaultRegistry} as registry.
105     * <p/>
106     * Use one of the other constructors to force use an explicit registry.
107     */
108    public DefaultCamelContext() {
109        this(true);
110    }
111
112    /**
113     * Creates the {@link CamelContext} using the given {@link BeanRepository} as first-choice repository, and the
114     * {@link org.apache.camel.support.SimpleRegistry} as fallback, via the {@link DefaultRegistry} implementation.
115     *
116     * @param repository the bean repository.
117     */
118    public DefaultCamelContext(BeanRepository repository) {
119        this(new DefaultRegistry(repository));
120    }
121
122    /**
123     * Creates the {@link ModelCamelContext} using the given registry
124     *
125     * @param registry the registry
126     */
127    public DefaultCamelContext(Registry registry) {
128        this();
129        setRegistry(registry);
130    }
131
132    public DefaultCamelContext(boolean init) {
133        super(init);
134        if (isDisableJmx()) {
135            disableJMX();
136        }
137    }
138
139    @Override
140    protected void doDumpRoutes() {
141        ModelToXMLDumper dumper = getModelToXMLDumper();
142
143        int size = getRouteDefinitions().size();
144        if (size > 0) {
145            LOG.info("Dumping {} routes as XML", size);
146            // for XML to output nicely all routes in one XML then lets put them into <routes>
147            RoutesDefinition def = new RoutesDefinition();
148            def.setRoutes(getRouteDefinitions());
149            try {
150                String xml = dumper.dumpModelAsXml(this, def, true, true);
151                // lets separate routes with empty line
152                xml = StringHelper.replaceFirst(xml, "xmlns=\"http://camel.apache.org/schema/spring\">",
153                        "xmlns=\"http://camel.apache.org/schema/spring\">\n");
154                xml = StringHelper.replaceAll(xml, "</route>", "</route>\n");
155                LOG.info("\n\n{}\n", xml);
156            } catch (Exception e) {
157                LOG.warn("Error dumping routes to XML due to {}. This exception is ignored.", e.getMessage(), e);
158            }
159        }
160
161        size = getRestDefinitions().size();
162        if (size > 0) {
163            LOG.info("Dumping {} rests as XML", size);
164            // for XML to output nicely all routes in one XML then lets put them into <routes>
165            RestsDefinition def = new RestsDefinition();
166            def.setRests(getRestDefinitions());
167            try {
168                String xml = dumper.dumpModelAsXml(this, def, true, true);
169                // lets separate rests with empty line
170                xml = StringHelper.replaceFirst(xml, "xmlns=\"http://camel.apache.org/schema/spring\">",
171                        "xmlns=\"http://camel.apache.org/schema/spring\">\n");
172                xml = StringHelper.replaceAll(xml, "</rest>", "</rest>\n");
173                LOG.info("\n\n{}\n", xml);
174            } catch (Exception e) {
175                LOG.warn("Error dumping rests to XML due to {}. This exception is ignored.", e.getMessage(), e);
176            }
177        }
178
179        size = getRouteTemplateDefinitions().size();
180        if (size > 0) {
181            LOG.info("Dumping {} route templates as XML", size);
182            // for XML to output nicely all routes in one XML then lets put them into <routes>
183            RouteTemplatesDefinition def = new RouteTemplatesDefinition();
184            def.setRouteTemplates(getRouteTemplateDefinitions());
185            try {
186                String xml = dumper.dumpModelAsXml(this, def, true, true);
187                // lets separate rests with empty line
188                xml = StringHelper.replaceFirst(xml, "xmlns=\"http://camel.apache.org/schema/spring\">",
189                        "xmlns=\"http://camel.apache.org/schema/spring\">\n");
190                xml = StringHelper.replaceAll(xml, "</routeTemplate>", "</routeTemplate>\n");
191                LOG.info("\n\n{}\n", xml);
192            } catch (Exception e) {
193                LOG.warn("Error dumping route-templates to XML due to {}. This exception is ignored.", e.getMessage(), e);
194            }
195        }
196    }
197
198    public static void setNoStart(boolean b) {
199        getOptions().noStart = b;
200    }
201
202    public static boolean isNoStart() {
203        return getOptions().noStart;
204    }
205
206    public static void setDisableJmx(boolean b) {
207        getOptions().disableJmx = b;
208    }
209
210    public static boolean isDisableJmx() {
211        return getOptions().disableJmx;
212    }
213
214    @Override
215    public String getTestExcludeRoutes() {
216        return getExcludeRoutes();
217    }
218
219    public static String getExcludeRoutes() {
220        return getOptions().excludeRoutes;
221    }
222
223    public static void setExcludeRoutes(String s) {
224        getOptions().excludeRoutes = s;
225    }
226
227    public static void clearOptions() {
228        OPTIONS.set(new OptionHolder());
229    }
230
231    private static OptionHolder getOptions() {
232        return OPTIONS.get();
233    }
234
235    @Override
236    public void start() {
237        // for example from unit testing we want to start Camel later (manually)
238        if (isNoStart()) {
239            LOG.trace("Ignoring start() as NO_START is true");
240            return;
241        }
242
243        if (!isStarted() && !isStarting()) {
244            StopWatch watch = new StopWatch();
245            super.start();
246            LOG.debug("start() took {} millis", watch.taken());
247        } else {
248            // ignore as Camel is already started
249            LOG.trace("Ignoring start() as Camel is already started");
250        }
251    }
252
253    @Override
254    protected PackageScanClassResolver createPackageScanClassResolver() {
255        PackageScanClassResolver resolver = super.createPackageScanClassResolver();
256        String excluded = getExcludeRoutes();
257        if (ObjectHelper.isNotEmpty(excluded)) {
258            Set<Class<?>> excludedClasses = new HashSet<>();
259            for (String str : excluded.split(",")) {
260                excludedClasses.add(getClassResolver().resolveClass(str));
261            }
262            resolver.addFilter(new InvertingPackageScanFilter(new AssignableToPackageScanFilter(excludedClasses)));
263        }
264        return resolver;
265    }
266
267    @Override
268    public void disposeModel() {
269        LOG.debug("Disposing Model on CamelContext");
270        model = null;
271    }
272
273    @Override
274    public void addModelLifecycleStrategy(ModelLifecycleStrategy modelLifecycleStrategy) {
275        if (model == null && isLightweight()) {
276            throw new IllegalStateException("Access to model not supported in lightweight mode");
277        }
278        model.addModelLifecycleStrategy(modelLifecycleStrategy);
279    }
280
281    @Override
282    public List<ModelLifecycleStrategy> getModelLifecycleStrategies() {
283        if (model == null && isLightweight()) {
284            throw new IllegalStateException("Access to model not supported in lightweight mode");
285        }
286        return model.getModelLifecycleStrategies();
287    }
288
289    @Override
290    public List<RouteDefinition> getRouteDefinitions() {
291        if (model == null && isLightweight()) {
292            throw new IllegalStateException("Access to model not supported in lightweight mode");
293        }
294        return model.getRouteDefinitions();
295    }
296
297    @Override
298    public RouteDefinition getRouteDefinition(String id) {
299        if (model == null && isLightweight()) {
300            throw new IllegalStateException("Access to model not supported in lightweight mode");
301        }
302        return model.getRouteDefinition(id);
303    }
304
305    @Override
306    public void addRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
307        if (model == null && isLightweight()) {
308            throw new IllegalStateException("Access to model not supported in lightweight mode");
309        }
310        model.addRouteDefinitions(routeDefinitions);
311    }
312
313    @Override
314    public void addRouteDefinition(RouteDefinition routeDefinition) throws Exception {
315        if (model == null && isLightweight()) {
316            throw new IllegalStateException("Access to model not supported in lightweight mode");
317        }
318        model.addRouteDefinition(routeDefinition);
319    }
320
321    @Override
322    public void removeRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
323        if (model == null && isLightweight()) {
324            throw new IllegalStateException("Access to model not supported in lightweight mode");
325        }
326        model.removeRouteDefinitions(routeDefinitions);
327    }
328
329    @Override
330    public void removeRouteDefinition(RouteDefinition routeDefinition) throws Exception {
331        if (model == null && isLightweight()) {
332            throw new IllegalStateException("Access to model not supported in lightweight mode");
333        }
334        model.removeRouteDefinition(routeDefinition);
335    }
336
337    @Override
338    public List<RouteTemplateDefinition> getRouteTemplateDefinitions() {
339        if (model == null && isLightweight()) {
340            throw new IllegalStateException("Access to model not supported in lightweight mode");
341        }
342        return model.getRouteTemplateDefinitions();
343    }
344
345    @Override
346    public RouteTemplateDefinition getRouteTemplateDefinition(String id) {
347        if (model == null && isLightweight()) {
348            throw new IllegalStateException("Access to model not supported in lightweight mode");
349        }
350        return model.getRouteTemplateDefinition(id);
351    }
352
353    @Override
354    public void addRouteTemplateDefinitions(Collection<RouteTemplateDefinition> routeTemplateDefinitions) throws Exception {
355        if (model == null && isLightweight()) {
356            throw new IllegalStateException("Access to model not supported in lightweight mode");
357        }
358        model.addRouteTemplateDefinitions(routeTemplateDefinitions);
359    }
360
361    @Override
362    public void addRouteTemplateDefinition(RouteTemplateDefinition routeTemplateDefinition) throws Exception {
363        if (model == null && isLightweight()) {
364            throw new IllegalStateException("Access to model not supported in lightweight mode");
365        }
366        model.addRouteTemplateDefinition(routeTemplateDefinition);
367    }
368
369    @Override
370    public void removeRouteTemplateDefinitions(Collection<RouteTemplateDefinition> routeTemplateDefinitions) throws Exception {
371        if (model == null && isLightweight()) {
372            throw new IllegalStateException("Access to model not supported in lightweight mode");
373        }
374        model.removeRouteTemplateDefinitions(routeTemplateDefinitions);
375    }
376
377    @Override
378    public void removeRouteTemplateDefinition(RouteTemplateDefinition routeTemplateDefinition) throws Exception {
379        if (model == null && isLightweight()) {
380            throw new IllegalStateException("Access to model not supported in lightweight mode");
381        }
382        model.removeRouteTemplateDefinition(routeTemplateDefinition);
383    }
384
385    @Override
386    public void addRouteTemplateDefinitionConverter(String templateIdPattern, RouteTemplateDefinition.Converter converter) {
387        if (model == null && isLightweight()) {
388            throw new IllegalStateException("Access to model not supported in lightweight mode");
389        }
390        model.addRouteTemplateDefinitionConverter(templateIdPattern, converter);
391    }
392
393    @Override
394    public String addRouteFromTemplate(String routeId, String routeTemplateId, Map<String, Object> parameters)
395            throws Exception {
396        if (model == null && isLightweight()) {
397            throw new IllegalStateException("Access to model not supported in lightweight mode");
398        }
399        return model.addRouteFromTemplate(routeId, routeTemplateId, parameters);
400    }
401
402    @Override
403    public String addRouteFromTemplate(String routeId, String routeTemplateId, RouteTemplateContext routeTemplateContext)
404            throws Exception {
405        if (model == null && isLightweight()) {
406            throw new IllegalStateException("Access to model not supported in lightweight mode");
407        }
408        return model.addRouteFromTemplate(routeId, routeTemplateId, routeTemplateContext);
409    }
410
411    @Override
412    public List<RestDefinition> getRestDefinitions() {
413        if (model == null && isLightweight()) {
414            throw new IllegalStateException("Access to model not supported in lightweight mode");
415        }
416        return model.getRestDefinitions();
417    }
418
419    @Override
420    public void addRestDefinitions(Collection<RestDefinition> restDefinitions, boolean addToRoutes) throws Exception {
421        if (model == null && isLightweight()) {
422            throw new IllegalStateException("Access to model not supported in lightweight mode");
423        }
424        model.addRestDefinitions(restDefinitions, addToRoutes);
425    }
426
427    @Override
428    public void setDataFormats(Map<String, DataFormatDefinition> dataFormats) {
429        if (model == null && isLightweight()) {
430            throw new IllegalStateException("Access to model not supported in lightweight mode");
431        }
432        model.setDataFormats(dataFormats);
433    }
434
435    @Override
436    public Map<String, DataFormatDefinition> getDataFormats() {
437        if (model == null && isLightweight()) {
438            throw new IllegalStateException("Access to model not supported in lightweight mode");
439        }
440        return model.getDataFormats();
441    }
442
443    @Override
444    public DataFormatDefinition resolveDataFormatDefinition(String name) {
445        if (model == null && isLightweight()) {
446            throw new IllegalStateException("Access to model not supported in lightweight mode");
447        }
448        return model.resolveDataFormatDefinition(name);
449    }
450
451    @Override
452    public ProcessorDefinition<?> getProcessorDefinition(String id) {
453        if (model == null && isLightweight()) {
454            throw new IllegalStateException("Access to model not supported in lightweight mode");
455        }
456        return model.getProcessorDefinition(id);
457    }
458
459    @Override
460    public <T extends ProcessorDefinition<T>> T getProcessorDefinition(String id, Class<T> type) {
461        if (model == null && isLightweight()) {
462            throw new IllegalStateException("Access to model not supported in lightweight mode");
463        }
464        return model.getProcessorDefinition(id, type);
465    }
466
467    @Override
468    public void setValidators(List<ValidatorDefinition> validators) {
469        if (model == null && isLightweight()) {
470            throw new IllegalStateException("Access to model not supported in lightweight mode");
471        }
472        model.setValidators(validators);
473    }
474
475    @Override
476    public HystrixConfigurationDefinition getHystrixConfiguration(String id) {
477        if (model == null && isLightweight()) {
478            throw new IllegalStateException("Access to model not supported in lightweight mode");
479        }
480        return model.getHystrixConfiguration(id);
481    }
482
483    @Override
484    public void setHystrixConfiguration(HystrixConfigurationDefinition configuration) {
485        if (model == null && isLightweight()) {
486            throw new IllegalStateException("Access to model not supported in lightweight mode");
487        }
488        model.setHystrixConfiguration(configuration);
489    }
490
491    @Override
492    public void setHystrixConfigurations(List<HystrixConfigurationDefinition> configurations) {
493        if (model == null && isLightweight()) {
494            throw new IllegalStateException("Access to model not supported in lightweight mode");
495        }
496        model.setHystrixConfigurations(configurations);
497    }
498
499    @Override
500    public void addHystrixConfiguration(String id, HystrixConfigurationDefinition configuration) {
501        if (model == null && isLightweight()) {
502            throw new IllegalStateException("Access to model not supported in lightweight mode");
503        }
504        model.addHystrixConfiguration(id, configuration);
505    }
506
507    @Override
508    public Resilience4jConfigurationDefinition getResilience4jConfiguration(String id) {
509        if (model == null && isLightweight()) {
510            throw new IllegalStateException("Access to model not supported in lightweight mode");
511        }
512        return model.getResilience4jConfiguration(id);
513    }
514
515    @Override
516    public void setResilience4jConfiguration(Resilience4jConfigurationDefinition configuration) {
517        if (model == null && isLightweight()) {
518            throw new IllegalStateException("Access to model not supported in lightweight mode");
519        }
520        model.setResilience4jConfiguration(configuration);
521    }
522
523    @Override
524    public void setResilience4jConfigurations(List<Resilience4jConfigurationDefinition> configurations) {
525        if (model == null && isLightweight()) {
526            throw new IllegalStateException("Access to model not supported in lightweight mode");
527        }
528        model.setResilience4jConfigurations(configurations);
529    }
530
531    @Override
532    public void addResilience4jConfiguration(String id, Resilience4jConfigurationDefinition configuration) {
533        if (model == null && isLightweight()) {
534            throw new IllegalStateException("Access to model not supported in lightweight mode");
535        }
536        model.addResilience4jConfiguration(id, configuration);
537    }
538
539    @Override
540    public FaultToleranceConfigurationDefinition getFaultToleranceConfiguration(String id) {
541        if (model == null && isLightweight()) {
542            throw new IllegalStateException("Access to model not supported in lightweight mode");
543        }
544        return model.getFaultToleranceConfiguration(id);
545    }
546
547    @Override
548    public void setFaultToleranceConfiguration(FaultToleranceConfigurationDefinition configuration) {
549        if (model == null && isLightweight()) {
550            throw new IllegalStateException("Access to model not supported in lightweight mode");
551        }
552        model.setFaultToleranceConfiguration(configuration);
553    }
554
555    @Override
556    public void setFaultToleranceConfigurations(List<FaultToleranceConfigurationDefinition> configurations) {
557        if (model == null && isLightweight()) {
558            throw new IllegalStateException("Access to model not supported in lightweight mode");
559        }
560        model.setFaultToleranceConfigurations(configurations);
561    }
562
563    @Override
564    public void addFaultToleranceConfiguration(String id, FaultToleranceConfigurationDefinition configuration) {
565        if (model == null && isLightweight()) {
566            throw new IllegalStateException("Access to model not supported in lightweight mode");
567        }
568        model.addFaultToleranceConfiguration(id, configuration);
569    }
570
571    @Override
572    public List<ValidatorDefinition> getValidators() {
573        if (model == null && isLightweight()) {
574            throw new IllegalStateException("Access to model not supported in lightweight mode");
575        }
576        return model.getValidators();
577    }
578
579    @Override
580    public void setTransformers(List<TransformerDefinition> transformers) {
581        if (model == null && isLightweight()) {
582            throw new IllegalStateException("Access to model not supported in lightweight mode");
583        }
584        model.setTransformers(transformers);
585    }
586
587    @Override
588    public List<TransformerDefinition> getTransformers() {
589        if (model == null && isLightweight()) {
590            throw new IllegalStateException("Access to model not supported in lightweight mode");
591        }
592        return model.getTransformers();
593    }
594
595    @Override
596    public ServiceCallConfigurationDefinition getServiceCallConfiguration(String serviceName) {
597        if (model == null && isLightweight()) {
598            throw new IllegalStateException("Access to model not supported in lightweight mode");
599        }
600        return model.getServiceCallConfiguration(serviceName);
601    }
602
603    @Override
604    public void setServiceCallConfiguration(ServiceCallConfigurationDefinition configuration) {
605        if (model == null && isLightweight()) {
606            throw new IllegalStateException("Access to model not supported in lightweight mode");
607        }
608        model.setServiceCallConfiguration(configuration);
609    }
610
611    @Override
612    public void setServiceCallConfigurations(List<ServiceCallConfigurationDefinition> configurations) {
613        if (model == null && isLightweight()) {
614            throw new IllegalStateException("Access to model not supported in lightweight mode");
615        }
616        model.setServiceCallConfigurations(configurations);
617    }
618
619    @Override
620    public void addServiceCallConfiguration(String serviceName, ServiceCallConfigurationDefinition configuration) {
621        if (model == null && isLightweight()) {
622            throw new IllegalStateException("Access to model not supported in lightweight mode");
623        }
624        model.addServiceCallConfiguration(serviceName, configuration);
625    }
626
627    @Override
628    public void setRouteFilterPattern(String include, String exclude) {
629        if (model == null && isLightweight()) {
630            throw new IllegalStateException("Access to model not supported in lightweight mode");
631        }
632        model.setRouteFilterPattern(include, exclude);
633    }
634
635    @Override
636    public void setRouteFilter(Function<RouteDefinition, Boolean> filter) {
637        if (model == null && isLightweight()) {
638            throw new IllegalStateException("Access to model not supported in lightweight mode");
639        }
640        model.setRouteFilter(filter);
641    }
642
643    @Override
644    public Function<RouteDefinition, Boolean> getRouteFilter() {
645        if (model == null && isLightweight()) {
646            throw new IllegalStateException("Access to model not supported in lightweight mode");
647        }
648        return model.getRouteFilter();
649    }
650
651    @Override
652    public ModelReifierFactory getModelReifierFactory() {
653        if (model == null && isLightweight()) {
654            throw new IllegalStateException("Access to model not supported in lightweight mode");
655        }
656        return model.getModelReifierFactory();
657    }
658
659    @Override
660    public void setModelReifierFactory(ModelReifierFactory modelReifierFactory) {
661        if (model == null && isLightweight()) {
662            throw new IllegalStateException("Access to model not supported in lightweight mode");
663        }
664        model.setModelReifierFactory(modelReifierFactory);
665    }
666
667    @Override
668    protected void bindDataFormats() throws Exception {
669        // eager lookup data formats and bind to registry so the dataformats can
670        // be looked up and used
671        if (model != null) {
672            for (Map.Entry<String, DataFormatDefinition> e : model.getDataFormats().entrySet()) {
673                String id = e.getKey();
674                DataFormatDefinition def = e.getValue();
675                LOG.debug("Creating Dataformat with id: {} and definition: {}", id, def);
676                DataFormat df = model.getModelReifierFactory().createDataFormat(this, def);
677                addService(df, true);
678                getRegistry().bind(id, df);
679            }
680        }
681    }
682
683    @Override
684    protected synchronized void shutdownRouteService(RouteService routeService) throws Exception {
685        if (model != null) {
686            RouteDefinition rd = model.getRouteDefinition(routeService.getId());
687            if (rd != null) {
688                model.getRouteDefinitions().remove(rd);
689            }
690        }
691        super.shutdownRouteService(routeService);
692    }
693
694    @Override
695    protected boolean isStreamCachingInUse() throws Exception {
696        boolean streamCachingInUse = super.isStreamCachingInUse();
697        if (!streamCachingInUse) {
698            for (RouteDefinition route : model.getRouteDefinitions()) {
699                Boolean routeCache = CamelContextHelper.parseBoolean(this, route.getStreamCache());
700                if (routeCache != null && routeCache) {
701                    streamCachingInUse = true;
702                    break;
703                }
704            }
705        }
706        return streamCachingInUse;
707    }
708
709    @Override
710    public void startRouteDefinitions() throws Exception {
711        if (model == null && isLightweight()) {
712            throw new IllegalStateException("Access to model not supported in lightweight mode");
713        }
714        List<RouteDefinition> routeDefinitions = model.getRouteDefinitions();
715        if (routeDefinitions != null) {
716            startRouteDefinitions(routeDefinitions);
717        }
718    }
719
720    public void startRouteDefinitions(List<RouteDefinition> routeDefinitions) throws Exception {
721        if (model == null && isLightweight()) {
722            throw new IllegalStateException("Access to model not supported in lightweight mode");
723        }
724
725        // indicate we are staring the route using this thread so
726        // we are able to query this if needed
727        boolean alreadyStartingRoutes = isStartingRoutes();
728        if (!alreadyStartingRoutes) {
729            setStartingRoutes(true);
730        }
731
732        PropertiesComponent pc = getCamelContextReference().getPropertiesComponent();
733        // route templates supports binding beans that are local for the template only
734        // in this local mode then we need to check for side-effects (see further)
735        LocalBeanRepositoryAware localBeans = null;
736        if (getCamelContextReference().getRegistry() instanceof LocalBeanRepositoryAware) {
737            localBeans = (LocalBeanRepositoryAware) getCamelContextReference().getRegistry();
738        }
739        try {
740            RouteDefinitionHelper.forceAssignIds(getCamelContextReference(), routeDefinitions);
741            for (RouteDefinition routeDefinition : routeDefinitions) {
742                // assign ids to the routes and validate that the id's is all unique
743                String duplicate = RouteDefinitionHelper.validateUniqueIds(routeDefinition, routeDefinitions);
744                if (duplicate != null) {
745                    throw new FailedToStartRouteException(
746                            routeDefinition.getId(),
747                            "duplicate id detected: " + duplicate + ". Please correct ids to be unique among all your routes.");
748                }
749
750                // if the route definition was created via a route template then we need to prepare its parameters when the route is being created and started
751                if (routeDefinition.isTemplate() != null && routeDefinition.isTemplate()
752                        && routeDefinition.getTemplateParameters() != null) {
753
754                    // apply configurer if any present
755                    if (routeDefinition.getRouteTemplateContext().getConfigurer() != null) {
756                        routeDefinition.getRouteTemplateContext().getConfigurer()
757                                .accept(routeDefinition.getRouteTemplateContext());
758                    }
759
760                    // copy parameters/bean repository to not cause side-effect
761                    Map<String, Object> params = new HashMap<>(routeDefinition.getTemplateParameters());
762                    LocalBeanRegistry bbr
763                            = (LocalBeanRegistry) routeDefinition.getRouteTemplateContext().getLocalBeanRepository();
764                    LocalBeanRegistry bbrCopy = new LocalBeanRegistry();
765
766                    // make all bean in the bean repository use unique keys (need to add uuid counter)
767                    // so when the route template is used again to create another route, then there is
768                    // no side-effect from previously used values that Camel may use in its endpoint
769                    // registry and elsewhere
770                    if (bbr != null && !bbr.isEmpty()) {
771                        for (Map.Entry<String, Object> param : params.entrySet()) {
772                            Object value = param.getValue();
773                            if (value instanceof String) {
774                                String oldKey = (String) value;
775                                boolean clash = bbr.keys().stream().anyMatch(k -> k.equals(oldKey));
776                                if (clash) {
777                                    String newKey = oldKey + "-" + UUID.generateUuid();
778                                    LOG.debug(
779                                            "Route: {} re-assigning local-bean id: {} to: {} to ensure ids are globally unique",
780                                            routeDefinition.getId(), oldKey, newKey);
781                                    bbrCopy.put(newKey, bbr.remove(oldKey));
782                                    param.setValue(newKey);
783                                }
784                            }
785                        }
786                        // the remainder of the local beans must also have their ids made global unique
787                        for (String oldKey : bbr.keySet()) {
788                            String newKey = oldKey + "-" + UUID.generateUuid();
789                            LOG.debug(
790                                    "Route: {} re-assigning local-bean id: {} to: {} to ensure ids are globally unique",
791                                    routeDefinition.getId(), oldKey, newKey);
792                            bbrCopy.put(newKey, bbr.get(oldKey));
793                            if (!params.containsKey(oldKey)) {
794                                // if a bean was bound as local bean with a key and it was not defined as template parameter
795                                // then store it as if it was a template parameter with same key=value which allows us
796                                // to use this local bean in the route without any problem such as:
797                                //   to("bean:{{myBean}}")
798                                // and myBean is the local bean id.
799                                params.put(oldKey, newKey);
800                            }
801                        }
802                    }
803
804                    Properties prop = new Properties();
805                    prop.putAll(params);
806                    pc.setLocalProperties(prop);
807
808                    // we need to shadow the bean registry on the CamelContext with the local beans from the route template context
809                    if (localBeans != null && bbrCopy != null) {
810                        localBeans.setLocalBeanRepository(bbrCopy);
811                    }
812
813                    // need to reset auto assigned ids, so there is no clash when creating routes
814                    ProcessorDefinitionHelper.resetAllAutoAssignedNodeIds(routeDefinition);
815                }
816
817                // must ensure route is prepared, before we can start it
818                if (!routeDefinition.isPrepared()) {
819                    RouteDefinitionHelper.prepareRoute(getCamelContextReference(), routeDefinition);
820                    routeDefinition.markPrepared();
821                }
822
823                StartupStepRecorder recorder
824                        = getCamelContextReference().adapt(ExtendedCamelContext.class).getStartupStepRecorder();
825                StartupStep step = recorder.beginStep(Route.class, routeDefinition.getRouteId(), "Create Route");
826                Route route = model.getModelReifierFactory().createRoute(this, routeDefinition);
827                recorder.endStep(step);
828
829                RouteService routeService = new RouteService(route);
830                startRouteService(routeService, true);
831
832                // clear local after the route is created via the reifier
833                pc.setLocalProperties(null);
834                if (localBeans != null) {
835                    localBeans.setLocalBeanRepository(null);
836                }
837            }
838        } finally {
839            if (!alreadyStartingRoutes) {
840                setStartingRoutes(false);
841            }
842            pc.setLocalProperties(null);
843            if (localBeans != null) {
844                localBeans.setLocalBeanRepository(null);
845            }
846        }
847    }
848
849    @Override
850    protected ExecutorServiceManager createExecutorServiceManager() {
851        return new DefaultExecutorServiceManager(this);
852    }
853
854    @Override
855    public Processor createErrorHandler(Route route, Processor processor) throws Exception {
856        if (model == null && isLightweight()) {
857            throw new IllegalStateException("Access to model not supported in lightweight mode");
858        }
859        return model.getModelReifierFactory().createErrorHandler(route, processor);
860    }
861
862    @Override
863    public Expression createExpression(ExpressionDefinition definition) {
864        if (model == null && isLightweight()) {
865            throw new IllegalStateException("Access to model not supported in lightweight mode");
866        }
867        return model.getModelReifierFactory().createExpression(this, definition);
868    }
869
870    @Override
871    public Predicate createPredicate(ExpressionDefinition definition) {
872        if (model == null && isLightweight()) {
873            throw new IllegalStateException("Access to model not supported in lightweight mode");
874        }
875        return model.getModelReifierFactory().createPredicate(this, definition);
876    }
877
878    @Override
879    public RouteDefinition adviceWith(RouteDefinition definition, AdviceWithRouteBuilder builder) throws Exception {
880        return AdviceWith.adviceWith(definition, this, builder);
881    }
882
883    @Override
884    public void registerValidator(ValidatorDefinition def) {
885        if (model == null && isLightweight()) {
886            throw new IllegalStateException("Access to model not supported in lightweight mode");
887        }
888        model.getValidators().add(def);
889        Validator validator = model.getModelReifierFactory().createValidator(this, def);
890        getValidatorRegistry().put(createValidatorKey(def), validator);
891    }
892
893    private static ValueHolder<String> createValidatorKey(ValidatorDefinition def) {
894        return new ValidatorKey(new DataType(def.getType()));
895    }
896
897    @Override
898    public void registerTransformer(TransformerDefinition def) {
899        if (model == null && isLightweight()) {
900            throw new IllegalStateException("Access to model not supported in lightweight mode");
901        }
902        model.getTransformers().add(def);
903        Transformer transformer = model.getModelReifierFactory().createTransformer(this, def);
904        getTransformerRegistry().put(createTransformerKey(def), transformer);
905    }
906
907    private static ValueHolder<String> createTransformerKey(TransformerDefinition def) {
908        return ObjectHelper.isNotEmpty(def.getScheme())
909                ? new TransformerKey(def.getScheme())
910                : new TransformerKey(new DataType(def.getFromType()), new DataType(def.getToType()));
911    }
912
913    protected static class OptionHolder {
914        public boolean noStart;
915        public boolean disableJmx = Boolean.getBoolean(JmxSystemPropertyKeys.DISABLED);
916        public String excludeRoutes;
917    }
918}