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