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