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