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