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.io.IOException;
020import java.io.InputStream;
021import java.net.URI;
022import java.util.ArrayList;
023import java.util.Arrays;
024import java.util.Collection;
025import java.util.Collections;
026import java.util.Comparator;
027import java.util.Date;
028import java.util.HashMap;
029import java.util.HashSet;
030import java.util.Iterator;
031import java.util.LinkedHashMap;
032import java.util.LinkedHashSet;
033import java.util.List;
034import java.util.Map;
035import java.util.Properties;
036import java.util.Set;
037import java.util.TreeMap;
038import java.util.concurrent.Callable;
039import java.util.concurrent.ConcurrentHashMap;
040import java.util.concurrent.CopyOnWriteArrayList;
041import java.util.concurrent.ScheduledExecutorService;
042import java.util.concurrent.TimeUnit;
043import java.util.concurrent.atomic.AtomicBoolean;
044import java.util.concurrent.atomic.AtomicInteger;
045import java.util.function.Function;
046import javax.management.MalformedObjectNameException;
047import javax.management.ObjectName;
048import javax.naming.Context;
049import javax.xml.bind.JAXBContext;
050import javax.xml.bind.Unmarshaller;
051
052import org.apache.camel.CamelContext;
053import org.apache.camel.CamelContextAware;
054import org.apache.camel.Component;
055import org.apache.camel.Consumer;
056import org.apache.camel.ConsumerTemplate;
057import org.apache.camel.Endpoint;
058import org.apache.camel.ErrorHandlerFactory;
059import org.apache.camel.ExtendedStartupListener;
060import org.apache.camel.FailedToStartRouteException;
061import org.apache.camel.FluentProducerTemplate;
062import org.apache.camel.IsSingleton;
063import org.apache.camel.MultipleConsumersSupport;
064import org.apache.camel.NamedNode;
065import org.apache.camel.NoFactoryAvailableException;
066import org.apache.camel.NoSuchEndpointException;
067import org.apache.camel.PollingConsumer;
068import org.apache.camel.Processor;
069import org.apache.camel.Producer;
070import org.apache.camel.ProducerTemplate;
071import org.apache.camel.ResolveEndpointFailedException;
072import org.apache.camel.Route;
073import org.apache.camel.RoutesBuilder;
074import org.apache.camel.RuntimeCamelException;
075import org.apache.camel.Service;
076import org.apache.camel.ServiceStatus;
077import org.apache.camel.ShutdownRoute;
078import org.apache.camel.ShutdownRunningTask;
079import org.apache.camel.StartupListener;
080import org.apache.camel.StatefulService;
081import org.apache.camel.Suspendable;
082import org.apache.camel.SuspendableService;
083import org.apache.camel.TypeConverter;
084import org.apache.camel.VetoCamelContextStartException;
085import org.apache.camel.api.management.mbean.ManagedCamelContextMBean;
086import org.apache.camel.api.management.mbean.ManagedProcessorMBean;
087import org.apache.camel.api.management.mbean.ManagedRouteMBean;
088import org.apache.camel.builder.DefaultFluentProducerTemplate;
089import org.apache.camel.builder.ErrorHandlerBuilder;
090import org.apache.camel.builder.ErrorHandlerBuilderSupport;
091import org.apache.camel.component.properties.PropertiesComponent;
092import org.apache.camel.health.HealthCheckRegistry;
093import org.apache.camel.impl.converter.BaseTypeConverterRegistry;
094import org.apache.camel.impl.converter.DefaultTypeConverter;
095import org.apache.camel.impl.converter.LazyLoadingTypeConverter;
096import org.apache.camel.impl.health.DefaultHealthCheckRegistry;
097import org.apache.camel.impl.transformer.TransformerKey;
098import org.apache.camel.impl.validator.ValidatorKey;
099import org.apache.camel.management.DefaultManagementMBeanAssembler;
100import org.apache.camel.management.DefaultManagementStrategy;
101import org.apache.camel.management.JmxSystemPropertyKeys;
102import org.apache.camel.management.ManagementStrategyFactory;
103import org.apache.camel.model.DataFormatDefinition;
104import org.apache.camel.model.FromDefinition;
105import org.apache.camel.model.HystrixConfigurationDefinition;
106import org.apache.camel.model.ModelCamelContext;
107import org.apache.camel.model.ModelHelper;
108import org.apache.camel.model.ProcessorDefinition;
109import org.apache.camel.model.ProcessorDefinitionHelper;
110import org.apache.camel.model.RouteDefinition;
111import org.apache.camel.model.RouteDefinitionHelper;
112import org.apache.camel.model.RoutesDefinition;
113import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition;
114import org.apache.camel.model.rest.RestDefinition;
115import org.apache.camel.model.rest.RestsDefinition;
116import org.apache.camel.model.transformer.TransformerDefinition;
117import org.apache.camel.model.validator.ValidatorDefinition;
118import org.apache.camel.processor.interceptor.BacklogDebugger;
119import org.apache.camel.processor.interceptor.BacklogTracer;
120import org.apache.camel.processor.interceptor.Debug;
121import org.apache.camel.processor.interceptor.Delayer;
122import org.apache.camel.processor.interceptor.HandleFault;
123import org.apache.camel.processor.interceptor.StreamCaching;
124import org.apache.camel.processor.interceptor.Tracer;
125import org.apache.camel.runtimecatalog.DefaultRuntimeCamelCatalog;
126import org.apache.camel.runtimecatalog.RuntimeCamelCatalog;
127import org.apache.camel.spi.AsyncProcessorAwaitManager;
128import org.apache.camel.spi.CamelContextNameStrategy;
129import org.apache.camel.spi.ClassResolver;
130import org.apache.camel.spi.ComponentResolver;
131import org.apache.camel.spi.Container;
132import org.apache.camel.spi.DataFormat;
133import org.apache.camel.spi.DataFormatResolver;
134import org.apache.camel.spi.DataType;
135import org.apache.camel.spi.Debugger;
136import org.apache.camel.spi.EndpointRegistry;
137import org.apache.camel.spi.EndpointStrategy;
138import org.apache.camel.spi.EventNotifier;
139import org.apache.camel.spi.ExecutorServiceManager;
140import org.apache.camel.spi.FactoryFinder;
141import org.apache.camel.spi.FactoryFinderResolver;
142import org.apache.camel.spi.HeadersMapFactory;
143import org.apache.camel.spi.InflightRepository;
144import org.apache.camel.spi.Injector;
145import org.apache.camel.spi.InterceptStrategy;
146import org.apache.camel.spi.Language;
147import org.apache.camel.spi.LanguageResolver;
148import org.apache.camel.spi.LifecycleStrategy;
149import org.apache.camel.spi.LogListener;
150import org.apache.camel.spi.ManagementMBeanAssembler;
151import org.apache.camel.spi.ManagementNameStrategy;
152import org.apache.camel.spi.ManagementStrategy;
153import org.apache.camel.spi.MessageHistoryFactory;
154import org.apache.camel.spi.ModelJAXBContextFactory;
155import org.apache.camel.spi.NodeIdFactory;
156import org.apache.camel.spi.PackageScanClassResolver;
157import org.apache.camel.spi.ProcessorFactory;
158import org.apache.camel.spi.Registry;
159import org.apache.camel.spi.ReloadStrategy;
160import org.apache.camel.spi.RestConfiguration;
161import org.apache.camel.spi.RestRegistry;
162import org.apache.camel.spi.RouteContext;
163import org.apache.camel.spi.RouteController;
164import org.apache.camel.spi.RouteError;
165import org.apache.camel.spi.RoutePolicyFactory;
166import org.apache.camel.spi.RouteStartupOrder;
167import org.apache.camel.spi.RuntimeEndpointRegistry;
168import org.apache.camel.spi.ServicePool;
169import org.apache.camel.spi.ShutdownStrategy;
170import org.apache.camel.spi.StreamCachingStrategy;
171import org.apache.camel.spi.Transformer;
172import org.apache.camel.spi.TransformerRegistry;
173import org.apache.camel.spi.TypeConverterRegistry;
174import org.apache.camel.spi.UnitOfWorkFactory;
175import org.apache.camel.spi.UuidGenerator;
176import org.apache.camel.spi.Validator;
177import org.apache.camel.spi.ValidatorRegistry;
178import org.apache.camel.support.ServiceSupport;
179import org.apache.camel.util.CamelContextHelper;
180import org.apache.camel.util.CollectionStringBuffer;
181import org.apache.camel.util.EndpointHelper;
182import org.apache.camel.util.EventHelper;
183import org.apache.camel.util.IOHelper;
184import org.apache.camel.util.IntrospectionSupport;
185import org.apache.camel.util.JsonSchemaHelper;
186import org.apache.camel.util.LoadPropertiesException;
187import org.apache.camel.util.ObjectHelper;
188import org.apache.camel.util.OrderedComparator;
189import org.apache.camel.util.ServiceHelper;
190import org.apache.camel.util.StopWatch;
191import org.apache.camel.util.StringHelper;
192import org.apache.camel.util.StringQuoteHelper;
193import org.apache.camel.util.TimeUtils;
194import org.apache.camel.util.URISupport;
195import org.apache.camel.util.jsse.SSLContextParameters;
196import org.slf4j.Logger;
197import org.slf4j.LoggerFactory;
198import org.slf4j.MDC;
199
200import static org.apache.camel.impl.MDCUnitOfWork.MDC_CAMEL_CONTEXT_ID;
201
202/**
203 * Represents the context used to configure routes and the policies to use.
204 *
205 * @version
206 */
207@SuppressWarnings("deprecation")
208public class DefaultCamelContext extends ServiceSupport implements ModelCamelContext, Suspendable {
209    private final Logger log = LoggerFactory.getLogger(getClass());
210    private final AtomicBoolean vetoStated = new AtomicBoolean();
211    private JAXBContext jaxbContext;
212    private CamelContextNameStrategy nameStrategy = createCamelContextNameStrategy();
213    private ManagementNameStrategy managementNameStrategy = createManagementNameStrategy();
214    private String managementName;
215    private ClassLoader applicationContextClassLoader;
216    private EndpointRegistry<EndpointKey> endpoints;
217    private final AtomicInteger endpointKeyCounter = new AtomicInteger();
218    private final List<EndpointStrategy> endpointStrategies = new ArrayList<>();
219    private final Map<String, Component> components = new ConcurrentHashMap<>();
220    private final Set<Route> routes = new LinkedHashSet<>();
221    private final List<Service> servicesToStop = new CopyOnWriteArrayList<>();
222    private final List<StartupListener> startupListeners = new CopyOnWriteArrayList<>();
223    private final DeferServiceStartupListener deferStartupListener = new DeferServiceStartupListener();
224    private TypeConverter typeConverter;
225    private TypeConverterRegistry typeConverterRegistry;
226    private Injector injector;
227    private ComponentResolver componentResolver;
228    private boolean autoCreateComponents = true;
229    private LanguageResolver languageResolver;
230    private final Map<String, Language> languages = new HashMap<>();
231    private Registry registry;
232    private List<LifecycleStrategy> lifecycleStrategies = new CopyOnWriteArrayList<>();
233    private ManagementStrategy managementStrategy;
234    private ManagementMBeanAssembler managementMBeanAssembler;
235    private final List<RouteDefinition> routeDefinitions = new ArrayList<>();
236    private final List<RestDefinition> restDefinitions = new ArrayList<>();
237    private Map<String, RestConfiguration> restConfigurations = new ConcurrentHashMap<>();
238    private Map<String, ServiceCallConfigurationDefinition> serviceCallConfigurations = new ConcurrentHashMap<>();
239    private Map<String, HystrixConfigurationDefinition> hystrixConfigurations = new ConcurrentHashMap<>();
240    private RestRegistry restRegistry = new DefaultRestRegistry();
241    private List<InterceptStrategy> interceptStrategies = new ArrayList<>();
242    private List<RoutePolicyFactory> routePolicyFactories = new ArrayList<>();
243    private Set<LogListener> logListeners = new LinkedHashSet<>();
244    private HeadersMapFactory headersMapFactory = createHeadersMapFactory();
245    // special flags to control the first startup which can are special
246    private volatile boolean firstStartDone;
247    private volatile boolean doNotStartRoutesOnFirstStart;
248    private final ThreadLocal<Boolean> isStartingRoutes = new ThreadLocal<>();
249    private final ThreadLocal<Boolean> isSetupRoutes = new ThreadLocal<>();
250    private Boolean autoStartup = Boolean.TRUE;
251    private Boolean trace = Boolean.FALSE;
252    private Boolean messageHistory = Boolean.TRUE;
253    private Boolean logMask = Boolean.FALSE;
254    private Boolean logExhaustedMessageBody = Boolean.FALSE;
255    private Boolean streamCache = Boolean.FALSE;
256    private Boolean handleFault = Boolean.FALSE;
257    private Boolean disableJMX = Boolean.FALSE;
258    private Boolean lazyLoadTypeConverters = Boolean.FALSE;
259    private Boolean loadTypeConverters = Boolean.TRUE;
260    private Boolean typeConverterStatisticsEnabled = Boolean.FALSE;
261    private Boolean useMDCLogging = Boolean.FALSE;
262    private Boolean useDataType = Boolean.FALSE;
263    private Boolean useBreadcrumb = Boolean.TRUE;
264    private Boolean allowUseOriginalMessage = Boolean.FALSE;
265    private Long delay;
266    private ErrorHandlerFactory errorHandlerBuilder;
267    private final Object errorHandlerExecutorServiceLock = new Object();
268    private ScheduledExecutorService errorHandlerExecutorService;
269    private Map<String, DataFormatDefinition> dataFormats = new HashMap<>();
270    private DataFormatResolver dataFormatResolver;
271    private Map<String, String> globalOptions = new HashMap<>();
272    private FactoryFinderResolver factoryFinderResolver;
273    private FactoryFinder defaultFactoryFinder;
274    private PropertiesComponent propertiesComponent;
275    private StreamCachingStrategy streamCachingStrategy;
276    private final Map<String, FactoryFinder> factories = new HashMap<>();
277    private final Map<String, RouteService> routeServices = new LinkedHashMap<>();
278    private final Map<String, RouteService> suspendedRouteServices = new LinkedHashMap<>();
279    private ClassResolver classResolver = createClassResolver();
280    private PackageScanClassResolver packageScanClassResolver;
281    // we use a capacity of 100 per endpoint, so for the same endpoint we have at most 100 producers in the pool
282    // so if we have 6 endpoints in the pool, we can have 6 x 100 producers in total
283    private ServicePool<Endpoint, Producer> producerServicePool = createProducerServicePool();
284    private ServicePool<Endpoint, PollingConsumer> pollingConsumerServicePool = createPollingConsumerServicePool();
285    private NodeIdFactory nodeIdFactory = createNodeIdFactory();
286    private ProcessorFactory processorFactory = createProcessorFactory();
287    private MessageHistoryFactory messageHistoryFactory = createMessageHistoryFactory();
288    private InterceptStrategy defaultTracer;
289    private InterceptStrategy defaultBacklogTracer;
290    private InterceptStrategy defaultBacklogDebugger;
291    private InflightRepository inflightRepository = createInflightRepository();
292    private AsyncProcessorAwaitManager asyncProcessorAwaitManager = createAsyncProcessorAwaitManager();
293    private RuntimeEndpointRegistry runtimeEndpointRegistry;
294    private final List<RouteStartupOrder> routeStartupOrder = new ArrayList<>();
295    // start auto assigning route ids using numbering 1000 and upwards
296    private int defaultRouteStartupOrder = 1000;
297    private ShutdownStrategy shutdownStrategy = createShutdownStrategy();
298    private ShutdownRoute shutdownRoute = ShutdownRoute.Default;
299    private ShutdownRunningTask shutdownRunningTask = ShutdownRunningTask.CompleteCurrentTaskOnly;
300    private ExecutorServiceManager executorServiceManager;
301    private Debugger debugger;
302    private UuidGenerator uuidGenerator = createDefaultUuidGenerator();
303    private UnitOfWorkFactory unitOfWorkFactory = createUnitOfWorkFactory();
304    private final StopWatch stopWatch = new StopWatch(false);
305    private Date startDate;
306    private ModelJAXBContextFactory modelJAXBContextFactory;
307    private List<TransformerDefinition> transformers = new ArrayList<>();
308    private TransformerRegistry<TransformerKey> transformerRegistry;
309    private List<ValidatorDefinition> validators = new ArrayList<>();
310    private ValidatorRegistry<ValidatorKey> validatorRegistry;
311    private ReloadStrategy reloadStrategy;
312    private final RuntimeCamelCatalog runtimeCamelCatalog = createRuntimeCamelCatalog();
313    private SSLContextParameters sslContextParameters;
314    private final ThreadLocal<Set<String>> componentsInCreation = new ThreadLocal<Set<String>>() {
315        @Override
316        public Set<String> initialValue() {
317            return new HashSet<>();
318        }
319    };
320    private RouteController routeController = createRouteController();
321    private HealthCheckRegistry healthCheckRegistry = createHealthCheckRegistry();
322
323
324    /**
325     * Creates the {@link CamelContext} using {@link JndiRegistry} as registry,
326     * but will silently fallback and use {@link SimpleRegistry} if JNDI cannot be used.
327     * <p/>
328     * Use one of the other constructors to force use an explicit registry / JNDI.
329     */
330    public DefaultCamelContext() {
331        this.executorServiceManager = createExecutorServiceManager();
332
333        // create a provisional (temporary) endpoint registry at first since end users may access endpoints before CamelContext is started
334        // we will later transfer the endpoints to the actual DefaultEndpointRegistry later, but we do this to starup Camel faster.
335        this.endpoints = new ProvisionalEndpointRegistry();
336
337        // add the defer service startup listener
338        this.startupListeners.add(deferStartupListener);
339
340        packageScanClassResolver = createPackageScanClassResolver();
341
342        // setup management strategy first since end users may use it to add event notifiers
343        // using the management strategy before the CamelContext has been started
344        this.managementStrategy = createManagementStrategy();
345        this.managementMBeanAssembler = createManagementMBeanAssembler();
346
347        // Call all registered trackers with this context
348        // Note, this may use a partially constructed object
349        CamelContextTrackerRegistry.INSTANCE.contextCreated(this);
350    }
351
352    /**
353     * Creates the {@link CamelContext} using the given JNDI context as the registry
354     *
355     * @param jndiContext the JNDI context
356     */
357    public DefaultCamelContext(Context jndiContext) {
358        this();
359        setJndiContext(jndiContext);
360    }
361
362    /**
363     * Creates the {@link CamelContext} using the given registry
364     *
365     * @param registry the registry
366     */
367    public DefaultCamelContext(Registry registry) {
368        this();
369        setRegistry(registry);
370    }
371
372    public <T extends CamelContext> T adapt(Class<T> type) {
373        return type.cast(this);
374    }
375
376    public boolean isVetoStarted() {
377        return vetoStated.get();
378    }
379
380    public String getName() {
381        return getNameStrategy().getName();
382    }
383
384    /**
385     * Sets the name of the this context.
386     *
387     * @param name the name
388     */
389    public void setName(String name) {
390        // use an explicit name strategy since an explicit name was provided to be used
391        this.nameStrategy = new ExplicitCamelContextNameStrategy(name);
392    }
393
394    public CamelContextNameStrategy getNameStrategy() {
395        return nameStrategy;
396    }
397
398    public void setNameStrategy(CamelContextNameStrategy nameStrategy) {
399        this.nameStrategy = nameStrategy;
400    }
401
402    public ManagementNameStrategy getManagementNameStrategy() {
403        return managementNameStrategy;
404    }
405
406    public void setManagementNameStrategy(ManagementNameStrategy managementNameStrategy) {
407        this.managementNameStrategy = managementNameStrategy;
408    }
409
410    public String getManagementName() {
411        return managementName;
412    }
413
414    public void setManagementName(String managementName) {
415        this.managementName = managementName;
416    }
417
418    public Component hasComponent(String componentName) {
419        return components.get(componentName);
420    }
421
422    public void addComponent(String componentName, final Component component) {
423        ObjectHelper.notNull(component, "component");
424        component.setCamelContext(this);
425        Component oldValue = components.putIfAbsent(componentName, component);
426        if (oldValue != null) {
427            throw new IllegalArgumentException("Cannot add component as its already previously added: " + componentName);
428        }
429        postInitComponent(componentName, component);
430    }
431
432    private void postInitComponent(String componentName, final Component component) {
433        for (LifecycleStrategy strategy : lifecycleStrategies) {
434            strategy.onComponentAdd(componentName, component);
435        }
436
437        // keep reference to properties component up to date
438        if (component instanceof PropertiesComponent && "properties".equals(componentName)) {
439            propertiesComponent = (PropertiesComponent) component;
440        }
441    }
442
443    public Component getComponent(String name) {
444        return getComponent(name, autoCreateComponents, true);
445    }
446
447    public Component getComponent(String name, boolean autoCreateComponents) {
448        return getComponent(name, autoCreateComponents, true);
449    }
450
451    public Component getComponent(String name, boolean autoCreateComponents, boolean autoStart) {
452        // Check if the named component is already being created, that would mean
453        // that the initComponent has triggered a new getComponent
454        if (componentsInCreation.get().contains(name)) {
455            throw new IllegalStateException("Circular dependency detected, the component " + name + " is already being created");
456        }
457
458        try {
459            // Flag used to mark a component of being created.
460            final AtomicBoolean created = new AtomicBoolean(false);
461
462            // atomic operation to get/create a component. Avoid global locks.
463            final Component component = components.computeIfAbsent(name, new Function<String, Component>() {
464                @Override
465                public Component apply(String comp) {
466                    created.set(true);
467                    return DefaultCamelContext.this.initComponent(name, autoCreateComponents);
468                }
469            });
470
471            // Start the component after its creation as if it is a component proxy
472            // that creates/start a delegated component, we may end up in a deadlock
473            if (component != null && created.get() && autoStart && (isStarted() || isStarting())) {
474                // If the component is looked up after the context is started,
475                // lets start it up.
476                if (component instanceof Service) {
477                    startService((Service)component);
478                }
479            }
480
481            return  component;
482        } catch (Exception e) {
483            throw new RuntimeCamelException("Cannot auto create component: " + name, e);
484        } finally {
485            // remove the reference to the component being created
486            componentsInCreation.get().remove(name);
487        }
488    }
489    
490    /**
491     * Function to initialize a component and auto start. Returns null if the autoCreateComponents is disabled
492     */
493    private Component initComponent(String name, boolean autoCreateComponents) {
494        Component component = null;
495        if (autoCreateComponents) {
496            try {
497                if (log.isDebugEnabled()) {
498                    log.debug("Using ComponentResolver: {} to resolve component with name: {}", getComponentResolver(), name);
499                }
500
501                // Mark the component as being created so we can detect circular
502                // requests.
503                //
504                // In spring apps, the component resolver may trigger a new getComponent
505                // because of the underlying bean factory and as the endpoints are
506                // registered as singleton, the spring factory creates the bean
507                // and then check the type so the getComponent is always triggered.
508                //
509                // Simple circular dependency:
510                //
511                //   <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
512                //     <route>
513                //       <from id="twitter" uri="twitter://timeline/home?type=polling"/>
514                //       <log message="Got ${body}"/>
515                //     </route>
516                //   </camelContext>
517                //
518                // Complex circular dependency:
519                //
520                //   <camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
521                //     <route>
522                //       <from id="log" uri="seda:test"/>
523                //       <to id="seda" uri="log:test"/>
524                //     </route>
525                //   </camelContext>
526                //
527                // This would freeze the app (lock or infinite loop).
528                //
529                // See https://issues.apache.org/jira/browse/CAMEL-11225
530                componentsInCreation.get().add(name);
531
532                component = getComponentResolver().resolveComponent(name, this);
533                if (component != null) {
534                    component.setCamelContext(this);
535                    postInitComponent(name, component);
536                }
537            } catch (Exception e) {
538                throw new RuntimeCamelException("Cannot auto create component: " + name, e);
539            }
540        }
541        return component;
542    }
543
544    public <T extends Component> T getComponent(String name, Class<T> componentType) {
545        Component component = getComponent(name);
546        if (componentType.isInstance(component)) {
547            return componentType.cast(component);
548        } else {
549            String message;
550            if (component == null) {
551                message = "Did not find component given by the name: " + name;
552            } else {
553                message = "Found component of type: " + component.getClass() + " instead of expected: " + componentType;
554            }
555            throw new IllegalArgumentException(message);
556        }
557    }
558
559    public Component resolveComponent(String name) {
560        Component answer = hasComponent(name);
561        if (answer == null) {
562            try {
563                answer = getComponentResolver().resolveComponent(name, this);
564            } catch (Exception e) {
565                throw new RuntimeCamelException("Cannot resolve component: " + name, e);
566            }
567        }
568        return answer;
569    }
570
571    public Component removeComponent(String componentName) {
572        Component oldComponent = components.remove(componentName);
573        if (oldComponent != null) {
574            try {
575                stopServices(oldComponent);
576            } catch (Exception e) {
577                log.warn("Error stopping component " + oldComponent + ". This exception will be ignored.", e);
578            }
579            for (LifecycleStrategy strategy : lifecycleStrategies) {
580                strategy.onComponentRemove(componentName, oldComponent);
581            }
582        }
583        // keep reference to properties component up to date
584        if (oldComponent != null && "properties".equals(componentName)) {
585            propertiesComponent = null;
586        }
587        return oldComponent;
588    }
589
590    // Endpoint Management Methods
591    // -----------------------------------------------------------------------
592
593    public EndpointRegistry<EndpointKey> getEndpointRegistry() {
594        return endpoints;
595    }
596
597    public Collection<Endpoint> getEndpoints() {
598        return new ArrayList<>(endpoints.values());
599    }
600
601    public Map<String, Endpoint> getEndpointMap() {
602        Map<String, Endpoint> answer = new TreeMap<>();
603        for (Map.Entry<EndpointKey, Endpoint> entry : endpoints.entrySet()) {
604            answer.put(entry.getKey().get(), entry.getValue());
605        }
606        return answer;
607    }
608
609    public Endpoint hasEndpoint(String uri) {
610        return endpoints.get(getEndpointKey(uri));
611    }
612
613    public Endpoint addEndpoint(String uri, Endpoint endpoint) throws Exception {
614        Endpoint oldEndpoint;
615
616        startService(endpoint);
617        oldEndpoint = endpoints.remove(getEndpointKey(uri));
618        for (LifecycleStrategy strategy : lifecycleStrategies) {
619            strategy.onEndpointAdd(endpoint);
620        }
621        addEndpointToRegistry(uri, endpoint);
622        if (oldEndpoint != null) {
623            stopServices(oldEndpoint);
624        }
625
626        return oldEndpoint;
627    }
628
629    public void removeEndpoint(Endpoint endpoint) throws Exception {
630        removeEndpoints(endpoint.getEndpointUri());
631    }
632
633    public Collection<Endpoint> removeEndpoints(String uri) throws Exception {
634        Collection<Endpoint> answer = new ArrayList<>();
635        Endpoint oldEndpoint = endpoints.remove(getEndpointKey(uri));
636        if (oldEndpoint != null) {
637            answer.add(oldEndpoint);
638            stopServices(oldEndpoint);
639        } else {
640            for (Map.Entry<EndpointKey, Endpoint> entry : endpoints.entrySet()) {
641                oldEndpoint = entry.getValue();
642                if (EndpointHelper.matchEndpoint(this, oldEndpoint.getEndpointUri(), uri)) {
643                    try {
644                        stopServices(oldEndpoint);
645                    } catch (Exception e) {
646                        log.warn("Error stopping endpoint " + oldEndpoint + ". This exception will be ignored.", e);
647                    }
648                    answer.add(oldEndpoint);
649                    endpoints.remove(entry.getKey());
650                }
651            }
652        }
653
654        // notify lifecycle its being removed
655        for (Endpoint endpoint : answer) {
656            for (LifecycleStrategy strategy : lifecycleStrategies) {
657                strategy.onEndpointRemove(endpoint);
658            }
659        }
660
661        return answer;
662    }
663
664    public Endpoint getEndpoint(String uri) {
665        StringHelper.notEmpty(uri, "uri");
666
667        log.trace("Getting endpoint with uri: {}", uri);
668
669        // in case path has property placeholders then try to let property component resolve those
670        try {
671            uri = resolvePropertyPlaceholders(uri);
672        } catch (Exception e) {
673            throw new ResolveEndpointFailedException(uri, e);
674        }
675
676        final String rawUri = uri;
677
678        // normalize uri so we can do endpoint hits with minor mistakes and parameters is not in the same order
679        uri = normalizeEndpointUri(uri);
680
681        log.trace("Getting endpoint with raw uri: {}, normalized uri: {}", rawUri, uri);
682
683        Endpoint answer;
684        String scheme = null;
685        // use optimized method to get the endpoint uri
686        EndpointKey key = getEndpointKeyPreNormalized(uri);
687        answer = endpoints.get(key);
688        if (answer == null) {
689            try {
690                // Use the URI prefix to find the component.
691                String splitURI[] = StringHelper.splitOnCharacter(uri, ":", 2);
692                if (splitURI[1] != null) {
693                    scheme = splitURI[0];
694                    log.trace("Endpoint uri: {} is from component with name: {}", uri, scheme);
695                    Component component = getComponent(scheme);
696
697                    // Ask the component to resolve the endpoint.
698                    if (component != null) {
699                        log.trace("Creating endpoint from uri: {} using component: {}", uri, component);
700
701                        // Have the component create the endpoint if it can.
702                        if (component.useRawUri()) {
703                            answer = component.createEndpoint(rawUri);
704                        } else {
705                            answer = component.createEndpoint(uri);
706                        }
707
708                        if (answer != null && log.isDebugEnabled()) {
709                            log.debug("{} converted to endpoint: {} by component: {}", URISupport.sanitizeUri(uri), answer, component);
710                        }
711                    }
712                }
713
714                if (answer == null) {
715                    // no component then try in registry and elsewhere
716                    answer = createEndpoint(uri);
717                    log.trace("No component to create endpoint from uri: {} fallback lookup in registry -> {}", uri, answer);
718                }
719
720                if (answer == null && splitURI[1] == null) {
721                    // the uri has no context-path which is rare and it was not referring to an endpoint in the registry
722                    // so try to see if it can be created by a component
723
724                    int pos = uri.indexOf('?');
725                    String componentName = pos > 0 ? uri.substring(0, pos) : uri;
726
727                    Component component = getComponent(componentName);
728
729                    // Ask the component to resolve the endpoint.
730                    if (component != null) {
731                        log.trace("Creating endpoint from uri: {} using component: {}", uri, component);
732
733                        // Have the component create the endpoint if it can.
734                        if (component.useRawUri()) {
735                            answer = component.createEndpoint(rawUri);
736                        } else {
737                            answer = component.createEndpoint(uri);
738                        }
739
740                        if (answer != null && log.isDebugEnabled()) {
741                            log.debug("{} converted to endpoint: {} by component: {}", URISupport.sanitizeUri(uri), answer, component);
742                        }
743                    }
744
745                }
746
747                if (answer != null) {
748                    addService(answer);
749                    answer = addEndpointToRegistry(uri, answer);
750                }
751            } catch (Exception e) {
752                throw new ResolveEndpointFailedException(uri, e);
753            }
754        }
755
756        // unknown scheme
757        if (answer == null && scheme != null) {
758            throw new ResolveEndpointFailedException(uri, "No component found with scheme: " + scheme);
759        }
760
761        return answer;
762    }
763
764    public <T extends Endpoint> T getEndpoint(String name, Class<T> endpointType) {
765        Endpoint endpoint = getEndpoint(name);
766        if (endpoint == null) {
767            throw new NoSuchEndpointException(name);
768        }
769        if (endpoint instanceof InterceptSendToEndpoint) {
770            endpoint = ((InterceptSendToEndpoint) endpoint).getDelegate();
771        }
772        if (endpointType.isInstance(endpoint)) {
773            return endpointType.cast(endpoint);
774        } else {
775            throw new IllegalArgumentException("The endpoint is not of type: " + endpointType
776                + " but is: " + endpoint.getClass().getCanonicalName());
777        }
778    }
779
780    public void addRegisterEndpointCallback(EndpointStrategy strategy) {
781        if (!endpointStrategies.contains(strategy)) {
782            // let it be invoked for already registered endpoints so it can catch-up.
783            endpointStrategies.add(strategy);
784            for (Endpoint endpoint : getEndpoints()) {
785                Endpoint newEndpoint = strategy.registerEndpoint(endpoint.getEndpointUri(), endpoint);
786                if (newEndpoint != null) {
787                    // put will replace existing endpoint with the new endpoint
788                    endpoints.put(getEndpointKey(endpoint.getEndpointUri()), newEndpoint);
789                }
790            }
791        }
792    }
793
794    /**
795     * Strategy to add the given endpoint to the internal endpoint registry
796     *
797     * @param uri      uri of the endpoint
798     * @param endpoint the endpoint to add
799     * @return the added endpoint
800     */
801    protected Endpoint addEndpointToRegistry(String uri, Endpoint endpoint) {
802        StringHelper.notEmpty(uri, "uri");
803        ObjectHelper.notNull(endpoint, "endpoint");
804
805        // if there is endpoint strategies, then use the endpoints they return
806        // as this allows to intercept endpoints etc.
807        for (EndpointStrategy strategy : endpointStrategies) {
808            endpoint = strategy.registerEndpoint(uri, endpoint);
809        }
810        endpoints.put(getEndpointKey(uri, endpoint), endpoint);
811        return endpoint;
812    }
813
814    /**
815     * Normalize uri so we can do endpoint hits with minor mistakes and parameters is not in the same order.
816     *
817     * @param uri the uri
818     * @return normalized uri
819     * @throws ResolveEndpointFailedException if uri cannot be normalized
820     */
821    protected static String normalizeEndpointUri(String uri) {
822        try {
823            uri = URISupport.normalizeUri(uri);
824        } catch (Exception e) {
825            throw new ResolveEndpointFailedException(uri, e);
826        }
827        return uri;
828    }
829
830    /**
831     * Gets the endpoint key to use for lookup or whe adding endpoints to the {@link DefaultEndpointRegistry}
832     *
833     * @param uri the endpoint uri
834     * @return the key
835     */
836    protected EndpointKey getEndpointKey(String uri) {
837        return new EndpointKey(uri);
838    }
839
840    /**
841     * Gets the endpoint key to use for lookup or whe adding endpoints to the {@link DefaultEndpointRegistry}
842     *
843     * @param uri the endpoint uri which is pre normalized
844     * @return the key
845     */
846    protected EndpointKey getEndpointKeyPreNormalized(String uri) {
847        return new EndpointKey(uri, true);
848    }
849
850    /**
851     * Gets the endpoint key to use for lookup or whe adding endpoints to the {@link DefaultEndpointRegistry}
852     *
853     * @param uri      the endpoint uri
854     * @param endpoint the endpoint
855     * @return the key
856     */
857    protected EndpointKey getEndpointKey(String uri, Endpoint endpoint) {
858        if (endpoint != null && !endpoint.isSingleton()) {
859            int counter = endpointKeyCounter.incrementAndGet();
860            return new EndpointKey(uri + ":" + counter);
861        } else {
862            return new EndpointKey(uri);
863        }
864    }
865
866    // Route Management Methods
867    // -----------------------------------------------------------------------
868
869    @Override
870    public void setRouteController(RouteController routeController) {
871        this.routeController = routeController;
872        this.routeController.setCamelContext(this);
873    }
874
875    @Override
876    public RouteController getRouteController() {
877        return routeController;
878    }
879
880    public List<RouteStartupOrder> getRouteStartupOrder() {
881        return routeStartupOrder;
882    }
883
884    public List<Route> getRoutes() {
885        // lets return a copy of the collection as objects are removed later when services are stopped
886        if (routes.isEmpty()) {
887            return Collections.emptyList();
888        } else {
889            synchronized (routes) {
890                return new ArrayList<>(routes);
891            }
892        }
893    }
894
895    public Route getRoute(String id) {
896        if (id != null) {
897            for (Route route : getRoutes()) {
898                if (route.getId().equals(id)) {
899                    return route;
900                }
901            }
902        }
903        return null;
904    }
905
906    public Processor getProcessor(String id) {
907        for (Route route : getRoutes()) {
908            List<Processor> list = route.filter(id);
909            if (list.size() == 1) {
910                return list.get(0);
911            }
912        }
913        return null;
914    }
915
916    public <T extends Processor> T getProcessor(String id, Class<T> type) {
917        Processor answer = getProcessor(id);
918        if (answer != null) {
919            return type.cast(answer);
920        }
921        return null;
922    }
923
924    public <T extends ManagedProcessorMBean> T getManagedProcessor(String id, Class<T> type) {
925        // jmx must be enabled
926        if (getManagementStrategy().getManagementAgent() == null) {
927            return null;
928        }
929
930        Processor processor = getProcessor(id);
931        ProcessorDefinition def = getProcessorDefinition(id);
932
933        // processor may be null if its anonymous inner class or as lambda
934        if (def != null) {
935            try {
936                ObjectName on = getManagementStrategy().getManagementNamingStrategy().getObjectNameForProcessor(this, processor, def);
937                return getManagementStrategy().getManagementAgent().newProxyClient(on, type);
938            } catch (MalformedObjectNameException e) {
939                throw ObjectHelper.wrapRuntimeCamelException(e);
940            }
941        }
942
943        return null;
944    }
945
946    public <T extends ManagedRouteMBean> T getManagedRoute(String routeId, Class<T> type) {
947        // jmx must be enabled
948        if (getManagementStrategy().getManagementAgent() == null) {
949            return null;
950        }
951
952        Route route = getRoute(routeId);
953
954        if (route != null) {
955            try {
956                ObjectName on = getManagementStrategy().getManagementNamingStrategy().getObjectNameForRoute(route);
957                return getManagementStrategy().getManagementAgent().newProxyClient(on, type);
958            } catch (MalformedObjectNameException e) {
959                throw ObjectHelper.wrapRuntimeCamelException(e);
960            }
961        }
962
963        return null;
964    }
965
966    public ManagedCamelContextMBean getManagedCamelContext() {
967        // jmx must be enabled
968        if (getManagementStrategy().getManagementAgent() == null) {
969            return null;
970        }
971
972        try {
973            ObjectName on = getManagementStrategy().getManagementNamingStrategy().getObjectNameForCamelContext(this);
974            return getManagementStrategy().getManagementAgent().newProxyClient(on, ManagedCamelContextMBean.class);
975        } catch (MalformedObjectNameException e) {
976            throw ObjectHelper.wrapRuntimeCamelException(e);
977        }
978    }
979
980    public ProcessorDefinition getProcessorDefinition(String id) {
981        for (RouteDefinition route : getRouteDefinitions()) {
982            Iterator<ProcessorDefinition> it = ProcessorDefinitionHelper.filterTypeInOutputs(route.getOutputs(), ProcessorDefinition.class);
983            while (it.hasNext()) {
984                ProcessorDefinition proc = it.next();
985                if (id.equals(proc.getId())) {
986                    return proc;
987                }
988            }
989        }
990        return null;
991    }
992
993    public <T extends ProcessorDefinition> T getProcessorDefinition(String id, Class<T> type) {
994        ProcessorDefinition answer = getProcessorDefinition(id);
995        if (answer != null) {
996            return type.cast(answer);
997        }
998        return null;
999    }
1000
1001    @Deprecated
1002    public void setRoutes(List<Route> routes) {
1003        throw new UnsupportedOperationException("Overriding existing routes is not supported yet, use addRouteCollection instead");
1004    }
1005
1006    void removeRouteCollection(Collection<Route> routes) {
1007        synchronized (this.routes) {
1008            this.routes.removeAll(routes);
1009        }
1010    }
1011
1012    void addRouteCollection(Collection<Route> routes) throws Exception {
1013        synchronized (this.routes) {
1014            this.routes.addAll(routes);
1015        }
1016    }
1017
1018    public void addRoutes(final RoutesBuilder builder) throws Exception {
1019        log.debug("Adding routes from builder: {}", builder);
1020        doWithDefinedClassLoader(new Callable<Void>() {
1021            @Override
1022            public Void call() throws Exception {
1023                builder.addRoutesToCamelContext(DefaultCamelContext.this);
1024                return null;
1025            }
1026        });
1027    }
1028
1029    public synchronized RoutesDefinition loadRoutesDefinition(InputStream is) throws Exception {
1030        return ModelHelper.loadRoutesDefinition(this, is);
1031    }
1032
1033    public synchronized RestsDefinition loadRestsDefinition(InputStream is) throws Exception {
1034        // load routes using JAXB
1035        if (jaxbContext == null) {
1036            // must use classloader from CamelContext to have JAXB working
1037            jaxbContext = getModelJAXBContextFactory().newJAXBContext();
1038        }
1039
1040        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
1041        Object result = unmarshaller.unmarshal(is);
1042
1043        if (result == null) {
1044            throw new IOException("Cannot unmarshal to rests using JAXB from input stream: " + is);
1045        }
1046
1047        // can either be routes or a single route
1048        RestsDefinition answer;
1049        if (result instanceof RestDefinition) {
1050            RestDefinition rest = (RestDefinition) result;
1051            answer = new RestsDefinition();
1052            answer.getRests().add(rest);
1053        } else if (result instanceof RestsDefinition) {
1054            answer = (RestsDefinition) result;
1055        } else {
1056            throw new IllegalArgumentException("Unmarshalled object is an unsupported type: " + ObjectHelper.className(result) + " -> " + result);
1057        }
1058
1059        return answer;
1060    }
1061
1062    public synchronized void addRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
1063        if (routeDefinitions == null || routeDefinitions.isEmpty()) {
1064            return;
1065        }
1066        for (RouteDefinition routeDefinition : routeDefinitions) {
1067            removeRouteDefinition(routeDefinition);
1068        }
1069        this.routeDefinitions.addAll(routeDefinitions);
1070        if (shouldStartRoutes()) {
1071            startRouteDefinitions(routeDefinitions);
1072        }
1073    }
1074
1075    public void addRouteDefinition(RouteDefinition routeDefinition) throws Exception {
1076        addRouteDefinitions(Arrays.asList(routeDefinition));
1077    }
1078
1079    /**
1080     * Removes the route definition with the given key.
1081     *
1082     * @return true if one or more routes was removed
1083     */
1084    protected boolean removeRouteDefinition(String key) {
1085        boolean answer = false;
1086        Iterator<RouteDefinition> iter = routeDefinitions.iterator();
1087        while (iter.hasNext()) {
1088            RouteDefinition route = iter.next();
1089            if (route.idOrCreate(nodeIdFactory).equals(key)) {
1090                iter.remove();
1091                answer = true;
1092            }
1093        }
1094        return answer;
1095    }
1096
1097    public synchronized void removeRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
1098        for (RouteDefinition routeDefinition : routeDefinitions) {
1099            removeRouteDefinition(routeDefinition);
1100        }
1101    }
1102
1103    public synchronized void removeRouteDefinition(RouteDefinition routeDefinition) throws Exception {
1104        RouteDefinition toBeRemoved = routeDefinition;
1105        String id = routeDefinition.getId();
1106        if (id != null) {
1107            // remove existing route
1108            stopRoute(id);
1109            removeRoute(id);
1110            toBeRemoved = getRouteDefinition(id);
1111        }
1112        this.routeDefinitions.remove(toBeRemoved);
1113    }
1114
1115    public ServiceStatus getRouteStatus(String key) {
1116        RouteService routeService = routeServices.get(key);
1117        if (routeService != null) {
1118            return routeService.getStatus();
1119        }
1120        return null;
1121    }
1122
1123    public void startRoute(RouteDefinition route) throws Exception {
1124        // assign ids to the routes and validate that the id's is all unique
1125        RouteDefinitionHelper.forceAssignIds(this, routeDefinitions);
1126        String duplicate = RouteDefinitionHelper.validateUniqueIds(route, routeDefinitions);
1127        if (duplicate != null) {
1128            throw new FailedToStartRouteException(route.getId(), "duplicate id detected: " + duplicate + ". Please correct ids to be unique among all your routes.");
1129        }
1130
1131        // indicate we are staring the route using this thread so
1132        // we are able to query this if needed
1133        isStartingRoutes.set(true);
1134        try {
1135            // must ensure route is prepared, before we can start it
1136            route.prepare(this);
1137
1138            List<Route> routes = new ArrayList<>();
1139            List<RouteContext> routeContexts = route.addRoutes(this, routes);
1140            RouteService routeService = new RouteService(this, route, routeContexts, routes);
1141            startRouteService(routeService, true);
1142        } finally {
1143            // we are done staring routes
1144            isStartingRoutes.remove();
1145        }
1146    }
1147
1148    public boolean isStartingRoutes() {
1149        Boolean answer = isStartingRoutes.get();
1150        return answer != null && answer;
1151    }
1152
1153    public boolean isSetupRoutes() {
1154        Boolean answer = isSetupRoutes.get();
1155        return answer != null && answer;
1156    }
1157
1158    public void stopRoute(RouteDefinition route) throws Exception {
1159        stopRoute(route.idOrCreate(nodeIdFactory));
1160    }
1161
1162    public void startAllRoutes() throws Exception {
1163        doStartOrResumeRoutes(routeServices, true, true, false, false);
1164    }
1165
1166    public synchronized void startRoute(String routeId) throws Exception {
1167        DefaultRouteError.reset(this, routeId);
1168
1169        RouteService routeService = routeServices.get(routeId);
1170        if (routeService != null) {
1171            try {
1172                startRouteService(routeService, false);
1173            } catch (Exception e) {
1174                DefaultRouteError.set(this, routeId, RouteError.Phase.START, e);
1175                throw e;
1176            }
1177        }
1178    }
1179
1180    public synchronized void resumeRoute(String routeId) throws Exception {
1181        DefaultRouteError.reset(this, routeId);
1182
1183        try {
1184            if (!routeSupportsSuspension(routeId)) {
1185                // start route if suspension is not supported
1186                startRoute(routeId);
1187                return;
1188            }
1189
1190            RouteService routeService = routeServices.get(routeId);
1191            if (routeService != null) {
1192                resumeRouteService(routeService);
1193                // must resume the route as well
1194                Route route = getRoute(routeId);
1195                ServiceHelper.resumeService(route);
1196            }
1197        } catch (Exception e) {
1198            DefaultRouteError.set(this, routeId, RouteError.Phase.RESUME, e);
1199            throw e;
1200        }
1201    }
1202
1203    public synchronized boolean stopRoute(String routeId, long timeout, TimeUnit timeUnit, boolean abortAfterTimeout) throws Exception {
1204        DefaultRouteError.reset(this, routeId);
1205
1206        RouteService routeService = routeServices.get(routeId);
1207        if (routeService != null) {
1208            try {
1209                RouteStartupOrder route = new DefaultRouteStartupOrder(1, routeService.getRoutes().iterator().next(), routeService);
1210
1211                boolean completed = getShutdownStrategy().shutdown(this, route, timeout, timeUnit, abortAfterTimeout);
1212                if (completed) {
1213                    // must stop route service as well
1214                    stopRouteService(routeService, false);
1215                } else {
1216                    // shutdown was aborted, make sure route is re-started properly
1217                    startRouteService(routeService, false);
1218                }
1219                return completed;
1220            } catch (Exception e) {
1221                DefaultRouteError.set(this, routeId, RouteError.Phase.STOP, e);
1222                throw e;
1223            }
1224        }
1225
1226        return false;
1227    }
1228
1229    public synchronized void stopRoute(String routeId) throws Exception {
1230        DefaultRouteError.reset(this, routeId);
1231
1232        RouteService routeService = routeServices.get(routeId);
1233        if (routeService != null) {
1234            try {
1235                List<RouteStartupOrder> routes = new ArrayList<>(1);
1236                RouteStartupOrder order = new DefaultRouteStartupOrder(1, routeService.getRoutes().iterator().next(), routeService);
1237                routes.add(order);
1238
1239                getShutdownStrategy().shutdown(this, routes);
1240                // must stop route service as well
1241                stopRouteService(routeService, false);
1242            } catch (Exception e) {
1243                DefaultRouteError.set(this, routeId, RouteError.Phase.STOP, e);
1244                throw e;
1245            }
1246        }
1247    }
1248
1249    public synchronized void stopRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception {
1250        DefaultRouteError.reset(this, routeId);
1251
1252        RouteService routeService = routeServices.get(routeId);
1253        if (routeService != null) {
1254            try {
1255                List<RouteStartupOrder> routes = new ArrayList<>(1);
1256                RouteStartupOrder order = new DefaultRouteStartupOrder(1, routeService.getRoutes().iterator().next(), routeService);
1257                routes.add(order);
1258
1259                getShutdownStrategy().shutdown(this, routes, timeout, timeUnit);
1260                // must stop route service as well
1261                stopRouteService(routeService, false);
1262            } catch (Exception e) {
1263                DefaultRouteError.set(this, routeId, RouteError.Phase.STOP, e);
1264                throw e;
1265            }
1266        }
1267    }
1268
1269    public synchronized void shutdownRoute(String routeId) throws Exception {
1270        DefaultRouteError.reset(this, routeId);
1271
1272        RouteService routeService = routeServices.get(routeId);
1273        if (routeService != null) {
1274            try {
1275                List<RouteStartupOrder> routes = new ArrayList<>(1);
1276                RouteStartupOrder order = new DefaultRouteStartupOrder(1, routeService.getRoutes().iterator().next(), routeService);
1277                routes.add(order);
1278
1279                getShutdownStrategy().shutdown(this, routes);
1280                // must stop route service as well (and remove the routes from management)
1281                stopRouteService(routeService, true);
1282            } catch (Exception e) {
1283                DefaultRouteError.set(this, routeId, RouteError.Phase.SHUTDOWN, e);
1284                throw e;
1285            }
1286        }
1287    }
1288
1289    public synchronized void shutdownRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception {
1290        DefaultRouteError.reset(this, routeId);
1291
1292        RouteService routeService = routeServices.get(routeId);
1293        if (routeService != null) {
1294            try {
1295                List<RouteStartupOrder> routes = new ArrayList<>(1);
1296                RouteStartupOrder order = new DefaultRouteStartupOrder(1, routeService.getRoutes().iterator().next(), routeService);
1297                routes.add(order);
1298
1299                getShutdownStrategy().shutdown(this, routes, timeout, timeUnit);
1300                // must stop route service as well (and remove the routes from management)
1301                stopRouteService(routeService, true);
1302            } catch (Exception e) {
1303                DefaultRouteError.set(this, routeId, RouteError.Phase.SHUTDOWN, e);
1304                throw e;
1305            }
1306        }
1307    }
1308
1309    public synchronized boolean removeRoute(String routeId) throws Exception {
1310        DefaultRouteError.reset(this, routeId);
1311
1312        // remove the route from ErrorHandlerBuilder if possible
1313        if (getErrorHandlerBuilder() instanceof ErrorHandlerBuilderSupport) {
1314            ErrorHandlerBuilderSupport builder = (ErrorHandlerBuilderSupport)getErrorHandlerBuilder();
1315            builder.removeOnExceptionList(routeId);
1316        }
1317
1318        // gather a map of all the endpoints in use by the routes, so we can known if a given endpoints is in use
1319        // by one or more routes, when we remove the route
1320        Map<String, Set<Endpoint>> endpointsInUse = new HashMap<>();
1321        for (Map.Entry<String, RouteService> entry : routeServices.entrySet()) {
1322            endpointsInUse.put(entry.getKey(), entry.getValue().gatherEndpoints());
1323        }
1324
1325        RouteService routeService = routeServices.get(routeId);
1326        if (routeService != null) {
1327            if (getRouteStatus(routeId).isStopped()) {
1328                try {
1329                    routeService.setRemovingRoutes(true);
1330                    shutdownRouteService(routeService);
1331                    removeRouteDefinition(routeId);
1332                    routeServices.remove(routeId);
1333                    // remove route from startup order as well, as it was removed
1334                    Iterator<RouteStartupOrder> it = routeStartupOrder.iterator();
1335                    while (it.hasNext()) {
1336                        RouteStartupOrder order = it.next();
1337                        if (order.getRoute().getId().equals(routeId)) {
1338                            it.remove();
1339                        }
1340                    }
1341
1342                    // from the route which we have removed, then remove all its private endpoints
1343                    // (eg the endpoints which are not in use by other routes)
1344                    Set<Endpoint> toRemove = new LinkedHashSet<>();
1345                    for (Endpoint endpoint : endpointsInUse.get(routeId)) {
1346                        // how many times is the endpoint in use
1347                        int count = 0;
1348                        for (Set<Endpoint> endpoints : endpointsInUse.values()) {
1349                            if (endpoints.contains(endpoint)) {
1350                                count++;
1351                            }
1352                        }
1353                        // notice we will count ourselves so if there is only 1 then its safe to remove
1354                        if (count <= 1) {
1355                            toRemove.add(endpoint);
1356                        }
1357                    }
1358                    for (Endpoint endpoint : toRemove) {
1359                        log.debug("Removing: {} which was only in use by route: {}", endpoint, routeId);
1360                        removeEndpoint(endpoint);
1361                    }
1362                } catch  (Exception e) {
1363                    DefaultRouteError.set(this, routeId, RouteError.Phase.REMOVE, e);
1364                    throw e;
1365                }
1366
1367                return true;
1368            } else {
1369                return false;
1370            }
1371        }
1372        return false;
1373    }
1374
1375    public synchronized void suspendRoute(String routeId) throws Exception {
1376        try {
1377            DefaultRouteError.reset(this, routeId);
1378
1379            if (!routeSupportsSuspension(routeId)) {
1380                // stop if we suspend is not supported
1381                stopRoute(routeId);
1382                return;
1383            }
1384
1385            RouteService routeService = routeServices.get(routeId);
1386            if (routeService != null) {
1387                List<RouteStartupOrder> routes = new ArrayList<>(1);
1388                Route route = routeService.getRoutes().iterator().next();
1389                RouteStartupOrder order = new DefaultRouteStartupOrder(1, route, routeService);
1390                routes.add(order);
1391
1392                getShutdownStrategy().suspend(this, routes);
1393                // must suspend route service as well
1394                suspendRouteService(routeService);
1395                // must suspend the route as well
1396                if (route instanceof SuspendableService) {
1397                    ((SuspendableService) route).suspend();
1398                }
1399            }
1400        } catch (Exception e) {
1401            DefaultRouteError.set(this, routeId, RouteError.Phase.SUSPEND, e);
1402            throw e;
1403        }
1404    }
1405
1406    public synchronized void suspendRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception {
1407        DefaultRouteError.reset(this, routeId);
1408
1409        try {
1410            if (!routeSupportsSuspension(routeId)) {
1411                stopRoute(routeId, timeout, timeUnit);
1412                return;
1413            }
1414
1415            RouteService routeService = routeServices.get(routeId);
1416            if (routeService != null) {
1417                List<RouteStartupOrder> routes = new ArrayList<>(1);
1418                Route route = routeService.getRoutes().iterator().next();
1419                RouteStartupOrder order = new DefaultRouteStartupOrder(1, route, routeService);
1420                routes.add(order);
1421
1422                getShutdownStrategy().suspend(this, routes, timeout, timeUnit);
1423                // must suspend route service as well
1424                suspendRouteService(routeService);
1425                // must suspend the route as well
1426                if (route instanceof SuspendableService) {
1427                    ((SuspendableService) route).suspend();
1428                }
1429            }
1430        } catch (Exception e) {
1431            DefaultRouteError.set(this, routeId, RouteError.Phase.SUSPEND, e);
1432            throw e;
1433        }
1434    }
1435
1436    public void addService(Object object) throws Exception {
1437        addService(object, true);
1438    }
1439
1440    public void addService(Object object, boolean stopOnShutdown) throws Exception {
1441        doAddService(object, stopOnShutdown, false);
1442    }
1443
1444    @Override
1445    public void addService(Object object, boolean stopOnShutdown, boolean forceStart) throws Exception {
1446        doAddService(object, stopOnShutdown, forceStart);
1447    }
1448
1449    private void doAddService(Object object, boolean stopOnShutdown, boolean forceStart) throws Exception {
1450
1451        // inject CamelContext
1452        if (object instanceof CamelContextAware) {
1453            CamelContextAware aware = (CamelContextAware) object;
1454            aware.setCamelContext(this);
1455        }
1456
1457        if (object instanceof Service) {
1458            Service service = (Service) object;
1459
1460            for (LifecycleStrategy strategy : lifecycleStrategies) {
1461                if (service instanceof Endpoint) {
1462                    // use specialized endpoint add
1463                    strategy.onEndpointAdd((Endpoint) service);
1464                } else {
1465                    strategy.onServiceAdd(this, service, null);
1466                }
1467            }
1468
1469            if (!forceStart) {
1470                // now start the service (and defer starting if CamelContext is starting up itself)
1471                deferStartService(object, stopOnShutdown);
1472            } else {
1473                // only add to services to close if its a singleton
1474                // otherwise we could for example end up with a lot of prototype scope endpoints
1475                boolean singleton = true; // assume singleton by default
1476                if (object instanceof IsSingleton) {
1477                    singleton = ((IsSingleton) service).isSingleton();
1478                }
1479                // do not add endpoints as they have their own list
1480                if (singleton && !(service instanceof Endpoint)) {
1481                    // only add to list of services to stop if its not already there
1482                    if (stopOnShutdown && !hasService(service)) {
1483                        servicesToStop.add(service);
1484                    }
1485                }
1486                ServiceHelper.startService(service);
1487            }
1488        }
1489    }
1490
1491    public boolean removeService(Object object) throws Exception {
1492        if (object instanceof Endpoint) {
1493            removeEndpoint((Endpoint) object);
1494            return true;
1495        }
1496        if (object instanceof Service) {
1497            Service service = (Service) object;
1498            for (LifecycleStrategy strategy : lifecycleStrategies) {
1499                strategy.onServiceRemove(this, service, null);
1500            }
1501            return servicesToStop.remove(service);
1502        }
1503        return false;
1504    }
1505
1506    public boolean hasService(Object object) {
1507        if (object instanceof Service) {
1508            Service service = (Service) object;
1509            return servicesToStop.contains(service);
1510        }
1511        return false;
1512    }
1513
1514    @Override
1515    public <T> T hasService(Class<T> type) {
1516        for (Service service : servicesToStop) {
1517            if (type.isInstance(service)) {
1518                return type.cast(service);
1519            }
1520        }
1521        return null;
1522    }
1523
1524    @Override
1525    public <T> Set<T> hasServices(Class<T> type) {
1526        Set<T> set = new HashSet<>();
1527        for (Service service : servicesToStop) {
1528            if (type.isInstance(service)) {
1529                set.add((T) service);
1530            }
1531        }
1532        return set;
1533    }
1534
1535    public void deferStartService(Object object, boolean stopOnShutdown) throws Exception {
1536        if (object instanceof Service) {
1537            Service service = (Service) object;
1538
1539            // only add to services to close if its a singleton
1540            // otherwise we could for example end up with a lot of prototype scope endpoints
1541            boolean singleton = true; // assume singleton by default
1542            if (object instanceof IsSingleton) {
1543                singleton = ((IsSingleton) service).isSingleton();
1544            }
1545            // do not add endpoints as they have their own list
1546            if (singleton && !(service instanceof Endpoint)) {
1547                // only add to list of services to stop if its not already there
1548                if (stopOnShutdown && !hasService(service)) {
1549                    servicesToStop.add(service);
1550                }
1551            }
1552            // are we already started?
1553            if (isStarted()) {
1554                ServiceHelper.startService(service);
1555            } else {
1556                deferStartupListener.addService(service);
1557            }
1558        }
1559    }
1560
1561    public void addStartupListener(StartupListener listener) throws Exception {
1562        // either add to listener so we can invoke then later when CamelContext has been started
1563        // or invoke the callback right now
1564        if (isStarted()) {
1565            listener.onCamelContextStarted(this, true);
1566        } else {
1567            startupListeners.add(listener);
1568        }
1569    }
1570
1571    public String resolveComponentDefaultName(String javaType) {
1572        // special for some components
1573        // TODO: ActiveMQ 5.11 will include this out of the box, so not needed when its released
1574        if ("org.apache.activemq.camel.component.ActiveMQComponent".equals(javaType)) {
1575            return "jms";
1576        }
1577
1578        // try to find the component by its java type from the in-use components
1579        if (javaType != null) {
1580            // find all the components which will include the default component name
1581            try {
1582                Map<String, Properties> all = CamelContextHelper.findComponents(this);
1583                for (Map.Entry<String, Properties> entry : all.entrySet()) {
1584                    String fqn = (String) entry.getValue().get("class");
1585                    if (javaType.equals(fqn)) {
1586                        // is there component docs for that name?
1587                        String name = entry.getKey();
1588                        String json = getComponentParameterJsonSchema(name);
1589                        if (json != null) {
1590                            return name;
1591                        }
1592                    }
1593                }
1594            } catch (Exception e) {
1595                // ignore
1596                return null;
1597            }
1598        }
1599
1600        // could not find a component with that name
1601        return null;
1602    }
1603
1604    public Map<String, Properties> findComponents() throws LoadPropertiesException, IOException {
1605        return CamelContextHelper.findComponents(this);
1606    }
1607
1608    public Map<String, Properties> findEips() throws LoadPropertiesException, IOException {
1609        return CamelContextHelper.findEips(this);
1610    }
1611
1612    public String getComponentDocumentation(String componentName) throws IOException {
1613        return null;
1614    }
1615
1616    public String getComponentParameterJsonSchema(String componentName) throws IOException {
1617        // use the component factory finder to find the package name of the component class, which is the location
1618        // where the documentation exists as well
1619        FactoryFinder finder = getFactoryFinder(DefaultComponentResolver.RESOURCE_PATH);
1620        try {
1621            Class<?> clazz = null;
1622            try {
1623                clazz = finder.findClass(componentName);
1624            } catch (NoFactoryAvailableException e) {
1625                // ignore, i.e. if a component is an auto-configured spring-boot
1626                // component
1627            }
1628
1629            if (clazz == null) {
1630                // fallback and find existing component
1631                Component existing = hasComponent(componentName);
1632                if (existing != null) {
1633                    clazz = existing.getClass();
1634                } else {
1635                    return null;
1636                }
1637            }
1638
1639            String packageName = clazz.getPackage().getName();
1640            packageName = packageName.replace('.', '/');
1641            String path = packageName + "/" + componentName + ".json";
1642
1643            ClassResolver resolver = getClassResolver();
1644            InputStream inputStream = resolver.loadResourceAsStream(path);
1645            log.debug("Loading component JSON Schema for: {} using class resolver: {} -> {}", componentName, resolver, inputStream);
1646            if (inputStream != null) {
1647                try {
1648                    return IOHelper.loadText(inputStream);
1649                } finally {
1650                    IOHelper.close(inputStream);
1651                }
1652            }
1653            // special for ActiveMQ as it is really just JMS
1654            if ("ActiveMQComponent".equals(clazz.getSimpleName())) {
1655                return getComponentParameterJsonSchema("jms");
1656            } else {
1657                return null;
1658            }
1659        } catch (ClassNotFoundException e) {
1660            return null;
1661        }
1662    }
1663
1664    public String getDataFormatParameterJsonSchema(String dataFormatName) throws IOException {
1665        // use the dataformat factory finder to find the package name of the dataformat class, which is the location
1666        // where the documentation exists as well
1667        FactoryFinder finder = getFactoryFinder(DefaultDataFormatResolver.DATAFORMAT_RESOURCE_PATH);
1668        try {
1669            Class<?> clazz = null;
1670            try {
1671                clazz = finder.findClass(dataFormatName);
1672            } catch (NoFactoryAvailableException e) {
1673                // ignore, i.e. if a component is an auto-configured spring-boot
1674                // data-formats
1675            }
1676
1677            if (clazz == null) {
1678                return null;
1679            }
1680
1681            String packageName = clazz.getPackage().getName();
1682            packageName = packageName.replace('.', '/');
1683            String path = packageName + "/" + dataFormatName + ".json";
1684
1685            ClassResolver resolver = getClassResolver();
1686            InputStream inputStream = resolver.loadResourceAsStream(path);
1687            log.debug("Loading dataformat JSON Schema for: {} using class resolver: {} -> {}", dataFormatName, resolver, inputStream);
1688            if (inputStream != null) {
1689                try {
1690                    return IOHelper.loadText(inputStream);
1691                } finally {
1692                    IOHelper.close(inputStream);
1693                }
1694            }
1695            return null;
1696
1697        } catch (ClassNotFoundException e) {
1698            return null;
1699        }
1700    }
1701
1702    public String getLanguageParameterJsonSchema(String languageName) throws IOException {
1703        // use the language factory finder to find the package name of the language class, which is the location
1704        // where the documentation exists as well
1705        FactoryFinder finder = getFactoryFinder(DefaultLanguageResolver.LANGUAGE_RESOURCE_PATH);
1706        try {
1707            Class<?> clazz = null;
1708            try {
1709                clazz = finder.findClass(languageName);
1710            } catch (NoFactoryAvailableException e) {
1711                // ignore, i.e. if a component is an auto-configured spring-boot
1712                // languages
1713            }
1714
1715            if (clazz == null) {
1716                return null;
1717            }
1718
1719            String packageName = clazz.getPackage().getName();
1720            packageName = packageName.replace('.', '/');
1721            String path = packageName + "/" + languageName + ".json";
1722
1723            ClassResolver resolver = getClassResolver();
1724            InputStream inputStream = resolver.loadResourceAsStream(path);
1725            log.debug("Loading language JSON Schema for: {} using class resolver: {} -> {}", languageName, resolver, inputStream);
1726            if (inputStream != null) {
1727                try {
1728                    return IOHelper.loadText(inputStream);
1729                } finally {
1730                    IOHelper.close(inputStream);
1731                }
1732            }
1733            return null;
1734
1735        } catch (ClassNotFoundException e) {
1736            return null;
1737        }
1738    }
1739
1740    public String getEipParameterJsonSchema(String eipName) throws IOException {
1741        // the eip json schema may be in some of the sub-packages so look until we find it
1742        String[] subPackages = new String[]{"", "/config", "/dataformat", "/language", "/loadbalancer", "/rest"};
1743        for (String sub : subPackages) {
1744            String path = CamelContextHelper.MODEL_DOCUMENTATION_PREFIX + sub + "/" + eipName + ".json";
1745            ClassResolver resolver = getClassResolver();
1746            InputStream inputStream = resolver.loadResourceAsStream(path);
1747            if (inputStream != null) {
1748                log.debug("Loading eip JSON Schema for: {} using class resolver: {} -> {}", eipName, resolver, inputStream);
1749                try {
1750                    return IOHelper.loadText(inputStream);
1751                } finally {
1752                    IOHelper.close(inputStream);
1753                }
1754            }
1755        }
1756        return null;
1757    }
1758
1759    public String explainEipJson(String nameOrId, boolean includeAllOptions) {
1760        try {
1761            // try to find the id within all known routes and their eips
1762            String eipName = nameOrId;
1763            NamedNode target = null;
1764            for (RouteDefinition route : getRouteDefinitions()) {
1765                if (route.getId().equals(nameOrId)) {
1766                    target = route;
1767                    break;
1768                }
1769                for (FromDefinition from : route.getInputs()) {
1770                    if (nameOrId.equals(from.getId())) {
1771                        target = route;
1772                        break;
1773                    }
1774                }
1775                Iterator<ProcessorDefinition> it = ProcessorDefinitionHelper.filterTypeInOutputs(route.getOutputs(), ProcessorDefinition.class);
1776                while (it.hasNext()) {
1777                    ProcessorDefinition def = it.next();
1778                    if (nameOrId.equals(def.getId())) {
1779                        target = def;
1780                        break;
1781                    }
1782                }
1783                if (target != null) {
1784                    break;
1785                }
1786            }
1787
1788            if (target != null) {
1789                eipName = target.getShortName();
1790            }
1791
1792            String json = getEipParameterJsonSchema(eipName);
1793            if (json == null) {
1794                return null;
1795            }
1796
1797            // overlay with runtime parameters that id uses at runtime
1798            if (target != null) {
1799                List<Map<String, String>> rows = JsonSchemaHelper.parseJsonSchema("properties", json, true);
1800
1801                // selected rows to use for answer
1802                Map<String, String[]> selected = new LinkedHashMap<>();
1803
1804                // extract options from the node
1805                Map<String, Object> options = new LinkedHashMap<>();
1806                IntrospectionSupport.getProperties(target, options, "", false);
1807                // remove outputs which we do not want to include
1808                options.remove("outputs");
1809
1810                // include other rows
1811                for (Map<String, String> row : rows) {
1812                    String name = row.get("name");
1813                    String kind = row.get("kind");
1814                    String label = row.get("label");
1815                    String required = row.get("required");
1816                    String value = row.get("value");
1817                    String defaultValue = row.get("defaultValue");
1818                    String type = row.get("type");
1819                    String javaType = row.get("javaType");
1820                    String deprecated = row.get("deprecated");
1821                    String description = row.get("description");
1822
1823                    // find the configured option
1824                    Object o = options.get(name);
1825                    if (o != null) {
1826                        value = o.toString();
1827                    }
1828
1829                    value = URISupport.sanitizePath(value);
1830
1831                    if (includeAllOptions || o != null) {
1832                        // add as selected row
1833                        if (!selected.containsKey(name)) {
1834                            selected.put(name, new String[]{name, kind, label, required, type, javaType, deprecated, value, defaultValue, description});
1835                        }
1836                    }
1837                }
1838
1839                json = StringHelper.before(json, "  \"properties\": {");
1840
1841                StringBuilder buffer = new StringBuilder("  \"properties\": {");
1842
1843                boolean first = true;
1844                for (String[] row : selected.values()) {
1845                    if (first) {
1846                        first = false;
1847                    } else {
1848                        buffer.append(",");
1849                    }
1850                    buffer.append("\n    ");
1851
1852                    String name = row[0];
1853                    String kind = row[1];
1854                    String label = row[2];
1855                    String required = row[3];
1856                    String type = row[4];
1857                    String javaType = row[5];
1858                    String deprecated = row[6];
1859                    String value = row[7];
1860                    String defaultValue = row[8];
1861                    String description = row[9];
1862
1863                    // add json of the option
1864                    buffer.append(StringQuoteHelper.doubleQuote(name)).append(": { ");
1865                    CollectionStringBuffer csb = new CollectionStringBuffer();
1866                    if (kind != null) {
1867                        csb.append("\"kind\": \"" + kind + "\"");
1868                    }
1869                    if (label != null) {
1870                        csb.append("\"label\": \"" + label + "\"");
1871                    }
1872                    if (required != null) {
1873                        csb.append("\"required\": \"" + required + "\"");
1874                    }
1875                    if (type != null) {
1876                        csb.append("\"type\": \"" + type + "\"");
1877                    }
1878                    if (javaType != null) {
1879                        csb.append("\"javaType\": \"" + javaType + "\"");
1880                    }
1881                    if (deprecated != null) {
1882                        csb.append("\"deprecated\": \"" + deprecated + "\"");
1883                    }
1884                    if (value != null) {
1885                        csb.append("\"value\": \"" + value + "\"");
1886                    }
1887                    if (defaultValue != null) {
1888                        csb.append("\"defaultValue\": \"" + defaultValue + "\"");
1889                    }
1890                    if (description != null) {
1891                        csb.append("\"description\": \"" + description + "\"");
1892                    }
1893                    if (!csb.isEmpty()) {
1894                        buffer.append(csb.toString());
1895                    }
1896                    buffer.append(" }");
1897                }
1898
1899                buffer.append("\n  }\n}\n");
1900
1901                // insert the original first part of the json into the start of the buffer
1902                buffer.insert(0, json);
1903                return buffer.toString();
1904            }
1905
1906            return json;
1907        } catch (Exception e) {
1908            // ignore and return empty response
1909            return null;
1910        }
1911    }
1912
1913    public String explainDataFormatJson(String dataFormatName, DataFormat dataFormat, boolean includeAllOptions) {
1914        try {
1915            String json = getDataFormatParameterJsonSchema(dataFormatName);
1916            if (json == null) {
1917                // the model may be shared for multiple data formats such as bindy, json (xstream, jackson, gson)
1918                if (dataFormatName.contains("-")) {
1919                    dataFormatName = StringHelper.before(dataFormatName, "-");
1920                    json = getDataFormatParameterJsonSchema(dataFormatName);
1921                }
1922                if (json == null) {
1923                    return null;
1924                }
1925            }
1926
1927            List<Map<String, String>> rows = JsonSchemaHelper.parseJsonSchema("properties", json, true);
1928
1929            // selected rows to use for answer
1930            Map<String, String[]> selected = new LinkedHashMap<>();
1931            Map<String, String[]> dataFormatOptions = new LinkedHashMap<>();
1932
1933            // extract options from the data format
1934            Map<String, Object> options = new LinkedHashMap<>();
1935            IntrospectionSupport.getProperties(dataFormat, options, "", false);
1936
1937            for (Map.Entry<String, Object> entry : options.entrySet()) {
1938                String name = entry.getKey();
1939                String value = "";
1940                if (entry.getValue() != null) {
1941                    value = entry.getValue().toString();
1942                }
1943                value = URISupport.sanitizePath(value);
1944
1945                // find type and description from the json schema
1946                String type = null;
1947                String kind = null;
1948                String label = null;
1949                String required = null;
1950                String javaType = null;
1951                String deprecated = null;
1952                String secret = null;
1953                String defaultValue = null;
1954                String description = null;
1955                for (Map<String, String> row : rows) {
1956                    if (name.equals(row.get("name"))) {
1957                        type = row.get("type");
1958                        kind = row.get("kind");
1959                        label = row.get("label");
1960                        required = row.get("required");
1961                        javaType = row.get("javaType");
1962                        deprecated = row.get("deprecated");
1963                        secret = row.get("secret");
1964                        defaultValue = row.get("defaultValue");
1965                        description = row.get("description");
1966                        break;
1967                    }
1968                }
1969
1970                // remember this option from the uri
1971                dataFormatOptions.put(name, new String[]{name, kind, label, required, type, javaType, deprecated, secret, value, defaultValue, description});
1972            }
1973
1974            // include other rows
1975            for (Map<String, String> row : rows) {
1976                String name = row.get("name");
1977                String kind = row.get("kind");
1978                String label = row.get("label");
1979                String required = row.get("required");
1980                String value = row.get("value");
1981                String defaultValue = row.get("defaultValue");
1982                String type = row.get("type");
1983                String javaType = row.get("javaType");
1984                String deprecated = row.get("deprecated");
1985                String secret = row.get("secret");
1986                value = URISupport.sanitizePath(value);
1987                String description = row.get("description");
1988
1989                boolean isDataFormatOption = dataFormatOptions.containsKey(name);
1990
1991                // always include from uri or path options
1992                if (includeAllOptions || isDataFormatOption) {
1993                    if (!selected.containsKey(name)) {
1994                        // add as selected row, but take the value from uri options if it was from there
1995                        if (isDataFormatOption) {
1996                            selected.put(name, dataFormatOptions.get(name));
1997                        } else {
1998                            selected.put(name, new String[]{name, kind, label, required, type, javaType, deprecated, secret, value, defaultValue, description});
1999                        }
2000                    }
2001                }
2002            }
2003
2004            json = StringHelper.before(json, "  \"properties\": {");
2005
2006            StringBuilder buffer = new StringBuilder("  \"properties\": {");
2007
2008            boolean first = true;
2009            for (String[] row : selected.values()) {
2010                if (first) {
2011                    first = false;
2012                } else {
2013                    buffer.append(",");
2014                }
2015                buffer.append("\n    ");
2016
2017                String name = row[0];
2018                String kind = row[1];
2019                String label = row[2];
2020                String required = row[3];
2021                String type = row[4];
2022                String javaType = row[5];
2023                String deprecated = row[6];
2024                String secret = row[7];
2025                String value = row[8];
2026                String defaultValue = row[9];
2027                String description = row[10];
2028
2029                // add json of the option
2030                buffer.append(StringQuoteHelper.doubleQuote(name)).append(": { ");
2031                CollectionStringBuffer csb = new CollectionStringBuffer();
2032                if (kind != null) {
2033                    csb.append("\"kind\": \"" + kind + "\"");
2034                }
2035                if (label != null) {
2036                    csb.append("\"label\": \"" + label + "\"");
2037                }
2038                if (required != null) {
2039                    csb.append("\"required\": \"" + required + "\"");
2040                }
2041                if (type != null) {
2042                    csb.append("\"type\": \"" + type + "\"");
2043                }
2044                if (javaType != null) {
2045                    csb.append("\"javaType\": \"" + javaType + "\"");
2046                }
2047                if (deprecated != null) {
2048                    csb.append("\"deprecated\": \"" + deprecated + "\"");
2049                }
2050                if (secret != null) {
2051                    csb.append("\"secret\": \"" + secret + "\"");
2052                }
2053                if (value != null) {
2054                    csb.append("\"value\": \"" + value + "\"");
2055                }
2056                if (defaultValue != null) {
2057                    csb.append("\"defaultValue\": \"" + defaultValue + "\"");
2058                }
2059                if (description != null) {
2060                    csb.append("\"description\": \"" + description + "\"");
2061                }
2062                if (!csb.isEmpty()) {
2063                    buffer.append(csb.toString());
2064                }
2065                buffer.append(" }");
2066            }
2067
2068            buffer.append("\n  }\n}\n");
2069
2070            // insert the original first part of the json into the start of the buffer
2071            buffer.insert(0, json);
2072            return buffer.toString();
2073
2074        } catch (Exception e) {
2075            // ignore and return empty response
2076            return null;
2077        }
2078    }
2079
2080    public String explainComponentJson(String componentName, boolean includeAllOptions) {
2081        try {
2082            String json = getComponentParameterJsonSchema(componentName);
2083            if (json == null) {
2084                return null;
2085            }
2086            List<Map<String, String>> rows = JsonSchemaHelper.parseJsonSchema("componentProperties", json, true);
2087
2088            // selected rows to use for answer
2089            Map<String, String[]> selected = new LinkedHashMap<>();
2090
2091            // insert values from component
2092            Component component = getComponent(componentName);
2093            Map<String, Object> options = new HashMap<>();
2094            IntrospectionSupport.getProperties(component, options, null);
2095
2096            for (Map.Entry<String, Object> entry : options.entrySet()) {
2097                String name = entry.getKey();
2098                // skip unwanted options which is default inherited from DefaultComponent
2099                if ("camelContext".equals(name) || "endpointClass".equals(name)) {
2100                    continue;
2101                }
2102                String value = "";
2103                if (entry.getValue() != null) {
2104                    value = entry.getValue().toString();
2105                }
2106                value = URISupport.sanitizePath(value);
2107
2108                // find type and description from the json schema
2109                String type = null;
2110                String kind = null;
2111                String group = null;
2112                String label = null;
2113                String required = null;
2114                String javaType = null;
2115                String deprecated = null;
2116                String secret = null;
2117                String defaultValue = null;
2118                String description = null;
2119                for (Map<String, String> row : rows) {
2120                    if (name.equals(row.get("name"))) {
2121                        type = row.get("type");
2122                        kind = row.get("kind");
2123                        group = row.get("group");
2124                        label = row.get("label");
2125                        required = row.get("required");
2126                        javaType = row.get("javaType");
2127                        deprecated = row.get("deprecated");
2128                        secret = row.get("secret");
2129                        defaultValue = row.get("defaultValue");
2130                        description = row.get("description");
2131                        break;
2132                    }
2133                }
2134                // add as selected row
2135                selected.put(name, new String[]{name, kind, group, label, required, type, javaType, deprecated, secret, value, defaultValue, description});
2136            }
2137
2138            // include other rows
2139            for (Map<String, String> row : rows) {
2140                String name = row.get("name");
2141                String kind = row.get("kind");
2142                String group = row.get("group");
2143                String label = row.get("label");
2144                String required = row.get("required");
2145                String value = row.get("value");
2146                String defaultValue = row.get("defaultValue");
2147                String type = row.get("type");
2148                String javaType = row.get("javaType");
2149                String deprecated = row.get("deprecated");
2150                String secret = row.get("secret");
2151                value = URISupport.sanitizePath(value);
2152                String description = row.get("description");
2153                // always include path options
2154                if (includeAllOptions) {
2155                    // add as selected row
2156                    if (!selected.containsKey(name)) {
2157                        selected.put(name, new String[]{name, kind, group, label, required, type, javaType, deprecated, secret, value, defaultValue, description});
2158                    }
2159                }
2160            }
2161
2162            json = StringHelper.before(json, "  \"componentProperties\": {");
2163            StringBuilder buffer = new StringBuilder("  \"componentProperties\": {");
2164
2165            boolean first = true;
2166            for (String[] row : selected.values()) {
2167                if (first) {
2168                    first = false;
2169                } else {
2170                    buffer.append(",");
2171                }
2172                buffer.append("\n    ");
2173
2174                String name = row[0];
2175                String kind = row[1];
2176                String group = row[2];
2177                String label = row[3];
2178                String required = row[4];
2179                String type = row[5];
2180                String javaType = row[6];
2181                String deprecated = row[7];
2182                String secret = row[8];
2183                String value = row[9];
2184                String defaultValue = row[10];
2185                String description = row[11];
2186
2187                // add json of the option
2188                buffer.append(StringQuoteHelper.doubleQuote(name)).append(": { ");
2189                CollectionStringBuffer csb = new CollectionStringBuffer();
2190                if (kind != null) {
2191                    csb.append("\"kind\": \"" + kind + "\"");
2192                }
2193                if (group != null) {
2194                    csb.append("\"group\": \"" + group + "\"");
2195                }
2196                if (label != null) {
2197                    csb.append("\"label\": \"" + label + "\"");
2198                }
2199                if (required != null) {
2200                    csb.append("\"required\": \"" + required + "\"");
2201                }
2202                if (type != null) {
2203                    csb.append("\"type\": \"" + type + "\"");
2204                }
2205                if (javaType != null) {
2206                    csb.append("\"javaType\": \"" + javaType + "\"");
2207                }
2208                if (deprecated != null) {
2209                    csb.append("\"deprecated\": \"" + deprecated + "\"");
2210                }
2211                if (secret != null) {
2212                    csb.append("\"secret\": \"" + secret + "\"");
2213                }
2214                if (value != null) {
2215                    csb.append("\"value\": \"" + value + "\"");
2216                }
2217                if (defaultValue != null) {
2218                    csb.append("\"defaultValue\": \"" + defaultValue + "\"");
2219                }
2220                if (description != null) {
2221                    csb.append("\"description\": \"" + description + "\"");
2222                }
2223                if (!csb.isEmpty()) {
2224                    buffer.append(csb.toString());
2225                }
2226                buffer.append(" }");
2227            }
2228            buffer.append("\n  }\n}\n");
2229            // insert the original first part of the json into the start of the buffer
2230            buffer.insert(0, json);
2231            return buffer.toString();
2232        } catch (Exception e) {
2233            // ignore and return empty response
2234            return null;
2235        }
2236    }
2237
2238    // CHECKSTYLE:OFF
2239    public String explainEndpointJson(String uri, boolean includeAllOptions) {
2240        try {
2241            URI u = new URI(uri);
2242            String json = getComponentParameterJsonSchema(u.getScheme());
2243            if (json == null) {
2244                return null;
2245            }
2246            List<Map<String, String>> rows = JsonSchemaHelper.parseJsonSchema("properties", json, true);
2247
2248            // selected rows to use for answer
2249            Map<String, String[]> selected = new LinkedHashMap<>();
2250            Map<String, String[]> uriOptions = new LinkedHashMap<>();
2251
2252            // insert values from uri
2253            Map<String, Object> options = EndpointHelper.endpointProperties(this, uri);
2254
2255            // extract consumer. prefix options
2256            Map<String, Object> consumerOptions = IntrospectionSupport.extractProperties(options, "consumer.");
2257            // and add back again without the consumer. prefix as that json schema omits that
2258            options.putAll(consumerOptions);
2259
2260            for (Map.Entry<String, Object> entry : options.entrySet()) {
2261                String name = entry.getKey();
2262                String value = "";
2263                if (entry.getValue() != null) {
2264                    value = entry.getValue().toString();
2265                }
2266                value = URISupport.sanitizePath(value);
2267                // find type and description from the json schema
2268                String type = null;
2269                String kind = null;
2270                String group = null;
2271                String label = null;
2272                String required = null;
2273                String javaType = null;
2274                String deprecated = null;
2275                String secret = null;
2276                String defaultValue = null;
2277                String description = null;
2278                for (Map<String, String> row : rows) {
2279                    if (name.equals(row.get("name"))) {
2280                        type = row.get("type");
2281                        kind = row.get("kind");
2282                        group = row.get("group");
2283                        label = row.get("label");
2284                        required = row.get("required");
2285                        javaType = row.get("javaType");
2286                        deprecated = row.get("deprecated");
2287                        secret = row.get("secret");
2288                        defaultValue = row.get("defaultValue");
2289                        description = row.get("description");
2290                        break;
2291                    }
2292                }
2293                // remember this option from the uri
2294                uriOptions.put(name, new String[]{name, kind, group, label, required, type, javaType, deprecated, secret, value, defaultValue, description});
2295            }
2296
2297            // include other rows
2298            for (Map<String, String> row : rows) {
2299                String name = row.get("name");
2300                String kind = row.get("kind");
2301                String group = row.get("group");
2302                String label = row.get("label");
2303                String required = row.get("required");
2304                String value = row.get("value");
2305                String defaultValue = row.get("defaultValue");
2306                String type = row.get("type");
2307                String javaType = row.get("javaType");
2308                String deprecated = row.get("deprecated");
2309                String secret = row.get("secret");
2310                value = URISupport.sanitizePath(value);
2311                String description = row.get("description");
2312                boolean isUriOption = uriOptions.containsKey(name);
2313                // always include from uri or path options
2314                if (includeAllOptions || isUriOption || "path".equals(kind)) {
2315                    if (!selected.containsKey(name)) {
2316                        // add as selected row, but take the value from uri options if it was from there
2317                        if (isUriOption) {
2318                            selected.put(name, uriOptions.get(name));
2319                        } else {
2320                            selected.put(name, new String[]{name, kind, group, label, required, type, javaType, deprecated, secret, value, defaultValue, description});
2321                        }
2322                    }
2323                }
2324            }
2325
2326            // skip component properties
2327            json = StringHelper.before(json, "  \"componentProperties\": {");
2328            // and rewrite properties
2329            StringBuilder buffer = new StringBuilder("  \"properties\": {");
2330
2331            boolean first = true;
2332            for (String[] row : selected.values()) {
2333                if (first) {
2334                    first = false;
2335                } else {
2336                    buffer.append(",");
2337                }
2338                buffer.append("\n    ");
2339
2340                String name = row[0];
2341                String kind = row[1];
2342                String group = row[2];
2343                String label = row[3];
2344                String required = row[4];
2345                String type = row[5];
2346                String javaType = row[6];
2347                String deprecated = row[7];
2348                String secret = row[8];
2349                String value = row[9];
2350                String defaultValue = row[10];
2351                String description = row[11];
2352
2353                // add json of the option
2354                buffer.append(StringQuoteHelper.doubleQuote(name)).append(": { ");
2355                CollectionStringBuffer csb = new CollectionStringBuffer();
2356                if (kind != null) {
2357                    csb.append("\"kind\": \"" + kind + "\"");
2358                }
2359                if (group != null) {
2360                    csb.append("\"group\": \"" + group + "\"");
2361                }
2362                if (label != null) {
2363                    csb.append("\"label\": \"" + label + "\"");
2364                }
2365                if (required != null) {
2366                    csb.append("\"required\": \"" + required + "\"");
2367                }
2368                if (type != null) {
2369                    csb.append("\"type\": \"" + type + "\"");
2370                }
2371                if (javaType != null) {
2372                    csb.append("\"javaType\": \"" + javaType + "\"");
2373                }
2374                if (deprecated != null) {
2375                    csb.append("\"deprecated\": \"" + deprecated + "\"");
2376                }
2377                if (secret != null) {
2378                    csb.append("\"secret\": \"" + secret + "\"");
2379                }
2380                if (value != null) {
2381                    csb.append("\"value\": \"" + value + "\"");
2382                }
2383                if (defaultValue != null) {
2384                    csb.append("\"defaultValue\": \"" + defaultValue + "\"");
2385                }
2386                if (description != null) {
2387                    csb.append("\"description\": \"" + description + "\"");
2388                }
2389                if (!csb.isEmpty()) {
2390                    buffer.append(csb.toString());
2391                }
2392                buffer.append(" }");
2393            }
2394            buffer.append("\n  }\n}\n");
2395            // insert the original first part of the json into the start of the buffer
2396            buffer.insert(0, json);
2397            return buffer.toString();
2398        } catch (Exception e) {
2399            // ignore and return empty response
2400            return null;
2401        }
2402    }
2403    // CHECKSTYLE:ON
2404
2405    public String createRouteStaticEndpointJson(String routeId) {
2406        // lets include dynamic as well as we want as much data as possible
2407        return createRouteStaticEndpointJson(routeId, true);
2408    }
2409
2410    public String createRouteStaticEndpointJson(String routeId, boolean includeDynamic) {
2411        List<RouteDefinition> routes = new ArrayList<>();
2412        if (routeId != null) {
2413            RouteDefinition route = getRouteDefinition(routeId);
2414            if (route == null) {
2415                throw new IllegalArgumentException("Route with id " + routeId + " does not exist");
2416            }
2417            routes.add(route);
2418        } else {
2419            routes.addAll(getRouteDefinitions());
2420        }
2421
2422        StringBuilder buffer = new StringBuilder("{\n  \"routes\": {");
2423        boolean firstRoute = true;
2424        for (RouteDefinition route : routes) {
2425            if (!firstRoute) {
2426                buffer.append("\n    },");
2427            } else {
2428                firstRoute = false;
2429            }
2430
2431            String id = route.getId();
2432            buffer.append("\n    \"").append(id).append("\": {");
2433            buffer.append("\n      \"inputs\": [");
2434            // for inputs we do not need to check dynamic as we have the data from the route definition
2435            Set<String> inputs = RouteDefinitionHelper.gatherAllStaticEndpointUris(this, route, true, false);
2436            boolean first = true;
2437            for (String input : inputs) {
2438                if (!first) {
2439                    buffer.append(",");
2440                } else {
2441                    first = false;
2442                }
2443                buffer.append("\n        ");
2444                buffer.append(StringHelper.toJson("uri", input, true));
2445            }
2446            buffer.append("\n      ]");
2447
2448            buffer.append(",");
2449            buffer.append("\n      \"outputs\": [");
2450            Set<String> outputs = RouteDefinitionHelper.gatherAllEndpointUris(this, route, false, true, includeDynamic);
2451            first = true;
2452            for (String output : outputs) {
2453                if (!first) {
2454                    buffer.append(",");
2455                } else {
2456                    first = false;
2457                }
2458                buffer.append("\n        ");
2459                buffer.append(StringHelper.toJson("uri", output, true));
2460            }
2461            buffer.append("\n      ]");
2462        }
2463        if (!firstRoute) {
2464            buffer.append("\n    }");
2465        }
2466        buffer.append("\n  }\n}\n");
2467
2468        return buffer.toString();
2469    }
2470
2471    // Helper methods
2472    // -----------------------------------------------------------------------
2473
2474    public Language resolveLanguage(String language) {
2475        Language answer;
2476        synchronized (languages) {
2477            answer = languages.get(language);
2478
2479            // check if the language is singleton, if so return the shared instance
2480            if (answer instanceof IsSingleton) {
2481                boolean singleton = ((IsSingleton) answer).isSingleton();
2482                if (singleton) {
2483                    return answer;
2484                }
2485            }
2486
2487            // language not known or not singleton, then use resolver
2488            answer = getLanguageResolver().resolveLanguage(language, this);
2489
2490            // inject CamelContext if aware
2491            if (answer != null) {
2492                if (answer instanceof CamelContextAware) {
2493                    ((CamelContextAware) answer).setCamelContext(this);
2494                }
2495                if (answer instanceof Service) {
2496                    try {
2497                        startService((Service) answer);
2498                    } catch (Exception e) {
2499                        throw ObjectHelper.wrapRuntimeCamelException(e);
2500                    }
2501                }
2502
2503                languages.put(language, answer);
2504            }
2505        }
2506
2507        return answer;
2508    }
2509
2510    public String getPropertyPrefixToken() {
2511        PropertiesComponent pc = getPropertiesComponent();
2512
2513        if (pc != null) {
2514            return pc.getPrefixToken();
2515        } else {
2516            return null;
2517        }
2518    }
2519
2520    public String getPropertySuffixToken() {
2521        PropertiesComponent pc = getPropertiesComponent();
2522
2523        if (pc != null) {
2524            return pc.getSuffixToken();
2525        } else {
2526            return null;
2527        }
2528    }
2529
2530    public String resolvePropertyPlaceholders(String text) throws Exception {
2531        // While it is more efficient to only do the lookup if we are sure we need the component,
2532        // with custom tokens, we cannot know if the URI contains a property or not without having
2533        // the component.  We also lose fail-fast behavior for the missing component with this change.
2534        PropertiesComponent pc = getPropertiesComponent();
2535
2536        // Do not parse uris that are designated for the properties component as it will handle that itself
2537        if (text != null && !text.startsWith("properties:")) {
2538            // No component, assume default tokens.
2539            if (pc == null && text.contains(PropertiesComponent.DEFAULT_PREFIX_TOKEN)) {
2540                // lookup existing properties component, or force create a new default component
2541                pc = (PropertiesComponent) CamelContextHelper.lookupPropertiesComponent(this, true);
2542            }
2543
2544            if (pc != null && text.contains(pc.getPrefixToken())) {
2545                // the parser will throw exception if property key was not found
2546                String answer = pc.parseUri(text);
2547                log.debug("Resolved text: {} -> {}", text, answer);
2548                return answer;
2549            }
2550        }
2551
2552        // return original text as is
2553        return text;
2554    }
2555
2556    // Properties
2557    // -----------------------------------------------------------------------
2558
2559    public TypeConverter getTypeConverter() {
2560        if (typeConverter == null) {
2561            synchronized (this) {
2562                // we can synchronize on this as there is only one instance
2563                // of the camel context (its the container)
2564                typeConverter = createTypeConverter();
2565                try {
2566                    // must add service eager and force start it
2567                    addService(typeConverter, true, true);
2568                } catch (Exception e) {
2569                    throw ObjectHelper.wrapRuntimeCamelException(e);
2570                }
2571            }
2572        }
2573        return typeConverter;
2574    }
2575
2576    public void setTypeConverter(TypeConverter typeConverter) {
2577        this.typeConverter = typeConverter;
2578        try {
2579            // must add service eager and force start it
2580            addService(typeConverter, true, true);
2581        } catch (Exception e) {
2582            throw ObjectHelper.wrapRuntimeCamelException(e);
2583        }
2584    }
2585
2586    public TypeConverterRegistry getTypeConverterRegistry() {
2587        if (typeConverterRegistry == null) {
2588            // init type converter as its lazy
2589            if (typeConverter == null) {
2590                getTypeConverter();
2591            }
2592            if (typeConverter instanceof TypeConverterRegistry) {
2593                typeConverterRegistry = (TypeConverterRegistry) typeConverter;
2594            }
2595        }
2596        return typeConverterRegistry;
2597    }
2598
2599    public void setTypeConverterRegistry(TypeConverterRegistry typeConverterRegistry) {
2600        this.typeConverterRegistry = typeConverterRegistry;
2601    }
2602
2603    public Injector getInjector() {
2604        if (injector == null) {
2605            injector = createInjector();
2606        }
2607        return injector;
2608    }
2609
2610    public void setInjector(Injector injector) {
2611        this.injector = injector;
2612    }
2613
2614    public ManagementMBeanAssembler getManagementMBeanAssembler() {
2615        return managementMBeanAssembler;
2616    }
2617
2618    public void setManagementMBeanAssembler(ManagementMBeanAssembler managementMBeanAssembler) {
2619        this.managementMBeanAssembler = managementMBeanAssembler;
2620    }
2621
2622    public ComponentResolver getComponentResolver() {
2623        if (componentResolver == null) {
2624            componentResolver = createComponentResolver();
2625        }
2626        return componentResolver;
2627    }
2628
2629    public void setComponentResolver(ComponentResolver componentResolver) {
2630        this.componentResolver = componentResolver;
2631    }
2632
2633    public LanguageResolver getLanguageResolver() {
2634        if (languageResolver == null) {
2635            languageResolver = createLanguageResolver();
2636        }
2637        return languageResolver;
2638    }
2639
2640    public void setLanguageResolver(LanguageResolver languageResolver) {
2641        this.languageResolver = languageResolver;
2642    }
2643
2644    public boolean isAutoCreateComponents() {
2645        return autoCreateComponents;
2646    }
2647
2648    public void setAutoCreateComponents(boolean autoCreateComponents) {
2649        this.autoCreateComponents = autoCreateComponents;
2650    }
2651
2652    public Registry getRegistry() {
2653        if (registry == null) {
2654            registry = createRegistry();
2655            setRegistry(registry);
2656        }
2657        return registry;
2658    }
2659
2660    public <T> T getRegistry(Class<T> type) {
2661        Registry reg = getRegistry();
2662
2663        // unwrap the property placeholder delegate
2664        if (reg instanceof PropertyPlaceholderDelegateRegistry) {
2665            reg = ((PropertyPlaceholderDelegateRegistry) reg).getRegistry();
2666        }
2667
2668        if (type.isAssignableFrom(reg.getClass())) {
2669            return type.cast(reg);
2670        } else if (reg instanceof CompositeRegistry) {
2671            List<Registry> list = ((CompositeRegistry) reg).getRegistryList();
2672            for (Registry r : list) {
2673                if (type.isAssignableFrom(r.getClass())) {
2674                    return type.cast(r);
2675                }
2676            }
2677        }
2678        return null;
2679    }
2680
2681    /**
2682     * Sets the registry to the given JNDI context
2683     *
2684     * @param jndiContext is the JNDI context to use as the registry
2685     * @see #setRegistry(org.apache.camel.spi.Registry)
2686     */
2687    public void setJndiContext(Context jndiContext) {
2688        setRegistry(new JndiRegistry(jndiContext));
2689    }
2690
2691    public void setRegistry(Registry registry) {
2692        // wrap the registry so we always do property placeholder lookups
2693        if (!(registry instanceof PropertyPlaceholderDelegateRegistry)) {
2694            registry = new PropertyPlaceholderDelegateRegistry(this, registry);
2695        }
2696        this.registry = registry;
2697    }
2698
2699    public List<LifecycleStrategy> getLifecycleStrategies() {
2700        return lifecycleStrategies;
2701    }
2702
2703    public void setLifecycleStrategies(List<LifecycleStrategy> lifecycleStrategies) {
2704        this.lifecycleStrategies = lifecycleStrategies;
2705    }
2706
2707    public void addLifecycleStrategy(LifecycleStrategy lifecycleStrategy) {
2708        this.lifecycleStrategies.add(lifecycleStrategy);
2709    }
2710
2711    public void setupRoutes(boolean done) {
2712        if (done) {
2713            isSetupRoutes.remove();
2714        } else {
2715            isSetupRoutes.set(true);
2716        }
2717    }
2718
2719    public synchronized List<RouteDefinition> getRouteDefinitions() {
2720        return routeDefinitions;
2721    }
2722
2723    public synchronized RouteDefinition getRouteDefinition(String id) {
2724        for (RouteDefinition route : routeDefinitions) {
2725            if (route.idOrCreate(nodeIdFactory).equals(id)) {
2726                return route;
2727            }
2728        }
2729        return null;
2730    }
2731
2732    public synchronized List<RestDefinition> getRestDefinitions() {
2733        return restDefinitions;
2734    }
2735
2736    public void addRestDefinitions(Collection<RestDefinition> restDefinitions) throws Exception {
2737        if (restDefinitions == null || restDefinitions.isEmpty()) {
2738            return;
2739        }
2740
2741        this.restDefinitions.addAll(restDefinitions);
2742    }
2743
2744    public RestConfiguration getRestConfiguration() {
2745        return restConfigurations.get("");
2746    }
2747
2748    public void setRestConfiguration(RestConfiguration restConfiguration) {
2749        restConfigurations.put("", restConfiguration);
2750    }
2751
2752    public Collection<RestConfiguration> getRestConfigurations() {
2753        return restConfigurations.values();
2754    }
2755
2756    public void addRestConfiguration(RestConfiguration restConfiguration) {
2757        restConfigurations.put(restConfiguration.getComponent(), restConfiguration);
2758    }
2759
2760    public RestConfiguration getRestConfiguration(String component, boolean defaultIfNotExist) {
2761        if (component == null) {
2762            component = "";
2763        }
2764        RestConfiguration config = restConfigurations.get(component);
2765        if (config == null && defaultIfNotExist) {
2766            // grab the default configuration
2767            config = getRestConfiguration();
2768            if (config == null || (config.getComponent() != null && !config.getComponent().equals(component))) {
2769                config = new RestConfiguration();
2770                restConfigurations.put(component, config);
2771            }
2772        }
2773        return config;
2774    }
2775
2776    @Override
2777    public ServiceCallConfigurationDefinition getServiceCallConfiguration(String serviceName) {
2778        if (serviceName == null) {
2779            serviceName = "";
2780        }
2781
2782        return serviceCallConfigurations.get(serviceName);
2783    }
2784
2785    @Override
2786    public void setServiceCallConfiguration(ServiceCallConfigurationDefinition configuration) {
2787        serviceCallConfigurations.put("", configuration);
2788    }
2789
2790    @Override
2791    public void setServiceCallConfigurations(List<ServiceCallConfigurationDefinition> configurations) {
2792        if (configurations != null) {
2793            for (ServiceCallConfigurationDefinition configuration : configurations) {
2794                serviceCallConfigurations.put(configuration.getId(), configuration);
2795            }
2796        }
2797    }
2798
2799    @Override
2800    public void addServiceCallConfiguration(String serviceName, ServiceCallConfigurationDefinition configuration) {
2801        serviceCallConfigurations.put(serviceName, configuration);
2802    }
2803
2804    @Override
2805    public HystrixConfigurationDefinition getHystrixConfiguration(String id) {
2806        if (id == null) {
2807            id = "";
2808        }
2809
2810        return hystrixConfigurations.get(id);
2811    }
2812
2813    @Override
2814    public void setHystrixConfiguration(HystrixConfigurationDefinition configuration) {
2815        hystrixConfigurations.put("", configuration);
2816    }
2817
2818    @Override
2819    public void setHystrixConfigurations(List<HystrixConfigurationDefinition> configurations) {
2820        if (configurations != null) {
2821            for (HystrixConfigurationDefinition configuration : configurations) {
2822                hystrixConfigurations.put(configuration.getId(), configuration);
2823            }
2824        }
2825    }
2826
2827    @Override
2828    public void addHystrixConfiguration(String id, HystrixConfigurationDefinition configuration) {
2829        hystrixConfigurations.put(id, configuration);
2830    }
2831
2832    public List<InterceptStrategy> getInterceptStrategies() {
2833        return interceptStrategies;
2834    }
2835
2836    public void setInterceptStrategies(List<InterceptStrategy> interceptStrategies) {
2837        this.interceptStrategies = interceptStrategies;
2838    }
2839
2840    public void addInterceptStrategy(InterceptStrategy interceptStrategy) {
2841        getInterceptStrategies().add(interceptStrategy);
2842
2843        // for backwards compatible or if user add them here instead of the setXXX methods
2844
2845        if (interceptStrategy instanceof Tracer) {
2846            setTracing(true);
2847        } else if (interceptStrategy instanceof HandleFault) {
2848            setHandleFault(true);
2849        } else if (interceptStrategy instanceof StreamCaching) {
2850            setStreamCaching(true);
2851        } else if (interceptStrategy instanceof Delayer) {
2852            setDelayer(((Delayer)interceptStrategy).getDelay());
2853        }
2854    }
2855
2856    public List<RoutePolicyFactory> getRoutePolicyFactories() {
2857        return routePolicyFactories;
2858    }
2859
2860    public void setRoutePolicyFactories(List<RoutePolicyFactory> routePolicyFactories) {
2861        this.routePolicyFactories = routePolicyFactories;
2862    }
2863
2864    public void addRoutePolicyFactory(RoutePolicyFactory routePolicyFactory) {
2865        getRoutePolicyFactories().add(routePolicyFactory);
2866    }
2867
2868    public Set<LogListener> getLogListeners() {
2869        return logListeners;
2870    }
2871
2872    public void addLogListener(LogListener listener) {
2873        logListeners.add(listener);
2874    }
2875
2876    public void setStreamCaching(Boolean cache) {
2877        this.streamCache = cache;
2878    }
2879
2880    public Boolean isStreamCaching() {
2881        return streamCache;
2882    }
2883
2884    public void setTracing(Boolean tracing) {
2885        this.trace = tracing;
2886    }
2887
2888    public Boolean isTracing() {
2889        return trace;
2890    }
2891
2892    public Boolean isMessageHistory() {
2893        return messageHistory;
2894    }
2895
2896    public void setMessageHistory(Boolean messageHistory) {
2897        this.messageHistory = messageHistory;
2898    }
2899
2900    public void setLogMask(Boolean logMask) {
2901        this.logMask = logMask;
2902    }
2903
2904    public Boolean isLogMask() {
2905        return logMask != null && logMask;
2906    }
2907
2908    public Boolean isLogExhaustedMessageBody() {
2909        return logExhaustedMessageBody;
2910    }
2911
2912    public void setLogExhaustedMessageBody(Boolean logExhaustedMessageBody) {
2913        this.logExhaustedMessageBody = logExhaustedMessageBody;
2914    }
2915
2916    public Boolean isHandleFault() {
2917        return handleFault;
2918    }
2919
2920    public void setHandleFault(Boolean handleFault) {
2921        this.handleFault = handleFault;
2922    }
2923
2924    public Long getDelayer() {
2925        return delay;
2926    }
2927
2928    public void setDelayer(Long delay) {
2929        this.delay = delay;
2930    }
2931
2932    public ProducerTemplate createProducerTemplate() {
2933        int size = CamelContextHelper.getMaximumCachePoolSize(this);
2934        return createProducerTemplate(size);
2935    }
2936
2937    public ProducerTemplate createProducerTemplate(int maximumCacheSize) {
2938        DefaultProducerTemplate answer = new DefaultProducerTemplate(this);
2939        answer.setMaximumCacheSize(maximumCacheSize);
2940        // start it so its ready to use
2941        try {
2942            startService(answer);
2943        } catch (Exception e) {
2944            throw ObjectHelper.wrapRuntimeCamelException(e);
2945        }
2946        return answer;
2947    }
2948
2949    public FluentProducerTemplate createFluentProducerTemplate() {
2950        int size = CamelContextHelper.getMaximumCachePoolSize(this);
2951        return createFluentProducerTemplate(size);
2952    }
2953
2954    public FluentProducerTemplate createFluentProducerTemplate(int maximumCacheSize) {
2955        DefaultFluentProducerTemplate answer = new DefaultFluentProducerTemplate(this);
2956        answer.setMaximumCacheSize(maximumCacheSize);
2957        // start it so its ready to use
2958        try {
2959            startService(answer);
2960        } catch (Exception e) {
2961            throw ObjectHelper.wrapRuntimeCamelException(e);
2962        }
2963        return answer;
2964    }
2965
2966    public ConsumerTemplate createConsumerTemplate() {
2967        int size = CamelContextHelper.getMaximumCachePoolSize(this);
2968        return createConsumerTemplate(size);
2969    }
2970
2971    public ConsumerTemplate createConsumerTemplate(int maximumCacheSize) {
2972        DefaultConsumerTemplate answer = new DefaultConsumerTemplate(this);
2973        answer.setMaximumCacheSize(maximumCacheSize);
2974        // start it so its ready to use
2975        try {
2976            startService(answer);
2977        } catch (Exception e) {
2978            throw ObjectHelper.wrapRuntimeCamelException(e);
2979        }
2980        return answer;
2981    }
2982
2983    public ErrorHandlerBuilder getErrorHandlerBuilder() {
2984        return (ErrorHandlerBuilder)errorHandlerBuilder;
2985    }
2986
2987    public void setErrorHandlerBuilder(ErrorHandlerFactory errorHandlerBuilder) {
2988        this.errorHandlerBuilder = errorHandlerBuilder;
2989    }
2990
2991    public ScheduledExecutorService getErrorHandlerExecutorService() {
2992        synchronized (errorHandlerExecutorServiceLock) {
2993            if (errorHandlerExecutorService == null) {
2994                // setup default thread pool for error handler
2995                errorHandlerExecutorService = getExecutorServiceManager().newDefaultScheduledThreadPool("ErrorHandlerRedeliveryThreadPool", "ErrorHandlerRedeliveryTask");
2996            }
2997        }
2998        return errorHandlerExecutorService;
2999    }
3000
3001    public void setProducerServicePool(ServicePool<Endpoint, Producer> producerServicePool) {
3002        this.producerServicePool = producerServicePool;
3003    }
3004
3005    public ServicePool<Endpoint, Producer> getProducerServicePool() {
3006        return producerServicePool;
3007    }
3008
3009    public ServicePool<Endpoint, PollingConsumer> getPollingConsumerServicePool() {
3010        return pollingConsumerServicePool;
3011    }
3012
3013    public void setPollingConsumerServicePool(ServicePool<Endpoint, PollingConsumer> pollingConsumerServicePool) {
3014        this.pollingConsumerServicePool = pollingConsumerServicePool;
3015    }
3016
3017    public UnitOfWorkFactory getUnitOfWorkFactory() {
3018        return unitOfWorkFactory;
3019    }
3020
3021    public void setUnitOfWorkFactory(UnitOfWorkFactory unitOfWorkFactory) {
3022        this.unitOfWorkFactory = unitOfWorkFactory;
3023    }
3024
3025    public RuntimeEndpointRegistry getRuntimeEndpointRegistry() {
3026        return runtimeEndpointRegistry;
3027    }
3028
3029    public void setRuntimeEndpointRegistry(RuntimeEndpointRegistry runtimeEndpointRegistry) {
3030        this.runtimeEndpointRegistry = runtimeEndpointRegistry;
3031    }
3032
3033    public String getUptime() {
3034        long delta = getUptimeMillis();
3035        if (delta == 0) {
3036            return "";
3037        }
3038        return TimeUtils.printDuration(delta);
3039    }
3040
3041    public long getUptimeMillis() {
3042        if (startDate == null) {
3043            return 0;
3044        }
3045        return new Date().getTime() - startDate.getTime();
3046    }
3047
3048    @Override
3049    protected void doSuspend() throws Exception {
3050        EventHelper.notifyCamelContextSuspending(this);
3051
3052        log.info("Apache Camel {} (CamelContext: {}) is suspending", getVersion(), getName());
3053        StopWatch watch = new StopWatch();
3054
3055        // update list of started routes to be suspended
3056        // because we only want to suspend started routes
3057        // (so when we resume we only resume the routes which actually was suspended)
3058        for (Map.Entry<String, RouteService> entry : getRouteServices().entrySet()) {
3059            if (entry.getValue().getStatus().isStarted()) {
3060                suspendedRouteServices.put(entry.getKey(), entry.getValue());
3061            }
3062        }
3063
3064        // assemble list of startup ordering so routes can be shutdown accordingly
3065        List<RouteStartupOrder> orders = new ArrayList<>();
3066        for (Map.Entry<String, RouteService> entry : suspendedRouteServices.entrySet()) {
3067            Route route = entry.getValue().getRoutes().iterator().next();
3068            Integer order = entry.getValue().getRouteDefinition().getStartupOrder();
3069            if (order == null) {
3070                order = defaultRouteStartupOrder++;
3071            }
3072            orders.add(new DefaultRouteStartupOrder(order, route, entry.getValue()));
3073        }
3074
3075        // suspend routes using the shutdown strategy so it can shutdown in correct order
3076        // routes which doesn't support suspension will be stopped instead
3077        getShutdownStrategy().suspend(this, orders);
3078
3079        // mark the route services as suspended or stopped
3080        for (RouteService service : suspendedRouteServices.values()) {
3081            if (routeSupportsSuspension(service.getId())) {
3082                service.suspend();
3083            } else {
3084                service.stop();
3085            }
3086        }
3087
3088        watch.stop();
3089        if (log.isInfoEnabled()) {
3090            log.info("Apache Camel {} (CamelContext: {}) is suspended in {}", getVersion(), getName(), TimeUtils.printDuration(watch.taken()));
3091        }
3092
3093        EventHelper.notifyCamelContextSuspended(this);
3094    }
3095
3096    @Override
3097    protected void doResume() throws Exception {
3098        try {
3099            EventHelper.notifyCamelContextResuming(this);
3100
3101            log.info("Apache Camel {} (CamelContext: {}) is resuming", getVersion(), getName());
3102            StopWatch watch = new StopWatch();
3103
3104            // start the suspended routes (do not check for route clashes, and indicate)
3105            doStartOrResumeRoutes(suspendedRouteServices, false, true, true, false);
3106
3107            // mark the route services as resumed (will be marked as started) as well
3108            for (RouteService service : suspendedRouteServices.values()) {
3109                if (routeSupportsSuspension(service.getId())) {
3110                    service.resume();
3111                } else {
3112                    service.start();
3113                }
3114            }
3115
3116            if (log.isInfoEnabled()) {
3117                log.info("Resumed {} routes", suspendedRouteServices.size());
3118                log.info("Apache Camel {} (CamelContext: {}) resumed in {}", getVersion(), getName(), TimeUtils.printDuration(watch.taken()));
3119            }
3120
3121            // and clear the list as they have been resumed
3122            suspendedRouteServices.clear();
3123
3124            EventHelper.notifyCamelContextResumed(this);
3125        } catch (Exception e) {
3126            EventHelper.notifyCamelContextResumeFailed(this, e);
3127            throw e;
3128        }
3129    }
3130
3131    @Override
3132    public void start() throws Exception {
3133        try (MDCHelper mdcHelper = new MDCHelper()) {
3134            vetoStated.set(false);
3135            startDate = new Date();
3136            stopWatch.restart();
3137            log.info("Apache Camel {} (CamelContext: {}) is starting", getVersion(), getName());
3138
3139            // Note: This is done on context start as we want to avoid doing it during object construction
3140            // where we could be dealing with CDI proxied camel contexts which may never be started (CAMEL-9657)
3141            // [TODO] Remove in 3.0
3142            Container.Instance.manage(this);
3143
3144            // Start the route controller
3145            ServiceHelper.startServices(this.routeController);
3146
3147            doNotStartRoutesOnFirstStart = !firstStartDone && !isAutoStartup();
3148
3149            // if the context was configured with auto startup = false, and we are already started,
3150            // then we may need to start the routes on the 2nd start call
3151            if (firstStartDone && !isAutoStartup() && isStarted()) {
3152                // invoke this logic to warm up the routes and if possible also start the routes
3153                doStartOrResumeRoutes(routeServices, true, true, false, true);
3154            }
3155
3156            // super will invoke doStart which will prepare internal services and start routes etc.
3157            try {
3158                firstStartDone = true;
3159                super.start();
3160            } catch (VetoCamelContextStartException e) {
3161                // mark we veto against starting Camel
3162                vetoStated.set(true);
3163                if (e.isRethrowException()) {
3164                    throw e;
3165                } else {
3166                    log.info("CamelContext ({}) vetoed to not start due {}", getName(), e.getMessage());
3167                    // swallow exception and change state of this camel context to stopped
3168                    stop();
3169                    return;
3170                }
3171            }
3172
3173            if (log.isInfoEnabled()) {
3174                // count how many routes are actually started
3175                int started = 0;
3176                for (Route route : getRoutes()) {
3177                    ServiceStatus status = getRouteStatus(route.getId());
3178                    if (status != null && status.isStarted()) {
3179                        started++;
3180                    }
3181                }
3182
3183                final Collection<Route> controlledRoutes = getRouteController().getControlledRoutes();
3184                if (controlledRoutes.isEmpty()) {
3185                    log.info("Total {} routes, of which {} are started",
3186                        getRoutes().size(),
3187                        started);
3188                } else {
3189                    log.info("Total {} routes, of which {} are started, and {} are managed by RouteController: {}",
3190                        getRoutes().size(),
3191                        started,
3192                        controlledRoutes.size(),
3193                        getRouteController().getClass().getName()
3194                    );
3195                }
3196                log.info("Apache Camel {} (CamelContext: {}) started in {}", getVersion(), getName(), TimeUtils.printDuration(stopWatch.taken()));
3197            }
3198
3199            // okay the routes has been started so emit event that CamelContext has started (here at the end)
3200            EventHelper.notifyCamelContextStarted(this);
3201
3202            // now call the startup listeners where the routes has been started
3203            for (StartupListener startup : startupListeners) {
3204                if (startup instanceof ExtendedStartupListener) {
3205                    ((ExtendedStartupListener) startup).onCamelContextFullyStarted(this, isStarted());
3206                }
3207            }
3208        }
3209    }
3210
3211    @Override
3212    public void stop() throws Exception {
3213        try (MDCHelper mdcHelper = new MDCHelper()) {
3214            super.stop();
3215        }
3216    }
3217
3218    @Override
3219    public void suspend() throws Exception {
3220        try (MDCHelper mdcHelper = new MDCHelper()) {
3221            super.suspend();
3222        }
3223    }
3224
3225    @Override
3226    public void resume() throws Exception {
3227        try (MDCHelper mdcHelper = new MDCHelper()) {
3228            super.resume();
3229        }
3230    }
3231
3232    @Override
3233    public void shutdown() throws Exception {
3234        try (MDCHelper mdcHelper = new MDCHelper()) {
3235            super.shutdown();
3236        }
3237    }
3238
3239    // Implementation methods
3240    // -----------------------------------------------------------------------
3241
3242    protected synchronized void doStart() throws Exception {
3243        doWithDefinedClassLoader(new Callable<Void>() {
3244            @Override
3245            public Void call() throws Exception {
3246                try {
3247                    doStartCamel();
3248                    return null;
3249                } catch (Exception e) {
3250                    // fire event that we failed to start
3251                    EventHelper.notifyCamelContextStartupFailed(DefaultCamelContext.this, e);
3252                    // rethrow cause
3253                    throw e;
3254                }
3255            }
3256        });
3257    }
3258
3259    private <T> T doWithDefinedClassLoader(Callable<T> callable) throws Exception {
3260        ClassLoader tccl = Thread.currentThread().getContextClassLoader();
3261        try {
3262            // Using the ApplicationClassLoader as the default for TCCL
3263            if (applicationContextClassLoader != null) {
3264                Thread.currentThread().setContextClassLoader(applicationContextClassLoader);
3265            }
3266            return callable.call();
3267        } finally {
3268            Thread.currentThread().setContextClassLoader(tccl);
3269        }
3270    }
3271
3272    protected void doStartCamel() throws Exception {
3273
3274        // custom properties may use property placeholders so resolve those early on
3275        if (globalOptions != null && !globalOptions.isEmpty()) {
3276            for (Map.Entry<String, String> entry : globalOptions.entrySet()) {
3277                String key = entry.getKey();
3278                String value = entry.getValue();
3279                if (value != null) {
3280                    String replaced = resolvePropertyPlaceholders(value);
3281                    if (!value.equals(replaced)) {
3282                        if (log.isDebugEnabled()) {
3283                            log.debug("Camel property with key {} replaced value from {} -> {}", key, value, replaced);
3284                        }
3285                        entry.setValue(replaced);
3286                    }
3287                }
3288            }
3289        }
3290
3291        if (classResolver instanceof CamelContextAware) {
3292            ((CamelContextAware) classResolver).setCamelContext(this);
3293        }
3294
3295        if (log.isDebugEnabled()) {
3296            log.debug("Using ClassResolver={}, PackageScanClassResolver={}, ApplicationContextClassLoader={}, RouteController={}",
3297                getClassResolver(), getPackageScanClassResolver(), getApplicationContextClassLoader(), getRouteController());
3298        }
3299
3300        if (isStreamCaching()) {
3301            log.info("StreamCaching is enabled on CamelContext: {}", getName());
3302        }
3303
3304        if (isTracing()) {
3305            // tracing is added in the DefaultChannel so we can enable it on the fly
3306            log.info("Tracing is enabled on CamelContext: {}", getName());
3307        }
3308
3309        if (isUseMDCLogging()) {
3310            // log if MDC has been enabled
3311            log.info("MDC logging is enabled on CamelContext: {}", getName());
3312        }
3313
3314        if (isHandleFault()) {
3315            // only add a new handle fault if not already configured
3316            if (HandleFault.getHandleFault(this) == null) {
3317                log.info("HandleFault is enabled on CamelContext: {}", getName());
3318                addInterceptStrategy(new HandleFault());
3319            }
3320        }
3321
3322        if (getDelayer() != null && getDelayer() > 0) {
3323            log.info("Delayer is enabled with: {} ms. on CamelContext: {}", getDelayer(), getName());
3324        }
3325
3326        // register debugger
3327        if (getDebugger() != null) {
3328            log.info("Debugger: {} is enabled on CamelContext: {}", getDebugger(), getName());
3329            // register this camel context on the debugger
3330            getDebugger().setCamelContext(this);
3331            startService(getDebugger());
3332            addInterceptStrategy(new Debug(getDebugger()));
3333        }
3334
3335        // start management strategy before lifecycles are started
3336        ManagementStrategy managementStrategy = getManagementStrategy();
3337        // inject CamelContext if aware
3338        if (managementStrategy instanceof CamelContextAware) {
3339            ((CamelContextAware) managementStrategy).setCamelContext(this);
3340        }
3341        ServiceHelper.startService(managementStrategy);
3342
3343        // start lifecycle strategies
3344        ServiceHelper.startServices(lifecycleStrategies);
3345        Iterator<LifecycleStrategy> it = lifecycleStrategies.iterator();
3346        while (it.hasNext()) {
3347            LifecycleStrategy strategy = it.next();
3348            try {
3349                strategy.onContextStart(this);
3350            } catch (VetoCamelContextStartException e) {
3351                // okay we should not start Camel since it was vetoed
3352                log.warn("Lifecycle strategy vetoed starting CamelContext ({}) due: {}", getName(), e.getMessage());
3353                throw e;
3354            } catch (Exception e) {
3355                log.warn("Lifecycle strategy " + strategy + " failed starting CamelContext ({}) due: {}", getName(), e.getMessage());
3356                throw e;
3357            }
3358        }
3359
3360        // start notifiers as services
3361        for (EventNotifier notifier : getManagementStrategy().getEventNotifiers()) {
3362            if (notifier instanceof Service) {
3363                Service service = (Service) notifier;
3364                for (LifecycleStrategy strategy : lifecycleStrategies) {
3365                    strategy.onServiceAdd(this, service, null);
3366                }
3367            }
3368            if (notifier instanceof Service) {
3369                startService((Service)notifier);
3370            }
3371        }
3372
3373        // must let some bootstrap service be started before we can notify the starting event
3374        EventHelper.notifyCamelContextStarting(this);
3375
3376        forceLazyInitialization();
3377
3378        // re-create endpoint registry as the cache size limit may be set after the constructor of this instance was called.
3379        // and we needed to create endpoints up-front as it may be accessed before this context is started
3380        endpoints = createEndpointRegistry(endpoints);
3381        // add this as service and force pre-start them
3382        addService(endpoints, true, true);
3383        // special for executorServiceManager as want to stop it manually so false in stopOnShutdown
3384        addService(executorServiceManager, false, true);
3385        addService(producerServicePool, true, true);
3386        addService(pollingConsumerServicePool, true, true);
3387        addService(inflightRepository, true, true);
3388        addService(asyncProcessorAwaitManager, true, true);
3389        addService(shutdownStrategy, true, true);
3390        addService(packageScanClassResolver, true, true);
3391        addService(restRegistry, true, true);
3392        addService(messageHistoryFactory, true, true);
3393        addService(runtimeCamelCatalog, true, true);
3394        if (reloadStrategy != null) {
3395            log.info("Using ReloadStrategy: {}", reloadStrategy);
3396            addService(reloadStrategy, true, true);
3397        }
3398
3399        // Initialize declarative transformer/validator registry
3400        transformerRegistry = createTransformerRegistry(transformers);
3401        addService(transformerRegistry, true, true);
3402        validatorRegistry = createValidatorRegistry(validators);
3403        addService(validatorRegistry, true, true);
3404
3405        // optimised to not include runtimeEndpointRegistry unlesstartServices its enabled or JMX statistics is in extended mode
3406        if (runtimeEndpointRegistry == null && getManagementStrategy() != null && getManagementStrategy().getManagementAgent() != null) {
3407            Boolean isEnabled = getManagementStrategy().getManagementAgent().getEndpointRuntimeStatisticsEnabled();
3408            boolean isExtended = getManagementStrategy().getManagementAgent().getStatisticsLevel().isExtended();
3409            // extended mode is either if we use Extended statistics level or the option is explicit enabled
3410            boolean extended = isExtended || isEnabled != null && isEnabled;
3411            if (extended) {
3412                runtimeEndpointRegistry = new DefaultRuntimeEndpointRegistry();
3413            }
3414        }
3415        if (runtimeEndpointRegistry != null) {
3416            if (runtimeEndpointRegistry instanceof EventNotifier) {
3417                getManagementStrategy().addEventNotifier((EventNotifier) runtimeEndpointRegistry);
3418            }
3419            addService(runtimeEndpointRegistry, true, true);
3420        }
3421
3422        // eager lookup any configured properties component to avoid subsequent lookup attempts which may impact performance
3423        // due we use properties component for property placeholder resolution at runtime
3424        Component existing = CamelContextHelper.lookupPropertiesComponent(this, false);
3425        if (existing != null) {
3426            // store reference to the existing properties component
3427            if (existing instanceof PropertiesComponent) {
3428                propertiesComponent = (PropertiesComponent) existing;
3429            } else {
3430                // properties component must be expected type
3431                throw new IllegalArgumentException("Found properties component of type: " + existing.getClass() + " instead of expected: " + PropertiesComponent.class);
3432            }
3433        }
3434
3435        // start components
3436        startServices(components.values());
3437
3438        // start the route definitions before the routes is started
3439        startRouteDefinitions(routeDefinitions);
3440
3441        // is there any stream caching enabled then log an info about this and its limit of spooling to disk, so people is aware of this
3442        boolean streamCachingInUse = isStreamCaching();
3443        if (!streamCachingInUse) {
3444            for (RouteDefinition route : routeDefinitions) {
3445                Boolean routeCache = CamelContextHelper.parseBoolean(this, route.getStreamCache());
3446                if (routeCache != null && routeCache) {
3447                    streamCachingInUse = true;
3448                    break;
3449                }
3450            }
3451        }
3452
3453        if (isUseDataType()) {
3454            // log if DataType has been enabled
3455            log.info("Message DataType is enabled on CamelContext: {}", getName());
3456        }
3457
3458        if (streamCachingInUse) {
3459            // stream caching is in use so enable the strategy
3460            getStreamCachingStrategy().setEnabled(true);
3461            addService(getStreamCachingStrategy(), true, true);
3462        } else {
3463            // log if stream caching is not in use as this can help people to enable it if they use streams
3464            log.info("StreamCaching is not in use. If using streams then its recommended to enable stream caching."
3465                    + " See more details at http://camel.apache.org/stream-caching.html");
3466        }
3467
3468        if (isAllowUseOriginalMessage()) {
3469            log.debug("AllowUseOriginalMessage enabled because UseOriginalMessage is in use");
3470        }
3471
3472        // use resolver to find the headers map factory to be used, if we are using the default
3473        if (headersMapFactory instanceof DefaultHeadersMapFactory) {
3474            headersMapFactory = new HeadersMapFactoryResolver().resolve(this);
3475        }
3476
3477        log.debug("Using HeadersMapFactory: {}", headersMapFactory);
3478        if (!headersMapFactory.isCaseInsensitive()) {
3479            log.info("HeadersMapFactory: {} is case-sensitive which can cause problems for protocols such as HTTP based, which rely on case-insensitive headers.", getHeadersMapFactory());
3480        }
3481
3482        // start routes
3483        if (doNotStartRoutesOnFirstStart) {
3484            log.debug("Skip starting routes as CamelContext has been configured with autoStartup=false");
3485        }
3486
3487        // invoke this logic to warmup the routes and if possible also start the routes
3488        doStartOrResumeRoutes(routeServices, true, !doNotStartRoutesOnFirstStart, false, true);
3489
3490        // starting will continue in the start method
3491    }
3492
3493    protected synchronized void doStop() throws Exception {
3494        stopWatch.restart();
3495        log.info("Apache Camel {} (CamelContext: {}) is shutting down", getVersion(), getName());
3496        EventHelper.notifyCamelContextStopping(this);
3497        
3498        // Stop the route controller
3499        ServiceHelper.stopAndShutdownService(this.routeController);
3500
3501        // stop route inputs in the same order as they was started so we stop the very first inputs first
3502        try {
3503            // force shutting down routes as they may otherwise cause shutdown to hang
3504            shutdownStrategy.shutdownForced(this, getRouteStartupOrder());
3505        } catch (Throwable e) {
3506            log.warn("Error occurred while shutting down routes. This exception will be ignored.", e);
3507        }
3508
3509        // shutdown await manager to trigger interrupt of blocked threads to attempt to free these threads graceful
3510        shutdownServices(asyncProcessorAwaitManager);
3511
3512        // we ned also to include routes which failed to start to ensure all resources get stopped when stopping Camel
3513        for (RouteService routeService : routeServices.values()) {
3514            boolean found = routeStartupOrder.stream().anyMatch(o -> o.getRoute().getId().equals(routeService.getId()));
3515            if (!found) {
3516                log.debug("Route: {} which failed to startup will be stopped", routeService.getId());
3517                routeStartupOrder.add(doPrepareRouteToBeStarted(routeService));
3518            }
3519        }
3520        routeStartupOrder.sort(Comparator.comparingInt(RouteStartupOrder::getStartupOrder).reversed());
3521        List<RouteService> list = new ArrayList<>();
3522        for (RouteStartupOrder startupOrder : routeStartupOrder) {
3523            DefaultRouteStartupOrder order = (DefaultRouteStartupOrder) startupOrder;
3524            RouteService routeService = order.getRouteService();
3525            list.add(routeService);
3526        }
3527        shutdownServices(list, false);
3528        // do not clear route services or startup listeners as we can start Camel again and get the route back as before
3529        routeStartupOrder.clear();
3530
3531        // but clear any suspend routes
3532        suspendedRouteServices.clear();
3533
3534        // stop consumers from the services to close first, such as POJO consumer (eg @Consumer)
3535        // which we need to stop after the routes, as a POJO consumer is essentially a route also
3536        for (Service service : servicesToStop) {
3537            if (service instanceof Consumer) {
3538                shutdownServices(service);
3539            }
3540        }
3541
3542        // the stop order is important
3543
3544        // shutdown default error handler thread pool
3545        if (errorHandlerExecutorService != null) {
3546            // force shutting down the thread pool
3547            getExecutorServiceManager().shutdownNow(errorHandlerExecutorService);
3548            errorHandlerExecutorService = null;
3549        }
3550
3551        // shutdown debugger
3552        ServiceHelper.stopAndShutdownService(getDebugger());
3553
3554        shutdownServices(endpoints.values());
3555        endpoints.clear();
3556
3557        shutdownServices(components.values());
3558        components.clear();
3559
3560        shutdownServices(languages.values());
3561        languages.clear();
3562
3563        try {
3564            for (LifecycleStrategy strategy : lifecycleStrategies) {
3565                strategy.onContextStop(this);
3566            }
3567        } catch (Throwable e) {
3568            log.warn("Error occurred while stopping lifecycle strategies. This exception will be ignored.", e);
3569        }
3570
3571        // shutdown services as late as possible
3572        shutdownServices(servicesToStop);
3573        servicesToStop.clear();
3574
3575        // must notify that we are stopped before stopping the management strategy
3576        EventHelper.notifyCamelContextStopped(this);
3577
3578        // stop the notifier service
3579        for (EventNotifier notifier : getManagementStrategy().getEventNotifiers()) {
3580            shutdownServices(notifier);
3581        }
3582
3583        // shutdown executor service and management as the last one
3584        shutdownServices(executorServiceManager);
3585        shutdownServices(managementStrategy);
3586        shutdownServices(managementMBeanAssembler);
3587        shutdownServices(lifecycleStrategies);
3588        // do not clear lifecycleStrategies as we can start Camel again and get the route back as before
3589
3590        // stop the lazy created so they can be re-created on restart
3591        forceStopLazyInitialization();
3592
3593        // stop to clear introspection cache
3594        IntrospectionSupport.stop();
3595
3596        if (log.isInfoEnabled()) {
3597            log.info("Apache Camel " + getVersion() + " (CamelContext: " + getName() + ") uptime {}", getUptime());
3598            log.info("Apache Camel {} (CamelContext: {}) is shutdown in {}", getVersion(), getName(), TimeUtils.printDuration(stopWatch.taken()));
3599        }
3600
3601        // and clear start date
3602        startDate = null;
3603
3604        // [TODO] Remove in 3.0
3605        Container.Instance.unmanage(this);
3606    }
3607
3608    /**
3609     * Starts or resumes the routes
3610     *
3611     * @param routeServices  the routes to start (will only start a route if its not already started)
3612     * @param checkClash     whether to check for startup ordering clash
3613     * @param startConsumer  whether the route consumer should be started. Can be used to warmup the route without starting the consumer.
3614     * @param resumeConsumer whether the route consumer should be resumed.
3615     * @param addingRoutes   whether we are adding new routes
3616     * @throws Exception is thrown if error starting routes
3617     */
3618    protected void doStartOrResumeRoutes(Map<String, RouteService> routeServices, boolean checkClash,
3619                                         boolean startConsumer, boolean resumeConsumer, boolean addingRoutes) throws Exception {
3620        isStartingRoutes.set(true);
3621        try {
3622            // filter out already started routes
3623            Map<String, RouteService> filtered = new LinkedHashMap<>();
3624            for (Map.Entry<String, RouteService> entry : routeServices.entrySet()) {
3625                boolean startable = false;
3626
3627                Consumer consumer = entry.getValue().getRoutes().iterator().next().getConsumer();
3628                if (consumer instanceof SuspendableService) {
3629                    // consumer could be suspended, which is not reflected in the RouteService status
3630                    startable = ((SuspendableService) consumer).isSuspended();
3631                }
3632
3633                if (!startable && consumer instanceof StatefulService) {
3634                    // consumer could be stopped, which is not reflected in the RouteService status
3635                    startable = ((StatefulService) consumer).getStatus().isStartable();
3636                } else if (!startable) {
3637                    // no consumer so use state from route service
3638                    startable = entry.getValue().getStatus().isStartable();
3639                }
3640
3641                if (startable) {
3642                    filtered.put(entry.getKey(), entry.getValue());
3643                }
3644            }
3645
3646            // the context is in last phase of staring, so lets start the routes
3647            safelyStartRouteServices(checkClash, startConsumer, resumeConsumer, addingRoutes, filtered.values());
3648
3649        } finally {
3650            isStartingRoutes.remove();
3651        }
3652    }
3653
3654    protected boolean routeSupportsSuspension(String routeId) {
3655        RouteService routeService = routeServices.get(routeId);
3656        if (routeService != null) {
3657            return routeService.getRoutes().iterator().next().supportsSuspension();
3658        }
3659        return false;
3660    }
3661
3662    private void shutdownServices(Object service) {
3663        // do not rethrow exception as we want to keep shutting down in case of problems
3664
3665        // allow us to do custom work before delegating to service helper
3666        try {
3667            if (service instanceof Service) {
3668                ServiceHelper.stopAndShutdownService(service);
3669            } else if (service instanceof Collection) {
3670                ServiceHelper.stopAndShutdownServices((Collection<?>)service);
3671            }
3672        } catch (Throwable e) {
3673            log.warn("Error occurred while shutting down service: " + service + ". This exception will be ignored.", e);
3674            // fire event
3675            EventHelper.notifyServiceStopFailure(this, service, e);
3676        }
3677    }
3678
3679    private void shutdownServices(Collection<?> services) {
3680        // reverse stopping by default
3681        shutdownServices(services, true);
3682    }
3683
3684    private void shutdownServices(Collection<?> services, boolean reverse) {
3685        Collection<?> list = services;
3686        if (reverse) {
3687            List<Object> reverseList = new ArrayList<>(services);
3688            Collections.reverse(reverseList);
3689            list = reverseList;
3690        }
3691
3692        for (Object service : list) {
3693            shutdownServices(service);
3694        }
3695    }
3696
3697    private void startService(Service service) throws Exception {
3698        // and register startup aware so they can be notified when
3699        // camel context has been started
3700        if (service instanceof StartupListener) {
3701            StartupListener listener = (StartupListener) service;
3702            addStartupListener(listener);
3703        }
3704
3705        if (service instanceof CamelContextAware) {
3706            CamelContextAware aware = (CamelContextAware) service;
3707            aware.setCamelContext(this);
3708        }
3709
3710        service.start();
3711    }
3712
3713    private void startServices(Collection<?> services) throws Exception {
3714        for (Object element : services) {
3715            if (element instanceof Service) {
3716                startService((Service)element);
3717            }
3718        }
3719    }
3720
3721    private void stopServices(Object service) throws Exception {
3722        // allow us to do custom work before delegating to service helper
3723        try {
3724            ServiceHelper.stopService(service);
3725        } catch (Exception e) {
3726            // fire event
3727            EventHelper.notifyServiceStopFailure(this, service, e);
3728            // rethrow to signal error with stopping
3729            throw e;
3730        }
3731    }
3732
3733    protected void startRouteDefinitions(Collection<RouteDefinition> list) throws Exception {
3734        if (list != null) {
3735            for (RouteDefinition route : list) {
3736                startRoute(route);
3737            }
3738        }
3739    }
3740
3741    /**
3742     * Starts the given route service
3743     */
3744    protected synchronized void startRouteService(RouteService routeService, boolean addingRoutes) throws Exception {
3745        // we may already be starting routes so remember this, so we can unset accordingly in finally block
3746        boolean alreadyStartingRoutes = isStartingRoutes();
3747        if (!alreadyStartingRoutes) {
3748            isStartingRoutes.set(true);
3749        }
3750
3751        try {
3752            // the route service could have been suspended, and if so then resume it instead
3753            if (routeService.getStatus().isSuspended()) {
3754                resumeRouteService(routeService);
3755            } else {
3756                // start the route service
3757                routeServices.put(routeService.getId(), routeService);
3758                if (shouldStartRoutes()) {
3759                    // this method will log the routes being started
3760                    safelyStartRouteServices(true, true, true, false, addingRoutes, routeService);
3761                    // start route services if it was configured to auto startup and we are not adding routes
3762                    boolean autoStartup = routeService.getRouteDefinition().isAutoStartup(this) && this.isAutoStartup();
3763                    if (!addingRoutes || autoStartup) {
3764                        // start the route since auto start is enabled or we are starting a route (not adding new routes)
3765                        routeService.start();
3766                    }
3767                }
3768            }
3769        } finally {
3770            if (!alreadyStartingRoutes) {
3771                isStartingRoutes.remove();
3772            }
3773        }
3774    }
3775
3776    /**
3777     * Resumes the given route service
3778     */
3779    protected synchronized void resumeRouteService(RouteService routeService) throws Exception {
3780        // the route service could have been stopped, and if so then start it instead
3781        if (!routeService.getStatus().isSuspended()) {
3782            startRouteService(routeService, false);
3783        } else {
3784            // resume the route service
3785            if (shouldStartRoutes()) {
3786                // this method will log the routes being started
3787                safelyStartRouteServices(true, false, true, true, false, routeService);
3788                // must resume route service as well
3789                routeService.resume();
3790            }
3791        }
3792    }
3793
3794    protected synchronized void stopRouteService(RouteService routeService, boolean removingRoutes) throws Exception {
3795        routeService.setRemovingRoutes(removingRoutes);
3796        stopRouteService(routeService);
3797    }
3798
3799    protected void logRouteState(Route route, String state) {
3800        if (log.isInfoEnabled()) {
3801            if (route.getConsumer() != null) {
3802                log.info("Route: {} is {}, was consuming from: {}", route.getId(), state, route.getConsumer().getEndpoint());
3803            } else {
3804                log.info("Route: {} is {}.", route.getId(), state);
3805            }
3806        }
3807    }
3808
3809    protected synchronized void stopRouteService(RouteService routeService) throws Exception {
3810        routeService.stop();
3811        for (Route route : routeService.getRoutes()) {
3812            logRouteState(route, "stopped");
3813        }
3814    }
3815
3816    protected synchronized void shutdownRouteService(RouteService routeService) throws Exception {
3817        routeService.shutdown();
3818        for (Route route : routeService.getRoutes()) {
3819            logRouteState(route, "shutdown and removed");
3820        }
3821    }
3822
3823    protected synchronized void suspendRouteService(RouteService routeService) throws Exception {
3824        routeService.setRemovingRoutes(false);
3825        routeService.suspend();
3826        for (Route route : routeService.getRoutes()) {
3827            logRouteState(route, "suspended");
3828        }
3829    }
3830
3831    /**
3832     * Starts the routes services in a proper manner which ensures the routes will be started in correct order,
3833     * check for clash and that the routes will also be shutdown in correct order as well.
3834     * <p/>
3835     * This method <b>must</b> be used to start routes in a safe manner.
3836     *
3837     * @param checkClash     whether to check for startup order clash
3838     * @param startConsumer  whether the route consumer should be started. Can be used to warmup the route without starting the consumer.
3839     * @param resumeConsumer whether the route consumer should be resumed.
3840     * @param addingRoutes   whether we are adding new routes
3841     * @param routeServices  the routes
3842     * @throws Exception is thrown if error starting the routes
3843     */
3844    protected synchronized void safelyStartRouteServices(boolean checkClash, boolean startConsumer, boolean resumeConsumer,
3845                                                         boolean addingRoutes, Collection<RouteService> routeServices) throws Exception {
3846        // list of inputs to start when all the routes have been prepared for starting
3847        // we use a tree map so the routes will be ordered according to startup order defined on the route
3848        Map<Integer, DefaultRouteStartupOrder> inputs = new TreeMap<>();
3849
3850        // figure out the order in which the routes should be started
3851        for (RouteService routeService : routeServices) {
3852            DefaultRouteStartupOrder order = doPrepareRouteToBeStarted(routeService);
3853            // check for clash before we add it as input
3854            if (checkClash) {
3855                doCheckStartupOrderClash(order, inputs);
3856            }
3857            inputs.put(order.getStartupOrder(), order);
3858        }
3859
3860        // warm up routes before we start them
3861        doWarmUpRoutes(inputs, startConsumer);
3862
3863        // sort the startup listeners so they are started in the right order
3864        startupListeners.sort(OrderedComparator.get());
3865        // now call the startup listeners where the routes has been warmed up
3866        // (only the actual route consumer has not yet been started)
3867        for (StartupListener startup : startupListeners) {
3868            startup.onCamelContextStarted(this, isStarted());
3869        }
3870        // because the consumers may also register startup listeners we need to reset
3871        // the already started listeners
3872        List<StartupListener> backup = new ArrayList<>(startupListeners);
3873        startupListeners.clear();
3874
3875        // now start the consumers
3876        if (startConsumer) {
3877            if (resumeConsumer) {
3878                // and now resume the routes
3879                doResumeRouteConsumers(inputs, addingRoutes);
3880            } else {
3881                // and now start the routes
3882                // and check for clash with multiple consumers of the same endpoints which is not allowed
3883                doStartRouteConsumers(inputs, addingRoutes);
3884            }
3885        }
3886
3887        // sort the startup listeners so they are started in the right order
3888        startupListeners.sort(OrderedComparator.get());
3889        // now the consumers that was just started may also add new StartupListeners (such as timer)
3890        // so we need to ensure they get started as well
3891        for (StartupListener startup : startupListeners) {
3892            startup.onCamelContextStarted(this, isStarted());
3893        }
3894        // and add the previous started startup listeners to the list so we have them all
3895        startupListeners.addAll(0, backup);
3896
3897        // inputs no longer needed
3898        inputs.clear();
3899    }
3900
3901    /**
3902     * @see #safelyStartRouteServices(boolean,boolean,boolean,boolean,java.util.Collection)
3903     */
3904    protected synchronized void safelyStartRouteServices(boolean forceAutoStart, boolean checkClash, boolean startConsumer,
3905                                                         boolean resumeConsumer, boolean addingRoutes, RouteService... routeServices) throws Exception {
3906        safelyStartRouteServices(checkClash, startConsumer, resumeConsumer, addingRoutes, Arrays.asList(routeServices));
3907    }
3908
3909    private DefaultRouteStartupOrder doPrepareRouteToBeStarted(RouteService routeService) {
3910        // add the inputs from this route service to the list to start afterwards
3911        // should be ordered according to the startup number
3912        Integer startupOrder = routeService.getRouteDefinition().getStartupOrder();
3913        if (startupOrder == null) {
3914            // auto assign a default startup order
3915            startupOrder = defaultRouteStartupOrder++;
3916        }
3917
3918        // create holder object that contains information about this route to be started
3919        Route route = routeService.getRoutes().iterator().next();
3920        return new DefaultRouteStartupOrder(startupOrder, route, routeService);
3921    }
3922
3923    private boolean doCheckStartupOrderClash(DefaultRouteStartupOrder answer, Map<Integer, DefaultRouteStartupOrder> inputs) throws FailedToStartRouteException {
3924        // check for clash by startupOrder id
3925        DefaultRouteStartupOrder other = inputs.get(answer.getStartupOrder());
3926        if (other != null && answer != other) {
3927            String otherId = other.getRoute().getId();
3928            throw new FailedToStartRouteException(answer.getRoute().getId(), "startupOrder clash. Route " + otherId + " already has startupOrder "
3929                + answer.getStartupOrder() + " configured which this route have as well. Please correct startupOrder to be unique among all your routes.");
3930        }
3931        // check in existing already started as well
3932        for (RouteStartupOrder order : routeStartupOrder) {
3933            String otherId = order.getRoute().getId();
3934            if (answer.getRoute().getId().equals(otherId)) {
3935                // its the same route id so skip clash check as its the same route (can happen when using suspend/resume)
3936            } else if (answer.getStartupOrder() == order.getStartupOrder()) {
3937                throw new FailedToStartRouteException(answer.getRoute().getId(), "startupOrder clash. Route " + otherId + " already has startupOrder "
3938                    + answer.getStartupOrder() + " configured which this route have as well. Please correct startupOrder to be unique among all your routes.");
3939            }
3940        }
3941        return true;
3942    }
3943
3944    private void doWarmUpRoutes(Map<Integer, DefaultRouteStartupOrder> inputs, boolean autoStartup) throws Exception {
3945        // now prepare the routes by starting its services before we start the input
3946        for (Map.Entry<Integer, DefaultRouteStartupOrder> entry : inputs.entrySet()) {
3947            // defer starting inputs till later as we want to prepare the routes by starting
3948            // all their processors and child services etc.
3949            // then later we open the floods to Camel by starting the inputs
3950            // what this does is to ensure Camel is more robust on starting routes as all routes
3951            // will then be prepared in time before we start inputs which will consume messages to be routed
3952            RouteService routeService = entry.getValue().getRouteService();
3953            log.debug("Warming up route id: {} having autoStartup={}", routeService.getId(), autoStartup);
3954            routeService.warmUp();
3955        }
3956    }
3957
3958    private void doResumeRouteConsumers(Map<Integer, DefaultRouteStartupOrder> inputs, boolean addingRoutes) throws Exception {
3959        doStartOrResumeRouteConsumers(inputs, true, addingRoutes);
3960    }
3961
3962    private void doStartRouteConsumers(Map<Integer, DefaultRouteStartupOrder> inputs, boolean addingRoutes) throws Exception {
3963        doStartOrResumeRouteConsumers(inputs, false, addingRoutes);
3964    }
3965
3966    private void doStartOrResumeRouteConsumers(Map<Integer, DefaultRouteStartupOrder> inputs, boolean resumeOnly, boolean addingRoute) throws Exception {
3967        List<Endpoint> routeInputs = new ArrayList<>();
3968
3969        for (Map.Entry<Integer, DefaultRouteStartupOrder> entry : inputs.entrySet()) {
3970            Integer order = entry.getKey();
3971            Route route = entry.getValue().getRoute();
3972            RouteService routeService = entry.getValue().getRouteService();
3973
3974            // if we are starting camel, then skip routes which are configured to not be auto started
3975            boolean autoStartup = routeService.getRouteDefinition().isAutoStartup(this) && this.isAutoStartup();
3976            if (addingRoute && !autoStartup) {
3977                log.info("Skipping starting of route {} as its configured with autoStartup=false", routeService.getId());
3978                continue;
3979            }
3980
3981            // start the service
3982            for (Consumer consumer : routeService.getInputs().values()) {
3983                Endpoint endpoint = consumer.getEndpoint();
3984
3985                // check multiple consumer violation, with the other routes to be started
3986                if (!doCheckMultipleConsumerSupportClash(endpoint, routeInputs)) {
3987                    throw new FailedToStartRouteException(routeService.getId(),
3988                        "Multiple consumers for the same endpoint is not allowed: " + endpoint);
3989                }
3990
3991                // check for multiple consumer violations with existing routes which
3992                // have already been started, or is currently starting
3993                List<Endpoint> existingEndpoints = new ArrayList<>();
3994                for (Route existingRoute : getRoutes()) {
3995                    if (route.getId().equals(existingRoute.getId())) {
3996                        // skip ourselves
3997                        continue;
3998                    }
3999                    Endpoint existing = existingRoute.getEndpoint();
4000                    ServiceStatus status = getRouteStatus(existingRoute.getId());
4001                    if (status != null && (status.isStarted() || status.isStarting())) {
4002                        existingEndpoints.add(existing);
4003                    }
4004                }
4005                if (!doCheckMultipleConsumerSupportClash(endpoint, existingEndpoints)) {
4006                    throw new FailedToStartRouteException(routeService.getId(),
4007                            "Multiple consumers for the same endpoint is not allowed: " + endpoint);
4008                }
4009
4010                // start the consumer on the route
4011                log.debug("Route: {} >>> {}", route.getId(), route);
4012                if (resumeOnly) {
4013                    log.debug("Resuming consumer (order: {}) on route: {}", order, route.getId());
4014                } else {
4015                    log.debug("Starting consumer (order: {}) on route: {}", order, route.getId());
4016                }
4017
4018                if (resumeOnly && route.supportsSuspension()) {
4019                    // if we are resuming and the route can be resumed
4020                    ServiceHelper.resumeService(consumer);
4021                    log.info("Route: {} resumed and consuming from: {}", route.getId(), endpoint);
4022                } else {
4023                    // when starting we should invoke the lifecycle strategies
4024                    for (LifecycleStrategy strategy : lifecycleStrategies) {
4025                        strategy.onServiceAdd(this, consumer, route);
4026                    }
4027                    try {
4028                        startService(consumer);
4029                        route.getProperties().remove("route.start.exception");
4030                    } catch (Exception e) {
4031                        route.getProperties().put("route.start.exception", e);
4032                        throw e;
4033                    }
4034
4035                    log.info("Route: {} started and consuming from: {}", route.getId(), endpoint);
4036                }
4037
4038                routeInputs.add(endpoint);
4039
4040                // add to the order which they was started, so we know how to stop them in reverse order
4041                // but only add if we haven't already registered it before (we dont want to double add when restarting)
4042                boolean found = false;
4043                for (RouteStartupOrder other : routeStartupOrder) {
4044                    if (other.getRoute().getId().equals(route.getId())) {
4045                        found = true;
4046                        break;
4047                    }
4048                }
4049                if (!found) {
4050                    routeStartupOrder.add(entry.getValue());
4051                }
4052            }
4053
4054            if (resumeOnly) {
4055                routeService.resume();
4056            } else {
4057                // and start the route service (no need to start children as they are already warmed up)
4058                try {
4059                    routeService.start(false);
4060                    route.getProperties().remove("route.start.exception");
4061                } catch (Exception e) {
4062                    route.getProperties().put("route.start.exception", e);
4063                    throw e;
4064                }
4065            }
4066        }
4067    }
4068
4069    private boolean doCheckMultipleConsumerSupportClash(Endpoint endpoint, List<Endpoint> routeInputs) {
4070        // is multiple consumers supported
4071        boolean multipleConsumersSupported = false;
4072        if (endpoint instanceof MultipleConsumersSupport) {
4073            multipleConsumersSupported = ((MultipleConsumersSupport) endpoint).isMultipleConsumersSupported();
4074        }
4075
4076        if (multipleConsumersSupported) {
4077            // multiple consumer allowed, so return true
4078            return true;
4079        }
4080
4081        // check in progress list
4082        if (routeInputs.contains(endpoint)) {
4083            return false;
4084        }
4085
4086        return true;
4087    }
4088
4089    /**
4090     * Force some lazy initialization to occur upfront before we start any
4091     * components and create routes
4092     */
4093    protected void forceLazyInitialization() {
4094        getRegistry();
4095        getInjector();
4096        getLanguageResolver();
4097        getTypeConverterRegistry();
4098        getTypeConverter();
4099
4100        if (isTypeConverterStatisticsEnabled() != null) {
4101            getTypeConverterRegistry().getStatistics().setStatisticsEnabled(isTypeConverterStatisticsEnabled());
4102        }
4103
4104        // resolve simple language to initialize it
4105        resolveLanguage("simple");
4106    }
4107
4108    /**
4109     * Force clear lazy initialization so they can be re-created on restart
4110     */
4111    protected void forceStopLazyInitialization() {
4112        injector = null;
4113        languageResolver = null;
4114        typeConverterRegistry = null;
4115        typeConverter = null;
4116    }
4117
4118    /**
4119     * Lazily create a default implementation
4120     */
4121    protected TypeConverter createTypeConverter() {
4122        BaseTypeConverterRegistry answer;
4123        if (isLazyLoadTypeConverters()) {
4124            answer = new LazyLoadingTypeConverter(packageScanClassResolver, getInjector(), getDefaultFactoryFinder());
4125        } else {
4126            answer = new DefaultTypeConverter(packageScanClassResolver, getInjector(), getDefaultFactoryFinder(), isLoadTypeConverters());
4127        }
4128        answer.setCamelContext(this);
4129        setTypeConverterRegistry(answer);
4130        return answer;
4131    }
4132
4133    /**
4134     * Lazily create a default implementation
4135     */
4136    protected Injector createInjector() {
4137        FactoryFinder finder = getDefaultFactoryFinder();
4138        try {
4139            return (Injector) finder.newInstance("Injector");
4140        } catch (NoFactoryAvailableException e) {
4141            // lets use the default injector
4142            return new DefaultInjector(this);
4143        }
4144    }
4145
4146    /**
4147     * Lazily create a default implementation
4148     */
4149    protected ManagementMBeanAssembler createManagementMBeanAssembler() {
4150        return new DefaultManagementMBeanAssembler(this);
4151    }
4152
4153    /**
4154     * Lazily create a default implementation
4155     */
4156    protected ComponentResolver createComponentResolver() {
4157        return new DefaultComponentResolver();
4158    }
4159
4160    /**
4161     * Lazily create a default implementation
4162     */
4163    protected Registry createRegistry() {
4164        JndiRegistry jndi = new JndiRegistry();
4165        try {
4166            // getContext() will force setting up JNDI
4167            jndi.getContext();
4168            return jndi;
4169        } catch (Throwable e) {
4170            log.debug("Cannot create javax.naming.InitialContext due " + e.getMessage() + ". Will fallback and use SimpleRegistry instead. This exception is ignored.", e);
4171            return new SimpleRegistry();
4172        }
4173    }
4174
4175    /**
4176     * A pluggable strategy to allow an endpoint to be created without requiring
4177     * a component to be its factory, such as for looking up the URI inside some
4178     * {@link Registry}
4179     *
4180     * @param uri the uri for the endpoint to be created
4181     * @return the newly created endpoint or null if it could not be resolved
4182     */
4183    protected Endpoint createEndpoint(String uri) {
4184        Object value = getRegistry().lookupByName(uri);
4185        if (value instanceof Endpoint) {
4186            return (Endpoint) value;
4187        } else if (value instanceof Processor) {
4188            return new ProcessorEndpoint(uri, this, (Processor) value);
4189        } else if (value != null) {
4190            return convertBeanToEndpoint(uri, value);
4191        }
4192        return null;
4193    }
4194
4195    /**
4196     * Strategy method for attempting to convert the bean from a {@link Registry} to an endpoint using
4197     * some kind of transformation or wrapper
4198     *
4199     * @param uri  the uri for the endpoint (and name in the registry)
4200     * @param bean the bean to be converted to an endpoint, which will be not null
4201     * @return a new endpoint
4202     */
4203    protected Endpoint convertBeanToEndpoint(String uri, Object bean) {
4204        throw new IllegalArgumentException("uri: " + uri + " bean: " + bean
4205                + " could not be converted to an Endpoint");
4206    }
4207
4208    /**
4209     * Should we start newly added routes?
4210     */
4211    protected boolean shouldStartRoutes() {
4212        return isStarted() && !isStarting();
4213    }
4214
4215    /**
4216     * Gets the properties component in use.
4217     * Returns {@code null} if no properties component is in use.
4218     */
4219    protected PropertiesComponent getPropertiesComponent() {
4220        return propertiesComponent;
4221    }
4222
4223    public void setDataFormats(Map<String, DataFormatDefinition> dataFormats) {
4224        this.dataFormats = dataFormats;
4225    }
4226
4227    public Map<String, DataFormatDefinition> getDataFormats() {
4228        return dataFormats;
4229    }
4230
4231    @Deprecated
4232    public Map<String, String> getProperties() {
4233        return getGlobalOptions();
4234    }
4235
4236    @Override
4237    public Map<String, String> getGlobalOptions() {
4238        return globalOptions;
4239    }
4240
4241    @Deprecated
4242    public void setProperties(Map<String, String> properties) {
4243        this.setGlobalOptions(properties);
4244    }
4245
4246    @Override
4247    public void setGlobalOptions(Map<String, String> globalOptions) {
4248        this.globalOptions = globalOptions;
4249    }
4250
4251    public FactoryFinder getDefaultFactoryFinder() {
4252        if (defaultFactoryFinder == null) {
4253            defaultFactoryFinder = getFactoryFinderResolver().resolveDefaultFactoryFinder(getClassResolver());
4254        }
4255        return defaultFactoryFinder;
4256    }
4257
4258    public FactoryFinderResolver getFactoryFinderResolver() {
4259        if (factoryFinderResolver == null) {
4260            factoryFinderResolver = createFactoryFinderResolver();
4261        }
4262        return factoryFinderResolver;
4263    }
4264
4265    public void setFactoryFinderResolver(FactoryFinderResolver resolver) {
4266        this.factoryFinderResolver = resolver;
4267    }
4268
4269    public FactoryFinder getFactoryFinder(String path) throws NoFactoryAvailableException {
4270        synchronized (factories) {
4271            FactoryFinder answer = factories.get(path);
4272            if (answer == null) {
4273                answer = getFactoryFinderResolver().resolveFactoryFinder(getClassResolver(), path);
4274                factories.put(path, answer);
4275            }
4276            return answer;
4277        }
4278    }
4279
4280    public ClassResolver getClassResolver() {
4281        return classResolver;
4282    }
4283
4284    public void setClassResolver(ClassResolver classResolver) {
4285        this.classResolver = classResolver;
4286    }
4287
4288    public PackageScanClassResolver getPackageScanClassResolver() {
4289        return packageScanClassResolver;
4290    }
4291
4292    public void setPackageScanClassResolver(PackageScanClassResolver packageScanClassResolver) {
4293        this.packageScanClassResolver = packageScanClassResolver;
4294    }
4295
4296    public List<String> getComponentNames() {
4297        List<String> answer = new ArrayList<>();
4298        for (String name : components.keySet()) {
4299            answer.add(name);
4300        }
4301        return answer;
4302    }
4303
4304    public List<String> getLanguageNames() {
4305        synchronized (languages) {
4306            List<String> answer = new ArrayList<>();
4307            for (String name : languages.keySet()) {
4308                answer.add(name);
4309            }
4310            return answer;
4311        }
4312    }
4313
4314    public ModelJAXBContextFactory getModelJAXBContextFactory() {
4315        if (modelJAXBContextFactory == null) {
4316            modelJAXBContextFactory = createModelJAXBContextFactory();
4317        }
4318        return modelJAXBContextFactory;
4319    }
4320
4321    public void setModelJAXBContextFactory(final ModelJAXBContextFactory modelJAXBContextFactory) {
4322        this.modelJAXBContextFactory = modelJAXBContextFactory;
4323    }
4324
4325    public NodeIdFactory getNodeIdFactory() {
4326        return nodeIdFactory;
4327    }
4328
4329    public void setNodeIdFactory(NodeIdFactory idFactory) {
4330        this.nodeIdFactory = idFactory;
4331    }
4332
4333    public ManagementStrategy getManagementStrategy() {
4334        return managementStrategy;
4335    }
4336
4337    public void setManagementStrategy(ManagementStrategy managementStrategy) {
4338        this.managementStrategy = managementStrategy;
4339    }
4340
4341    public InterceptStrategy getDefaultTracer() {
4342        if (defaultTracer == null) {
4343            defaultTracer = new Tracer();
4344        }
4345        return defaultTracer;
4346    }
4347
4348    public void setDefaultTracer(InterceptStrategy tracer) {
4349        this.defaultTracer = tracer;
4350    }
4351
4352    public InterceptStrategy getDefaultBacklogTracer() {
4353        if (defaultBacklogTracer == null) {
4354            defaultBacklogTracer = BacklogTracer.createTracer(this);
4355        }
4356        return defaultBacklogTracer;
4357    }
4358
4359    public void setDefaultBacklogTracer(InterceptStrategy backlogTracer) {
4360        this.defaultBacklogTracer = backlogTracer;
4361    }
4362
4363    public InterceptStrategy getDefaultBacklogDebugger() {
4364        if (defaultBacklogDebugger == null) {
4365            defaultBacklogDebugger = new BacklogDebugger(this);
4366        }
4367        return defaultBacklogDebugger;
4368    }
4369
4370    public void setDefaultBacklogDebugger(InterceptStrategy defaultBacklogDebugger) {
4371        this.defaultBacklogDebugger = defaultBacklogDebugger;
4372    }
4373
4374    public void disableJMX() {
4375        if (isStarting() || isStarted()) {
4376            throw new IllegalStateException("Disabling JMX can only be done when CamelContext has not been started");
4377        }
4378        managementStrategy = new DefaultManagementStrategy(this);
4379        // must clear lifecycle strategies as we add DefaultManagementLifecycleStrategy by default for JMX support
4380        lifecycleStrategies.clear();
4381    }
4382
4383    public InflightRepository getInflightRepository() {
4384        return inflightRepository;
4385    }
4386
4387    public void setInflightRepository(InflightRepository repository) {
4388        this.inflightRepository = repository;
4389    }
4390
4391    public AsyncProcessorAwaitManager getAsyncProcessorAwaitManager() {
4392        return asyncProcessorAwaitManager;
4393    }
4394
4395    public void setAsyncProcessorAwaitManager(AsyncProcessorAwaitManager asyncProcessorAwaitManager) {
4396        this.asyncProcessorAwaitManager = asyncProcessorAwaitManager;
4397    }
4398
4399    public void setAutoStartup(Boolean autoStartup) {
4400        this.autoStartup = autoStartup;
4401    }
4402
4403    public Boolean isAutoStartup() {
4404        return autoStartup != null && autoStartup;
4405    }
4406
4407    @Deprecated
4408    public Boolean isLazyLoadTypeConverters() {
4409        return lazyLoadTypeConverters != null && lazyLoadTypeConverters;
4410    }
4411
4412    @Deprecated
4413    public void setLazyLoadTypeConverters(Boolean lazyLoadTypeConverters) {
4414        this.lazyLoadTypeConverters = lazyLoadTypeConverters;
4415    }
4416
4417    public Boolean isLoadTypeConverters() {
4418        return loadTypeConverters != null && loadTypeConverters;
4419    }
4420
4421    public void setLoadTypeConverters(Boolean loadTypeConverters) {
4422        this.loadTypeConverters = loadTypeConverters;
4423    }
4424
4425    public Boolean isTypeConverterStatisticsEnabled() {
4426        return typeConverterStatisticsEnabled != null && typeConverterStatisticsEnabled;
4427    }
4428
4429    public void setTypeConverterStatisticsEnabled(Boolean typeConverterStatisticsEnabled) {
4430        this.typeConverterStatisticsEnabled = typeConverterStatisticsEnabled;
4431    }
4432
4433    public Boolean isUseMDCLogging() {
4434        return useMDCLogging != null && useMDCLogging;
4435    }
4436
4437    public void setUseMDCLogging(Boolean useMDCLogging) {
4438        this.useMDCLogging = useMDCLogging;
4439    }
4440
4441    public Boolean isUseDataType() {
4442        return useDataType;
4443    }
4444
4445    @Override
4446    public void setUseDataType(Boolean useDataType) {
4447        this.useDataType = useDataType;
4448    }
4449
4450    public Boolean isUseBreadcrumb() {
4451        return useBreadcrumb != null && useBreadcrumb;
4452    }
4453
4454    public void setUseBreadcrumb(Boolean useBreadcrumb) {
4455        this.useBreadcrumb = useBreadcrumb;
4456    }
4457
4458    public ClassLoader getApplicationContextClassLoader() {
4459        return applicationContextClassLoader;
4460    }
4461
4462    public void setApplicationContextClassLoader(ClassLoader classLoader) {
4463        applicationContextClassLoader = classLoader;
4464    }
4465
4466    public DataFormatResolver getDataFormatResolver() {
4467        if (dataFormatResolver == null) {
4468            dataFormatResolver = createDataFormatResolver();
4469        }
4470        return dataFormatResolver;
4471    }
4472
4473    public void setDataFormatResolver(DataFormatResolver dataFormatResolver) {
4474        this.dataFormatResolver = dataFormatResolver;
4475    }
4476
4477    public DataFormat resolveDataFormat(String name) {
4478        DataFormat answer = getDataFormatResolver().resolveDataFormat(name, this);
4479
4480        // inject CamelContext if aware
4481        if (answer instanceof CamelContextAware) {
4482            ((CamelContextAware) answer).setCamelContext(this);
4483        }
4484
4485        return answer;
4486    }
4487
4488    public DataFormat createDataFormat(String name) {
4489        DataFormat answer = getDataFormatResolver().createDataFormat(name, this);
4490
4491        // inject CamelContext if aware
4492        if (answer instanceof CamelContextAware) {
4493            ((CamelContextAware) answer).setCamelContext(this);
4494        }
4495
4496        return answer;
4497    }
4498
4499    public DataFormatDefinition resolveDataFormatDefinition(String name) {
4500        // lookup type and create the data format from it
4501        DataFormatDefinition type = lookup(this, name, DataFormatDefinition.class);
4502        if (type == null && getDataFormats() != null) {
4503            type = getDataFormats().get(name);
4504        }
4505        return type;
4506    }
4507
4508    private static <T> T lookup(CamelContext context, String ref, Class<T> type) {
4509        try {
4510            return context.getRegistry().lookupByNameAndType(ref, type);
4511        } catch (Exception e) {
4512            // need to ignore not same type and return it as null
4513            return null;
4514        }
4515    }
4516
4517    /**
4518     * @deprecated use {@link org.apache.camel.util.CamelContextHelper#lookupPropertiesComponent(org.apache.camel.CamelContext, boolean)}
4519     */
4520    @Deprecated
4521    protected Component lookupPropertiesComponent() {
4522        return CamelContextHelper.lookupPropertiesComponent(this, false);
4523    }
4524
4525    public ShutdownStrategy getShutdownStrategy() {
4526        return shutdownStrategy;
4527    }
4528
4529    public void setShutdownStrategy(ShutdownStrategy shutdownStrategy) {
4530        this.shutdownStrategy = shutdownStrategy;
4531    }
4532
4533    public ShutdownRoute getShutdownRoute() {
4534        return shutdownRoute;
4535    }
4536
4537    public void setShutdownRoute(ShutdownRoute shutdownRoute) {
4538        this.shutdownRoute = shutdownRoute;
4539    }
4540
4541    public ShutdownRunningTask getShutdownRunningTask() {
4542        return shutdownRunningTask;
4543    }
4544
4545    public void setShutdownRunningTask(ShutdownRunningTask shutdownRunningTask) {
4546        this.shutdownRunningTask = shutdownRunningTask;
4547    }
4548
4549    public void setAllowUseOriginalMessage(Boolean allowUseOriginalMessage) {
4550        this.allowUseOriginalMessage = allowUseOriginalMessage;
4551    }
4552
4553    public Boolean isAllowUseOriginalMessage() {
4554        return allowUseOriginalMessage != null && allowUseOriginalMessage;
4555    }
4556
4557    public ExecutorServiceManager getExecutorServiceManager() {
4558        return this.executorServiceManager;
4559    }
4560
4561    @Deprecated
4562    public org.apache.camel.spi.ExecutorServiceStrategy getExecutorServiceStrategy() {
4563        // its okay to create a new instance as its stateless, and just delegate
4564        // ExecutorServiceManager which is the new API
4565        return new DefaultExecutorServiceStrategy(this);
4566    }
4567
4568    public void setExecutorServiceManager(ExecutorServiceManager executorServiceManager) {
4569        this.executorServiceManager = executorServiceManager;
4570    }
4571
4572    public ProcessorFactory getProcessorFactory() {
4573        return processorFactory;
4574    }
4575
4576    public void setProcessorFactory(ProcessorFactory processorFactory) {
4577        this.processorFactory = processorFactory;
4578    }
4579
4580    public MessageHistoryFactory getMessageHistoryFactory() {
4581        return messageHistoryFactory;
4582    }
4583
4584    public void setMessageHistoryFactory(MessageHistoryFactory messageHistoryFactory) {
4585        this.messageHistoryFactory = messageHistoryFactory;
4586    }
4587
4588    public Debugger getDebugger() {
4589        return debugger;
4590    }
4591
4592    public void setDebugger(Debugger debugger) {
4593        this.debugger = debugger;
4594    }
4595
4596    public UuidGenerator getUuidGenerator() {
4597        return uuidGenerator;
4598    }
4599
4600    public void setUuidGenerator(UuidGenerator uuidGenerator) {
4601        this.uuidGenerator = uuidGenerator;
4602    }
4603
4604    public StreamCachingStrategy getStreamCachingStrategy() {
4605        if (streamCachingStrategy == null) {
4606            streamCachingStrategy = new DefaultStreamCachingStrategy();
4607        }
4608        return streamCachingStrategy;
4609    }
4610
4611    public void setStreamCachingStrategy(StreamCachingStrategy streamCachingStrategy) {
4612        this.streamCachingStrategy = streamCachingStrategy;
4613    }
4614
4615    public RestRegistry getRestRegistry() {
4616        return restRegistry;
4617    }
4618
4619    public void setRestRegistry(RestRegistry restRegistry) {
4620        this.restRegistry = restRegistry;
4621    }
4622
4623    @Deprecated
4624    @Override
4625    public String getProperty(String key) {
4626        return getGlobalOption(key);
4627    }
4628
4629    @Override
4630    public String getGlobalOption(String key) {
4631        String value = getGlobalOptions().get(key);
4632        if (ObjectHelper.isNotEmpty(value)) {
4633            try {
4634                value = resolvePropertyPlaceholders(value);
4635            } catch (Exception e) {
4636                throw new RuntimeCamelException("Error getting global option: " + key, e);
4637            }
4638        }
4639        return value;
4640    }
4641
4642    @Override
4643    public ReloadStrategy getReloadStrategy() {
4644        return reloadStrategy;
4645    }
4646
4647    @Override
4648    public void setReloadStrategy(ReloadStrategy reloadStrategy) {
4649        this.reloadStrategy = reloadStrategy;
4650    }
4651
4652    @Override
4653    public void setTransformers(List<TransformerDefinition> transformers) {
4654        this.transformers = transformers;
4655    }
4656
4657    @Override
4658    public List<TransformerDefinition> getTransformers() {
4659        return transformers;
4660    }
4661
4662    @Override
4663    public Transformer resolveTransformer(String scheme) {
4664        return transformerRegistry.resolveTransformer(new TransformerKey(scheme));
4665    }
4666
4667    @Override
4668    public Transformer resolveTransformer(DataType from, DataType to) {
4669        return transformerRegistry.resolveTransformer(new TransformerKey(from, to));
4670    }
4671
4672    @Override
4673    public TransformerRegistry<TransformerKey> getTransformerRegistry() {
4674        return transformerRegistry;
4675    }
4676
4677    @Override
4678    public void setValidators(List<ValidatorDefinition> validators) {
4679        this.validators = validators;
4680    }
4681
4682    @Override
4683    public List<ValidatorDefinition> getValidators() {
4684        return validators;
4685    }
4686
4687    @Override
4688    public Validator resolveValidator(DataType type) {
4689        return validatorRegistry.resolveValidator(new ValidatorKey(type));
4690    }
4691
4692    @Override
4693    public ValidatorRegistry<ValidatorKey> getValidatorRegistry() {
4694        return validatorRegistry;
4695    }
4696
4697    @Override
4698    public RuntimeCamelCatalog getRuntimeCamelCatalog() {
4699        return runtimeCamelCatalog;
4700    }
4701
4702    @Override
4703    public void setSSLContextParameters(SSLContextParameters sslContextParameters) {
4704        this.sslContextParameters = sslContextParameters;
4705    }
4706
4707    @Override
4708    public SSLContextParameters getSSLContextParameters() {
4709        return this.sslContextParameters;
4710    }
4711
4712    @Override
4713    public HeadersMapFactory getHeadersMapFactory() {
4714        return headersMapFactory;
4715    }
4716
4717    @Override
4718    public void setHeadersMapFactory(HeadersMapFactory headersMapFactory) {
4719        this.headersMapFactory = headersMapFactory;
4720    }
4721
4722    protected Map<String, RouteService> getRouteServices() {
4723        return routeServices;
4724    }
4725
4726    protected ManagementStrategy createManagementStrategy() {
4727        return new ManagementStrategyFactory().create(this, disableJMX || Boolean.getBoolean(JmxSystemPropertyKeys.DISABLED));
4728    }
4729
4730    /**
4731     * Reset context counter to a preset value. Mostly used for tests to ensure a predictable getName()
4732     *
4733     * @param value new value for the context counter
4734     */
4735    public static void setContextCounter(int value) {
4736        DefaultCamelContextNameStrategy.setCounter(value);
4737        DefaultManagementNameStrategy.setCounter(value);
4738    }
4739
4740    protected UuidGenerator createDefaultUuidGenerator() {
4741        if (System.getProperty("com.google.appengine.runtime.environment") != null) {
4742            // either "Production" or "Development"
4743            return new JavaUuidGenerator();
4744        } else {
4745            return new DefaultUuidGenerator();
4746        }
4747    }
4748
4749    protected ModelJAXBContextFactory createModelJAXBContextFactory() {
4750        return new DefaultModelJAXBContextFactory();
4751    }
4752
4753    @Override
4754    public String toString() {
4755        return "CamelContext(" + getName() + ")";
4756    }
4757
4758    class MDCHelper implements AutoCloseable {
4759        final Map<String, String> originalContextMap;
4760
4761        MDCHelper() {
4762            if (isUseMDCLogging()) {
4763                originalContextMap = MDC.getCopyOfContextMap();
4764                MDC.put(MDC_CAMEL_CONTEXT_ID, getName());
4765            } else {
4766                originalContextMap = null;
4767            }
4768        }
4769
4770        @Override
4771        public void close() {
4772            if (isUseMDCLogging()) {
4773                if (originalContextMap != null) {
4774                    MDC.setContextMap(originalContextMap);
4775                } else {
4776                    MDC.clear();
4777                }
4778            }
4779        }
4780    }
4781
4782    @Override
4783    public HealthCheckRegistry getHealthCheckRegistry() {
4784        return healthCheckRegistry;
4785    }
4786
4787    /**
4788     * Sets a {@link HealthCheckRegistry}.
4789     */
4790    public void setHealthCheckRegistry(HealthCheckRegistry healthCheckRegistry) {
4791        this.healthCheckRegistry = ObjectHelper.notNull(healthCheckRegistry, "HealthCheckRegistry");
4792    }
4793
4794    protected NodeIdFactory createNodeIdFactory() {
4795        return new DefaultNodeIdFactory();
4796    }
4797
4798    protected FactoryFinderResolver createFactoryFinderResolver() {
4799        return new DefaultFactoryFinderResolver();
4800    }
4801
4802    protected ClassResolver createClassResolver() {
4803        return new DefaultClassResolver(this);
4804    }
4805
4806    protected ProcessorFactory createProcessorFactory() {
4807        return new DefaultProcessorFactory();
4808    }
4809
4810    protected DataFormatResolver createDataFormatResolver() {
4811        return new DefaultDataFormatResolver();
4812    }
4813
4814    protected MessageHistoryFactory createMessageHistoryFactory() {
4815        return new DefaultMessageHistoryFactory();
4816    }
4817
4818    protected InflightRepository createInflightRepository() {
4819        return new DefaultInflightRepository();
4820    }
4821
4822    protected AsyncProcessorAwaitManager createAsyncProcessorAwaitManager() {
4823        return new DefaultAsyncProcessorAwaitManager();
4824    }
4825
4826    protected RouteController createRouteController() {
4827        return new DefaultRouteController(this);
4828    }
4829
4830    protected HealthCheckRegistry createHealthCheckRegistry() {
4831        return new DefaultHealthCheckRegistry(this);
4832    }
4833
4834
4835    protected ShutdownStrategy createShutdownStrategy() {
4836        return new DefaultShutdownStrategy(this);
4837    }
4838
4839    protected PackageScanClassResolver createPackageScanClassResolver() {
4840        PackageScanClassResolver packageScanClassResolver;
4841        // use WebSphere specific resolver if running on WebSphere
4842        if (WebSpherePackageScanClassResolver.isWebSphereClassLoader(this.getClass().getClassLoader())) {
4843            log.info("Using WebSphere specific PackageScanClassResolver");
4844            packageScanClassResolver = new WebSpherePackageScanClassResolver("META-INF/services/org/apache/camel/TypeConverter");
4845        } else {
4846            packageScanClassResolver = new DefaultPackageScanClassResolver();
4847        }
4848        return packageScanClassResolver;
4849    }
4850
4851    protected ExecutorServiceManager createExecutorServiceManager() {
4852        return new DefaultExecutorServiceManager(this);
4853    }
4854
4855    protected ServicePool<Endpoint, Producer> createProducerServicePool() {
4856        return new SharedProducerServicePool(100);
4857    }
4858
4859    protected ServicePool<Endpoint, PollingConsumer> createPollingConsumerServicePool() {
4860        return new SharedPollingConsumerServicePool(100);
4861    }
4862
4863    protected UnitOfWorkFactory createUnitOfWorkFactory() {
4864        return new DefaultUnitOfWorkFactory();
4865    }
4866
4867    protected RuntimeCamelCatalog createRuntimeCamelCatalog() {
4868        return new DefaultRuntimeCamelCatalog(this, true);
4869    }
4870
4871    protected CamelContextNameStrategy createCamelContextNameStrategy() {
4872        return new DefaultCamelContextNameStrategy();
4873    }
4874
4875    protected ManagementNameStrategy createManagementNameStrategy() {
4876        return new DefaultManagementNameStrategy(this);
4877    }
4878
4879    protected HeadersMapFactory createHeadersMapFactory() {
4880        return new DefaultHeadersMapFactory();
4881    }
4882
4883    protected LanguageResolver createLanguageResolver() {
4884        return new DefaultLanguageResolver();
4885    }
4886
4887    protected EndpointRegistry<EndpointKey> createEndpointRegistry(Map<EndpointKey, Endpoint> endpoints) {
4888        return new DefaultEndpointRegistry(this, endpoints);
4889    }
4890
4891    protected ValidatorRegistry<ValidatorKey> createValidatorRegistry(List<ValidatorDefinition> validators) throws Exception {
4892        return new DefaultValidatorRegistry(this, validators);
4893    }
4894
4895    protected TransformerRegistry<TransformerKey> createTransformerRegistry(List<TransformerDefinition> transformers) throws Exception {
4896        return new DefaultTransformerRegistry(this, transformers);
4897    }
4898
4899}