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.util.ArrayList;
022import java.util.Arrays;
023import java.util.Collection;
024import java.util.Collections;
025import java.util.Date;
026import java.util.HashMap;
027import java.util.Iterator;
028import java.util.LinkedHashMap;
029import java.util.LinkedHashSet;
030import java.util.List;
031import java.util.Map;
032import java.util.Properties;
033import java.util.Set;
034import java.util.TreeMap;
035import java.util.concurrent.CopyOnWriteArrayList;
036import java.util.concurrent.ScheduledExecutorService;
037import java.util.concurrent.TimeUnit;
038import java.util.concurrent.atomic.AtomicInteger;
039import javax.naming.Context;
040import javax.xml.bind.JAXBContext;
041import javax.xml.bind.Unmarshaller;
042
043import org.apache.camel.CamelContext;
044import org.apache.camel.CamelContextAware;
045import org.apache.camel.Component;
046import org.apache.camel.Consumer;
047import org.apache.camel.ConsumerTemplate;
048import org.apache.camel.Endpoint;
049import org.apache.camel.ErrorHandlerFactory;
050import org.apache.camel.FailedToStartRouteException;
051import org.apache.camel.IsSingleton;
052import org.apache.camel.MultipleConsumersSupport;
053import org.apache.camel.NoFactoryAvailableException;
054import org.apache.camel.NoSuchEndpointException;
055import org.apache.camel.Processor;
056import org.apache.camel.Producer;
057import org.apache.camel.ProducerTemplate;
058import org.apache.camel.ResolveEndpointFailedException;
059import org.apache.camel.Route;
060import org.apache.camel.RoutesBuilder;
061import org.apache.camel.RuntimeCamelException;
062import org.apache.camel.Service;
063import org.apache.camel.ServiceStatus;
064import org.apache.camel.ShutdownRoute;
065import org.apache.camel.ShutdownRunningTask;
066import org.apache.camel.StartupListener;
067import org.apache.camel.StatefulService;
068import org.apache.camel.SuspendableService;
069import org.apache.camel.TypeConverter;
070import org.apache.camel.VetoCamelContextStartException;
071import org.apache.camel.builder.ErrorHandlerBuilder;
072import org.apache.camel.builder.ErrorHandlerBuilderSupport;
073import org.apache.camel.component.properties.PropertiesComponent;
074import org.apache.camel.impl.converter.BaseTypeConverterRegistry;
075import org.apache.camel.impl.converter.DefaultTypeConverter;
076import org.apache.camel.impl.converter.LazyLoadingTypeConverter;
077import org.apache.camel.management.DefaultManagementMBeanAssembler;
078import org.apache.camel.management.DefaultManagementStrategy;
079import org.apache.camel.management.JmxSystemPropertyKeys;
080import org.apache.camel.management.ManagementStrategyFactory;
081import org.apache.camel.model.Constants;
082import org.apache.camel.model.DataFormatDefinition;
083import org.apache.camel.model.ModelCamelContext;
084import org.apache.camel.model.RouteDefinition;
085import org.apache.camel.model.RouteDefinitionHelper;
086import org.apache.camel.model.RoutesDefinition;
087import org.apache.camel.model.rest.RestDefinition;
088import org.apache.camel.processor.interceptor.BacklogDebugger;
089import org.apache.camel.processor.interceptor.BacklogTracer;
090import org.apache.camel.processor.interceptor.Debug;
091import org.apache.camel.processor.interceptor.Delayer;
092import org.apache.camel.processor.interceptor.HandleFault;
093import org.apache.camel.processor.interceptor.StreamCaching;
094import org.apache.camel.processor.interceptor.Tracer;
095import org.apache.camel.spi.CamelContextNameStrategy;
096import org.apache.camel.spi.ClassResolver;
097import org.apache.camel.spi.ComponentResolver;
098import org.apache.camel.spi.Container;
099import org.apache.camel.spi.DataFormat;
100import org.apache.camel.spi.DataFormatResolver;
101import org.apache.camel.spi.Debugger;
102import org.apache.camel.spi.EndpointStrategy;
103import org.apache.camel.spi.EventNotifier;
104import org.apache.camel.spi.ExecutorServiceManager;
105import org.apache.camel.spi.FactoryFinder;
106import org.apache.camel.spi.FactoryFinderResolver;
107import org.apache.camel.spi.InflightRepository;
108import org.apache.camel.spi.Injector;
109import org.apache.camel.spi.InterceptStrategy;
110import org.apache.camel.spi.Language;
111import org.apache.camel.spi.LanguageResolver;
112import org.apache.camel.spi.LifecycleStrategy;
113import org.apache.camel.spi.ManagementMBeanAssembler;
114import org.apache.camel.spi.ManagementNameStrategy;
115import org.apache.camel.spi.ManagementStrategy;
116import org.apache.camel.spi.NodeIdFactory;
117import org.apache.camel.spi.PackageScanClassResolver;
118import org.apache.camel.spi.ProcessorFactory;
119import org.apache.camel.spi.Registry;
120import org.apache.camel.spi.RestConfiguration;
121import org.apache.camel.spi.RestRegistry;
122import org.apache.camel.spi.RouteContext;
123import org.apache.camel.spi.RoutePolicyFactory;
124import org.apache.camel.spi.RouteStartupOrder;
125import org.apache.camel.spi.RuntimeEndpointRegistry;
126import org.apache.camel.spi.ServicePool;
127import org.apache.camel.spi.ShutdownStrategy;
128import org.apache.camel.spi.StreamCachingStrategy;
129import org.apache.camel.spi.TypeConverterRegistry;
130import org.apache.camel.spi.UnitOfWorkFactory;
131import org.apache.camel.spi.UuidGenerator;
132import org.apache.camel.support.ServiceSupport;
133import org.apache.camel.util.CamelContextHelper;
134import org.apache.camel.util.EndpointHelper;
135import org.apache.camel.util.EventHelper;
136import org.apache.camel.util.IOHelper;
137import org.apache.camel.util.IntrospectionSupport;
138import org.apache.camel.util.LoadPropertiesException;
139import org.apache.camel.util.ObjectHelper;
140import org.apache.camel.util.ServiceHelper;
141import org.apache.camel.util.StopWatch;
142import org.apache.camel.util.StringHelper;
143import org.apache.camel.util.TimeUtils;
144import org.apache.camel.util.URISupport;
145import org.slf4j.Logger;
146import org.slf4j.LoggerFactory;
147
148import static org.apache.camel.util.StringQuoteHelper.doubleQuote;
149
150/**
151 * Represents the context used to configure routes and the policies to use.
152 *
153 * @version
154 */
155@SuppressWarnings("deprecation")
156public class DefaultCamelContext extends ServiceSupport implements ModelCamelContext, SuspendableService {
157    private final Logger log = LoggerFactory.getLogger(getClass());
158    private JAXBContext jaxbContext;
159    private CamelContextNameStrategy nameStrategy = new DefaultCamelContextNameStrategy();
160    private ManagementNameStrategy managementNameStrategy = new DefaultManagementNameStrategy(this);
161    private String managementName;
162    private ClassLoader applicationContextClassLoader;
163    private Map<EndpointKey, Endpoint> endpoints;
164    private final AtomicInteger endpointKeyCounter = new AtomicInteger();
165    private final List<EndpointStrategy> endpointStrategies = new ArrayList<EndpointStrategy>();
166    private final Map<String, Component> components = new HashMap<String, Component>();
167    private final Set<Route> routes = new LinkedHashSet<Route>();
168    private final List<Service> servicesToClose = new CopyOnWriteArrayList<Service>();
169    private final Set<StartupListener> startupListeners = new LinkedHashSet<StartupListener>();
170    private TypeConverter typeConverter;
171    private TypeConverterRegistry typeConverterRegistry;
172    private Injector injector;
173    private ComponentResolver componentResolver;
174    private boolean autoCreateComponents = true;
175    private LanguageResolver languageResolver = new DefaultLanguageResolver();
176    private final Map<String, Language> languages = new HashMap<String, Language>();
177    private Registry registry;
178    private List<LifecycleStrategy> lifecycleStrategies = new CopyOnWriteArrayList<LifecycleStrategy>();
179    private ManagementStrategy managementStrategy;
180    private ManagementMBeanAssembler managementMBeanAssembler;
181    private final List<RouteDefinition> routeDefinitions = new ArrayList<RouteDefinition>();
182    private final List<RestDefinition> restDefinitions = new ArrayList<RestDefinition>();
183    private RestConfiguration restConfiguration = new RestConfiguration();
184    private RestRegistry restRegistry = new DefaultRestRegistry();
185    private List<InterceptStrategy> interceptStrategies = new ArrayList<InterceptStrategy>();
186    private List<RoutePolicyFactory> routePolicyFactories = new ArrayList<RoutePolicyFactory>();
187
188    // special flags to control the first startup which can are special
189    private volatile boolean firstStartDone;
190    private volatile boolean doNotStartRoutesOnFirstStart;
191    private final ThreadLocal<Boolean> isStartingRoutes = new ThreadLocal<Boolean>();
192    private final ThreadLocal<Boolean> isSetupRoutes = new ThreadLocal<Boolean>();
193    private Boolean autoStartup = Boolean.TRUE;
194    private Boolean trace = Boolean.FALSE;
195    private Boolean messageHistory = Boolean.TRUE;
196    private Boolean streamCache = Boolean.FALSE;
197    private Boolean handleFault = Boolean.FALSE;
198    private Boolean disableJMX = Boolean.FALSE;
199    private Boolean lazyLoadTypeConverters = Boolean.FALSE;
200    private Boolean typeConverterStatisticsEnabled = Boolean.FALSE;
201    private Boolean useMDCLogging = Boolean.FALSE;
202    private Boolean useBreadcrumb = Boolean.TRUE;
203    private Boolean allowUseOriginalMessage = Boolean.TRUE;
204    private Long delay;
205    private ErrorHandlerFactory errorHandlerBuilder;
206    private final Object errorHandlerExecutorServiceLock = new Object();
207    private ScheduledExecutorService errorHandlerExecutorService;
208    private Map<String, DataFormatDefinition> dataFormats = new HashMap<String, DataFormatDefinition>();
209    private DataFormatResolver dataFormatResolver = new DefaultDataFormatResolver();
210    private Map<String, String> properties = new HashMap<String, String>();
211    private FactoryFinderResolver factoryFinderResolver = new DefaultFactoryFinderResolver();
212    private FactoryFinder defaultFactoryFinder;
213    private PropertiesComponent propertiesComponent;
214    private StreamCachingStrategy streamCachingStrategy;
215    private final Map<String, FactoryFinder> factories = new HashMap<String, FactoryFinder>();
216    private final Map<String, RouteService> routeServices = new LinkedHashMap<String, RouteService>();
217    private final Map<String, RouteService> suspendedRouteServices = new LinkedHashMap<String, RouteService>();
218    private ClassResolver classResolver = new DefaultClassResolver();
219    private PackageScanClassResolver packageScanClassResolver;
220    // we use a capacity of 100 per endpoint, so for the same endpoint we have at most 100 producers in the pool
221    // so if we have 6 endpoints in the pool, we can have 6 x 100 producers in total
222    private ServicePool<Endpoint, Producer> producerServicePool = new SharedProducerServicePool(100);
223    private NodeIdFactory nodeIdFactory = new DefaultNodeIdFactory();
224    private ProcessorFactory processorFactory;
225    private InterceptStrategy defaultTracer;
226    private InterceptStrategy defaultBacklogTracer;
227    private InterceptStrategy defaultBacklogDebugger;
228    private InflightRepository inflightRepository = new DefaultInflightRepository();
229    private RuntimeEndpointRegistry runtimeEndpointRegistry = new DefaultRuntimeEndpointRegistry();
230    private final List<RouteStartupOrder> routeStartupOrder = new ArrayList<RouteStartupOrder>();
231    // start auto assigning route ids using numbering 1000 and upwards
232    private int defaultRouteStartupOrder = 1000;
233    private ShutdownStrategy shutdownStrategy = new DefaultShutdownStrategy(this);
234    private ShutdownRoute shutdownRoute = ShutdownRoute.Default;
235    private ShutdownRunningTask shutdownRunningTask = ShutdownRunningTask.CompleteCurrentTaskOnly;
236    private ExecutorServiceManager executorServiceManager;
237    private Debugger debugger;
238    private UuidGenerator uuidGenerator = createDefaultUuidGenerator();
239    private UnitOfWorkFactory unitOfWorkFactory = new DefaultUnitOfWorkFactory();
240    private final StopWatch stopWatch = new StopWatch(false);
241    private Date startDate;
242
243    /**
244     * Creates the {@link CamelContext} using {@link JndiRegistry} as registry,
245     * but will silently fallback and use {@link SimpleRegistry} if JNDI cannot be used.
246     * <p/>
247     * Use one of the other constructors to force use an explicit registry / JNDI.
248     */
249    public DefaultCamelContext() {
250        this.executorServiceManager = new DefaultExecutorServiceManager(this);
251
252        // create endpoint registry at first since end users may access endpoints before CamelContext is started
253        this.endpoints = new EndpointRegistry(this);
254
255        // use WebSphere specific resolver if running on WebSphere
256        if (WebSpherePackageScanClassResolver.isWebSphereClassLoader(this.getClass().getClassLoader())) {
257            log.info("Using WebSphere specific PackageScanClassResolver");
258            packageScanClassResolver = new WebSpherePackageScanClassResolver("META-INF/services/org/apache/camel/TypeConverter");
259        } else {
260            packageScanClassResolver = new DefaultPackageScanClassResolver();
261        }
262
263        // setup management strategy first since end users may use it to add event notifiers
264        // using the management strategy before the CamelContext has been started
265        this.managementStrategy = createManagementStrategy();
266        this.managementMBeanAssembler = createManagementMBeanAssembler();
267
268        Container.Instance.manage(this);
269    }
270
271    /**
272     * Creates the {@link CamelContext} using the given JNDI context as the registry
273     *
274     * @param jndiContext the JNDI context
275     */
276    public DefaultCamelContext(Context jndiContext) {
277        this();
278        setJndiContext(jndiContext);
279    }
280
281    /**
282     * Creates the {@link CamelContext} using the given registry
283     *
284     * @param registry the registry
285     */
286    public DefaultCamelContext(Registry registry) {
287        this();
288        setRegistry(registry);
289    }
290
291    public String getName() {
292        return getNameStrategy().getName();
293    }
294
295    /**
296     * Sets the name of the this context.
297     *
298     * @param name the name
299     */
300    public void setName(String name) {
301        // use an explicit name strategy since an explicit name was provided to be used
302        this.nameStrategy = new ExplicitCamelContextNameStrategy(name);
303    }
304
305    public CamelContextNameStrategy getNameStrategy() {
306        return nameStrategy;
307    }
308
309    public void setNameStrategy(CamelContextNameStrategy nameStrategy) {
310        this.nameStrategy = nameStrategy;
311    }
312
313    public ManagementNameStrategy getManagementNameStrategy() {
314        return managementNameStrategy;
315    }
316
317    public void setManagementNameStrategy(ManagementNameStrategy managementNameStrategy) {
318        this.managementNameStrategy = managementNameStrategy;
319    }
320
321    public String getManagementName() {
322        return managementName;
323    }
324
325    public void setManagementName(String managementName) {
326        this.managementName = managementName;
327    }
328
329    public Component hasComponent(String componentName) {
330        return components.get(componentName);
331    }
332
333    public void addComponent(String componentName, final Component component) {
334        ObjectHelper.notNull(component, "component");
335        synchronized (components) {
336            if (components.containsKey(componentName)) {
337                throw new IllegalArgumentException("Cannot add component as its already previously added: " + componentName);
338            }
339            component.setCamelContext(this);
340            components.put(componentName, component);
341            for (LifecycleStrategy strategy : lifecycleStrategies) {
342                strategy.onComponentAdd(componentName, component);
343            }
344
345            // keep reference to properties component up to date
346            if (component instanceof PropertiesComponent && "properties".equals(componentName)) {
347                propertiesComponent = (PropertiesComponent) component;
348            }
349        }
350    }
351
352    public Component getComponent(String name) {
353        return getComponent(name, autoCreateComponents);
354    }
355
356    public Component getComponent(String name, boolean autoCreateComponents) {
357        // synchronize the look up and auto create so that 2 threads can't
358        // concurrently auto create the same component.
359        synchronized (components) {
360            Component component = components.get(name);
361            if (component == null && autoCreateComponents) {
362                try {
363                    if (log.isDebugEnabled()) {
364                        log.debug("Using ComponentResolver: {} to resolve component with name: {}", getComponentResolver(), name);
365                    }
366                    component = getComponentResolver().resolveComponent(name, this);
367                    if (component != null) {
368                        addComponent(name, component);
369                        if (isStarted() || isStarting()) {
370                            // If the component is looked up after the context is started, lets start it up.
371                            if (component instanceof Service) {
372                                startService((Service)component);
373                            }
374                        }
375                    }
376                } catch (Exception e) {
377                    throw new RuntimeCamelException("Cannot auto create component: " + name, e);
378                }
379            }
380            log.trace("getComponent({}) -> {}", name, component);
381            return component;
382        }
383    }
384
385    public <T extends Component> T getComponent(String name, Class<T> componentType) {
386        Component component = getComponent(name);
387        if (componentType.isInstance(component)) {
388            return componentType.cast(component);
389        } else {
390            String message;
391            if (component == null) {
392                message = "Did not find component given by the name: " + name;
393            } else {
394                message = "Found component of type: " + component.getClass() + " instead of expected: " + componentType;
395            }
396            throw new IllegalArgumentException(message);
397        }
398    }
399
400    public Component removeComponent(String componentName) {
401        synchronized (components) {
402            Component oldComponent = components.remove(componentName);
403            if (oldComponent != null) {
404                try {
405                    stopServices(oldComponent);
406                } catch (Exception e) {
407                    log.warn("Error stopping component " + oldComponent + ". This exception will be ignored.", e);
408                }
409                for (LifecycleStrategy strategy : lifecycleStrategies) {
410                    strategy.onComponentRemove(componentName, oldComponent);
411                }
412            }
413            // keep reference to properties component up to date
414            if (oldComponent != null && "properties".equals(componentName)) {
415                propertiesComponent = null;
416            }
417            return oldComponent;
418        }
419    }
420
421    // Endpoint Management Methods
422    // -----------------------------------------------------------------------
423
424    public Collection<Endpoint> getEndpoints() {
425        return new ArrayList<Endpoint>(endpoints.values());
426    }
427
428    public Map<String, Endpoint> getEndpointMap() {
429        Map<String, Endpoint> answer = new TreeMap<String, Endpoint>();
430        for (Map.Entry<EndpointKey, Endpoint> entry : endpoints.entrySet()) {
431            answer.put(entry.getKey().get(), entry.getValue());
432        }
433        return answer;
434    }
435
436    public Endpoint hasEndpoint(String uri) {
437        return endpoints.get(getEndpointKey(uri));
438    }
439
440    public Endpoint addEndpoint(String uri, Endpoint endpoint) throws Exception {
441        Endpoint oldEndpoint;
442
443        startService(endpoint);
444        oldEndpoint = endpoints.remove(getEndpointKey(uri));
445        for (LifecycleStrategy strategy : lifecycleStrategies) {
446            strategy.onEndpointAdd(endpoint);
447        }
448        addEndpointToRegistry(uri, endpoint);
449        if (oldEndpoint != null) {
450            stopServices(oldEndpoint);
451        }
452
453        return oldEndpoint;
454    }
455
456    public Collection<Endpoint> removeEndpoints(String uri) throws Exception {
457        Collection<Endpoint> answer = new ArrayList<Endpoint>();
458        Endpoint oldEndpoint = endpoints.remove(getEndpointKey(uri));
459        if (oldEndpoint != null) {
460            answer.add(oldEndpoint);
461            stopServices(oldEndpoint);
462        } else {
463            for (Map.Entry<EndpointKey, Endpoint> entry : endpoints.entrySet()) {
464                oldEndpoint = entry.getValue();
465                if (EndpointHelper.matchEndpoint(this, oldEndpoint.getEndpointUri(), uri)) {
466                    try {
467                        stopServices(oldEndpoint);
468                    } catch (Exception e) {
469                        log.warn("Error stopping endpoint " + oldEndpoint + ". This exception will be ignored.", e);
470                    }
471                    answer.add(oldEndpoint);
472                    endpoints.remove(entry.getKey());
473                }
474            }
475        }
476
477        // notify lifecycle its being removed
478        for (Endpoint endpoint : answer) {
479            for (LifecycleStrategy strategy : lifecycleStrategies) {
480                strategy.onEndpointRemove(endpoint);
481            }
482        }
483
484        return answer;
485    }
486
487    public Endpoint getEndpoint(String uri) {
488        ObjectHelper.notEmpty(uri, "uri");
489
490        log.trace("Getting endpoint with uri: {}", uri);
491
492        // in case path has property placeholders then try to let property component resolve those
493        try {
494            uri = resolvePropertyPlaceholders(uri);
495        } catch (Exception e) {
496            throw new ResolveEndpointFailedException(uri, e);
497        }
498
499        final String rawUri = uri;
500
501        // normalize uri so we can do endpoint hits with minor mistakes and parameters is not in the same order
502        uri = normalizeEndpointUri(uri);
503
504        log.trace("Getting endpoint with raw uri: {}, normalized uri: {}", rawUri, uri);
505
506        Endpoint answer;
507        String scheme = null;
508        EndpointKey key = getEndpointKey(uri);
509        answer = endpoints.get(key);
510        if (answer == null) {
511            try {
512                // Use the URI prefix to find the component.
513                String splitURI[] = ObjectHelper.splitOnCharacter(uri, ":", 2);
514                if (splitURI[1] != null) {
515                    scheme = splitURI[0];
516                    log.trace("Endpoint uri: {} is from component with name: {}", uri, scheme);
517                    Component component = getComponent(scheme);
518
519                    // Ask the component to resolve the endpoint.
520                    if (component != null) {
521                        log.trace("Creating endpoint from uri: {} using component: {}", uri, component);
522
523                        // Have the component create the endpoint if it can.
524                        if (component.useRawUri()) {
525                            answer = component.createEndpoint(rawUri);
526                        } else {
527                            answer = component.createEndpoint(uri);
528                        }
529
530                        if (answer != null && log.isDebugEnabled()) {
531                            log.debug("{} converted to endpoint: {} by component: {}", new Object[]{URISupport.sanitizeUri(uri), answer, component});
532                        }
533                    }
534                }
535
536                if (answer == null) {
537                    // no component then try in registry and elsewhere
538                    answer = createEndpoint(uri);
539                    log.trace("No component to create endpoint from uri: {} fallback lookup in registry -> {}", uri, answer);
540                }
541
542                if (answer != null) {
543                    addService(answer);
544                    answer = addEndpointToRegistry(uri, answer);
545                }
546            } catch (Exception e) {
547                throw new ResolveEndpointFailedException(uri, e);
548            }
549        }
550
551        // unknown scheme
552        if (answer == null && scheme != null) {
553            throw new ResolveEndpointFailedException(uri, "No component found with scheme: " + scheme);
554        }
555
556        return answer;
557    }
558
559    public <T extends Endpoint> T getEndpoint(String name, Class<T> endpointType) {
560        Endpoint endpoint = getEndpoint(name);
561        if (endpoint == null) {
562            throw new NoSuchEndpointException(name);
563        }
564        if (endpoint instanceof InterceptSendToEndpoint) {
565            endpoint = ((InterceptSendToEndpoint) endpoint).getDelegate();
566        }
567        if (endpointType.isInstance(endpoint)) {
568            return endpointType.cast(endpoint);
569        } else {
570            throw new IllegalArgumentException("The endpoint is not of type: " + endpointType
571                + " but is: " + endpoint.getClass().getCanonicalName());
572        }
573    }
574
575    public void addRegisterEndpointCallback(EndpointStrategy strategy) {
576        if (!endpointStrategies.contains(strategy)) {
577            // let it be invoked for already registered endpoints so it can catch-up.
578            endpointStrategies.add(strategy);
579            for (Endpoint endpoint : getEndpoints()) {
580                Endpoint newEndpoint = strategy.registerEndpoint(endpoint.getEndpointUri(), endpoint);
581                if (newEndpoint != null) {
582                    // put will replace existing endpoint with the new endpoint
583                    endpoints.put(getEndpointKey(endpoint.getEndpointUri()), newEndpoint);
584                }
585            }
586        }
587    }
588
589    /**
590     * Strategy to add the given endpoint to the internal endpoint registry
591     *
592     * @param uri      uri of the endpoint
593     * @param endpoint the endpoint to add
594     * @return the added endpoint
595     */
596    protected Endpoint addEndpointToRegistry(String uri, Endpoint endpoint) {
597        ObjectHelper.notEmpty(uri, "uri");
598        ObjectHelper.notNull(endpoint, "endpoint");
599
600        // if there is endpoint strategies, then use the endpoints they return
601        // as this allows to intercept endpoints etc.
602        for (EndpointStrategy strategy : endpointStrategies) {
603            endpoint = strategy.registerEndpoint(uri, endpoint);
604        }
605        endpoints.put(getEndpointKey(uri, endpoint), endpoint);
606        return endpoint;
607    }
608
609    /**
610     * Normalize uri so we can do endpoint hits with minor mistakes and parameters is not in the same order.
611     *
612     * @param uri the uri
613     * @return normalized uri
614     * @throws ResolveEndpointFailedException if uri cannot be normalized
615     */
616    protected static String normalizeEndpointUri(String uri) {
617        try {
618            uri = URISupport.normalizeUri(uri);
619        } catch (Exception e) {
620            throw new ResolveEndpointFailedException(uri, e);
621        }
622        return uri;
623    }
624
625    /**
626     * Gets the endpoint key to use for lookup or whe adding endpoints to the {@link EndpointRegistry}
627     *
628     * @param uri the endpoint uri
629     * @return the key
630     */
631    protected EndpointKey getEndpointKey(String uri) {
632        return new EndpointKey(uri);
633    }
634
635    /**
636     * Gets the endpoint key to use for lookup or whe adding endpoints to the {@link EndpointRegistry}
637     *
638     * @param uri      the endpoint uri
639     * @param endpoint the endpoint
640     * @return the key
641     */
642    protected EndpointKey getEndpointKey(String uri, Endpoint endpoint) {
643        if (endpoint != null && !endpoint.isSingleton()) {
644            int counter = endpointKeyCounter.incrementAndGet();
645            return new EndpointKey(uri + ":" + counter);
646        } else {
647            return new EndpointKey(uri);
648        }
649    }
650
651    // Route Management Methods
652    // -----------------------------------------------------------------------
653
654    public List<RouteStartupOrder> getRouteStartupOrder() {
655        return routeStartupOrder;
656    }
657
658    public List<Route> getRoutes() {
659        // lets return a copy of the collection as objects are removed later when services are stopped
660        if (routes.isEmpty()) {
661            return Collections.emptyList();
662        } else {
663            synchronized (routes) {
664                return new ArrayList<Route>(routes);
665            }
666        }
667    }
668
669    public Route getRoute(String id) {
670        for (Route route : getRoutes()) {
671            if (route.getId().equals(id)) {
672                return route;
673            }
674        }
675        return null;
676    }
677
678    @Deprecated
679    public void setRoutes(List<Route> routes) {
680        throw new UnsupportedOperationException("Overriding existing routes is not supported yet, use addRouteCollection instead");
681    }
682
683    void removeRouteCollection(Collection<Route> routes) {
684        synchronized (this.routes) {
685            this.routes.removeAll(routes);
686        }
687    }
688
689    void addRouteCollection(Collection<Route> routes) throws Exception {
690        synchronized (this.routes) {
691            this.routes.addAll(routes);
692        }
693    }
694
695    public void addRoutes(RoutesBuilder builder) throws Exception {
696        log.debug("Adding routes from builder: {}", builder);
697        // lets now add the routes from the builder
698        builder.addRoutesToCamelContext(this);
699    }
700
701    public synchronized RoutesDefinition loadRoutesDefinition(InputStream is) throws Exception {
702        // load routes using JAXB
703        if (jaxbContext == null) {
704            // must use classloader from CamelContext to have JAXB working
705            jaxbContext = JAXBContext.newInstance(Constants.JAXB_CONTEXT_PACKAGES, CamelContext.class.getClassLoader());
706        }
707
708        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
709        Object result = unmarshaller.unmarshal(is);
710
711        if (result == null) {
712            throw new IOException("Cannot unmarshal to routes using JAXB from input stream: " + is);
713        }
714
715        // can either be routes or a single route
716        RoutesDefinition answer;
717        if (result instanceof RouteDefinition) {
718            RouteDefinition route = (RouteDefinition) result;
719            answer = new RoutesDefinition();
720            answer.getRoutes().add(route);
721        } else if (result instanceof RoutesDefinition) {
722            answer = (RoutesDefinition) result;
723        } else {
724            throw new IllegalArgumentException("Unmarshalled object is an unsupported type: " + ObjectHelper.className(result) + " -> " + result);
725        }
726
727        return answer;
728    }
729
730    public synchronized void addRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
731        if (routeDefinitions == null || routeDefinitions.isEmpty()) {
732            return;
733        }
734        for (RouteDefinition routeDefinition : routeDefinitions) {
735            removeRouteDefinition(routeDefinition);
736        }
737        this.routeDefinitions.addAll(routeDefinitions);
738        if (shouldStartRoutes()) {
739            startRouteDefinitions(routeDefinitions);
740        }
741    }
742
743    public void addRouteDefinition(RouteDefinition routeDefinition) throws Exception {
744        addRouteDefinitions(Arrays.asList(routeDefinition));
745    }
746
747    /**
748     * Removes the route definition with the given key.
749     *
750     * @return true if one or more routes was removed
751     */
752    protected boolean removeRouteDefinition(String key) {
753        boolean answer = false;
754        Iterator<RouteDefinition> iter = routeDefinitions.iterator();
755        while (iter.hasNext()) {
756            RouteDefinition route = iter.next();
757            if (route.idOrCreate(nodeIdFactory).equals(key)) {
758                iter.remove();
759                answer = true;
760            }
761        }
762        return answer;
763    }
764
765    public synchronized void removeRouteDefinitions(Collection<RouteDefinition> routeDefinitions) throws Exception {
766        for (RouteDefinition routeDefinition : routeDefinitions) {
767            removeRouteDefinition(routeDefinition);
768        }
769    }
770
771    public synchronized void removeRouteDefinition(RouteDefinition routeDefinition) throws Exception {
772        String id = routeDefinition.getId();
773        if (id != null) {
774            // remove existing route
775            stopRoute(id);
776            removeRoute(id);
777        }
778        this.routeDefinitions.remove(routeDefinition);
779    }
780
781    public ServiceStatus getRouteStatus(String key) {
782        RouteService routeService = routeServices.get(key);
783        if (routeService != null) {
784            return routeService.getStatus();
785        }
786        return null;
787    }
788
789    public void startRoute(RouteDefinition route) throws Exception {
790        // assign ids to the routes and validate that the id's is all unique
791        RouteDefinitionHelper.forceAssignIds(this, routeDefinitions);
792        String duplicate = RouteDefinitionHelper.validateUniqueIds(route, routeDefinitions);
793        if (duplicate != null) {
794            throw new FailedToStartRouteException(route.getId(), "duplicate id detected: " + duplicate + ". Please correct ids to be unique among all your routes.");
795        }
796
797        // indicate we are staring the route using this thread so
798        // we are able to query this if needed
799        isStartingRoutes.set(true);
800        try {
801            // must ensure route is prepared, before we can start it
802            route.prepare(this);
803
804            List<Route> routes = new ArrayList<Route>();
805            List<RouteContext> routeContexts = route.addRoutes(this, routes);
806            RouteService routeService = new RouteService(this, route, routeContexts, routes);
807            startRouteService(routeService, true);
808        } finally {
809            // we are done staring routes
810            isStartingRoutes.remove();
811        }
812    }
813
814    public boolean isStartingRoutes() {
815        Boolean answer = isStartingRoutes.get();
816        return answer != null && answer;
817    }
818
819    public boolean isSetupRoutes() {
820        Boolean answer = isSetupRoutes.get();
821        return answer != null && answer;
822    }
823
824    public void stopRoute(RouteDefinition route) throws Exception {
825        stopRoute(route.idOrCreate(nodeIdFactory));
826    }
827
828    public void startAllRoutes() throws Exception {
829        doStartOrResumeRoutes(routeServices, true, true, false, false);
830    }
831
832    public synchronized void startRoute(String routeId) throws Exception {
833        RouteService routeService = routeServices.get(routeId);
834        if (routeService != null) {
835            startRouteService(routeService, false);
836        }
837    }
838
839    public synchronized void resumeRoute(String routeId) throws Exception {
840        if (!routeSupportsSuspension(routeId)) {
841            // start route if suspension is not supported
842            startRoute(routeId);
843            return;
844        }
845
846        RouteService routeService = routeServices.get(routeId);
847        if (routeService != null) {
848            resumeRouteService(routeService);
849        }
850    }
851
852    public synchronized boolean stopRoute(String routeId, long timeout, TimeUnit timeUnit, boolean abortAfterTimeout) throws Exception {
853        RouteService routeService = routeServices.get(routeId);
854        if (routeService != null) {
855            RouteStartupOrder route = new DefaultRouteStartupOrder(1, routeService.getRoutes().iterator().next(), routeService);
856
857            boolean completed = getShutdownStrategy().shutdown(this, route, timeout, timeUnit, abortAfterTimeout);
858            if (completed) {
859                // must stop route service as well
860                stopRouteService(routeService, false);
861            } else {
862                // shutdown was aborted, make sure route is re-started properly
863                startRouteService(routeService, false);
864            }
865            return completed;
866        }
867        return false;
868    }
869
870    public synchronized void stopRoute(String routeId) throws Exception {
871        RouteService routeService = routeServices.get(routeId);
872        if (routeService != null) {
873            List<RouteStartupOrder> routes = new ArrayList<RouteStartupOrder>(1);
874            RouteStartupOrder order = new DefaultRouteStartupOrder(1, routeService.getRoutes().iterator().next(), routeService);
875            routes.add(order);
876
877            getShutdownStrategy().shutdown(this, routes);
878            // must stop route service as well
879            stopRouteService(routeService, false);
880        }
881    }
882
883    public synchronized void stopRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception {
884        RouteService routeService = routeServices.get(routeId);
885        if (routeService != null) {
886            List<RouteStartupOrder> routes = new ArrayList<RouteStartupOrder>(1);
887            RouteStartupOrder order = new DefaultRouteStartupOrder(1, routeService.getRoutes().iterator().next(), routeService);
888            routes.add(order);
889
890            getShutdownStrategy().shutdown(this, routes, timeout, timeUnit);
891            // must stop route service as well
892            stopRouteService(routeService, false);
893        }
894    }
895
896    public synchronized void shutdownRoute(String routeId) throws Exception {
897        RouteService routeService = routeServices.get(routeId);
898        if (routeService != null) {
899            List<RouteStartupOrder> routes = new ArrayList<RouteStartupOrder>(1);
900            RouteStartupOrder order = new DefaultRouteStartupOrder(1, routeService.getRoutes().iterator().next(), routeService);
901            routes.add(order);
902
903            getShutdownStrategy().shutdown(this, routes);
904            // must stop route service as well (and remove the routes from management)
905            stopRouteService(routeService, true);
906        }
907    }
908
909    public synchronized void shutdownRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception {
910        RouteService routeService = routeServices.get(routeId);
911        if (routeService != null) {
912            List<RouteStartupOrder> routes = new ArrayList<RouteStartupOrder>(1);
913            RouteStartupOrder order = new DefaultRouteStartupOrder(1, routeService.getRoutes().iterator().next(), routeService);
914            routes.add(order);
915
916            getShutdownStrategy().shutdown(this, routes, timeout, timeUnit);
917            // must stop route service as well (and remove the routes from management)
918            stopRouteService(routeService, true);
919        }
920    }
921
922    public synchronized boolean removeRoute(String routeId) throws Exception {
923        // remove the route from ErrorHandlerBuilder if possible
924        if (getErrorHandlerBuilder() instanceof ErrorHandlerBuilderSupport) {
925            ErrorHandlerBuilderSupport builder = (ErrorHandlerBuilderSupport)getErrorHandlerBuilder();
926            builder.removeOnExceptionList(routeId);
927        }
928        RouteService routeService = routeServices.get(routeId);
929        if (routeService != null) {
930            if (getRouteStatus(routeId).isStopped()) {
931                routeService.setRemovingRoutes(true);
932                shutdownRouteService(routeService);
933                removeRouteDefinition(routeId);
934                routeServices.remove(routeId);
935                // remove route from startup order as well, as it was removed
936                Iterator<RouteStartupOrder> it = routeStartupOrder.iterator();
937                while (it.hasNext()) {
938                    RouteStartupOrder order = it.next();
939                    if (order.getRoute().getId().equals(routeId)) {
940                        it.remove();
941                    }
942                }
943                return true;
944            } else {
945                return false;
946            }
947        }
948        return false;
949    }
950
951    public synchronized void suspendRoute(String routeId) throws Exception {
952        if (!routeSupportsSuspension(routeId)) {
953            // stop if we suspend is not supported
954            stopRoute(routeId);
955            return;
956        }
957
958        RouteService routeService = routeServices.get(routeId);
959        if (routeService != null) {
960            List<RouteStartupOrder> routes = new ArrayList<RouteStartupOrder>(1);
961            RouteStartupOrder order = new DefaultRouteStartupOrder(1, routeService.getRoutes().iterator().next(), routeService);
962            routes.add(order);
963
964            getShutdownStrategy().suspend(this, routes);
965            // must suspend route service as well
966            suspendRouteService(routeService);
967        }
968    }
969
970    public synchronized void suspendRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception {
971        if (!routeSupportsSuspension(routeId)) {
972            stopRoute(routeId, timeout, timeUnit);
973            return;
974        }
975
976        RouteService routeService = routeServices.get(routeId);
977        if (routeService != null) {
978            List<RouteStartupOrder> routes = new ArrayList<RouteStartupOrder>(1);
979            RouteStartupOrder order = new DefaultRouteStartupOrder(1, routeService.getRoutes().iterator().next(), routeService);
980            routes.add(order);
981
982            getShutdownStrategy().suspend(this, routes, timeout, timeUnit);
983            // must suspend route service as well
984            suspendRouteService(routeService);
985        }
986    }
987
988    public void addService(Object object) throws Exception {
989        addService(object, true);
990    }
991
992    public void addService(Object object, boolean closeOnShutdown) throws Exception {
993        doAddService(object, closeOnShutdown);
994    }
995
996    private void doAddService(Object object, boolean closeOnShutdown) throws Exception {
997        // inject CamelContext
998        if (object instanceof CamelContextAware) {
999            CamelContextAware aware = (CamelContextAware) object;
1000            aware.setCamelContext(this);
1001        }
1002
1003        if (object instanceof Service) {
1004            Service service = (Service) object;
1005
1006            for (LifecycleStrategy strategy : lifecycleStrategies) {
1007                if (service instanceof Endpoint) {
1008                    // use specialized endpoint add
1009                    strategy.onEndpointAdd((Endpoint) service);
1010                } else {
1011                    strategy.onServiceAdd(this, service, null);
1012                }
1013            }
1014
1015            // only add to services to close if its a singleton
1016            // otherwise we could for example end up with a lot of prototype scope endpoints
1017            boolean singleton = true; // assume singleton by default
1018            if (service instanceof IsSingleton) {
1019                singleton = ((IsSingleton) service).isSingleton();
1020            }
1021            // do not add endpoints as they have their own list
1022            if (singleton && !(service instanceof Endpoint)) {
1023                // only add to list of services to close if its not already there
1024                if (closeOnShutdown && !hasService(service)) {
1025                    servicesToClose.add(service);
1026                }
1027            }
1028        }
1029
1030        // and then ensure service is started (as stated in the javadoc)
1031        if (object instanceof Service) {
1032            startService((Service)object);
1033        } else if (object instanceof Collection<?>) {
1034            startServices((Collection<?>)object);
1035        }
1036    }
1037
1038    public boolean removeService(Object object) throws Exception {
1039        if (object instanceof Service) {
1040            Service service = (Service) object;
1041
1042            for (LifecycleStrategy strategy : lifecycleStrategies) {
1043                if (service instanceof Endpoint) {
1044                    // use specialized endpoint remove
1045                    strategy.onEndpointRemove((Endpoint) service);
1046                } else {
1047                    strategy.onServiceRemove(this, service, null);
1048                }
1049            }
1050            return servicesToClose.remove(service);
1051        }
1052        return false;
1053    }
1054
1055    public boolean hasService(Object object) {
1056        if (object instanceof Service) {
1057            Service service = (Service) object;
1058            return servicesToClose.contains(service);
1059        }
1060        return false;
1061    }
1062
1063    @Override
1064    public <T> T hasService(Class<T> type) {
1065        for (Service service : servicesToClose) {
1066            if (type.isInstance(service)) {
1067                return type.cast(service);
1068            }
1069        }
1070        return null;
1071    }
1072
1073    public void addStartupListener(StartupListener listener) throws Exception {
1074        // either add to listener so we can invoke then later when CamelContext has been started
1075        // or invoke the callback right now
1076        if (isStarted()) {
1077            listener.onCamelContextStarted(this, true);
1078        } else {
1079            startupListeners.add(listener);
1080        }
1081    }
1082
1083    public Map<String, Properties> findComponents() throws LoadPropertiesException, IOException {
1084        return CamelContextHelper.findComponents(this);
1085    }
1086
1087    public String getComponentDocumentation(String componentName) throws IOException {
1088        String packageName = sanitizeComponentName(componentName);
1089        String path = CamelContextHelper.COMPONENT_DOCUMENTATION_PREFIX + packageName + "/" + componentName + ".html";
1090        ClassResolver resolver = getClassResolver();
1091        InputStream inputStream = resolver.loadResourceAsStream(path);
1092        log.debug("Loading component documentation for: {} using class resolver: {} -> {}", new Object[]{componentName, resolver, inputStream});
1093        if (inputStream != null) {
1094            try {
1095                return IOHelper.loadText(inputStream);
1096            } finally {
1097                IOHelper.close(inputStream);
1098            }
1099        }
1100        return null;
1101    }
1102
1103    /**
1104     * Sanitizes the component name by removing dash (-) in the name, when using the component name to load
1105     * resources from the classpath.
1106     */
1107    private static String sanitizeComponentName(String componentName) {
1108        // the ftp components are in a special package
1109        if ("ftp".equals(componentName) || "ftps".equals(componentName) || "sftp".equals(componentName)) {
1110            return "file/remote";
1111        } else if ("cxfrs".equals(componentName)) {
1112            return "cxf/jaxrs";
1113        } else if ("gauth".equals(componentName) || "ghttp".equals(componentName) || "glogin".equals(componentName)
1114                || "gmail".equals(componentName) || "gtask".equals(componentName)) {
1115            return "gae/" + componentName.substring(1);
1116        } else if ("atmosphere-websocket".equals(componentName)) {
1117            return "atmosphere/websocket";
1118        } else if ("netty-http".equals(componentName)) {
1119            return "netty/http";
1120        } else if ("netty4-http".equals(componentName)) {
1121            return "netty4/http";
1122        }
1123        return componentName.replaceAll("-", "");
1124    }
1125
1126    public String createRouteStaticEndpointJson(String routeId) {
1127        // lets include dynamic as well as we want as much data as possible
1128        return createRouteStaticEndpointJson(routeId, true);
1129    }
1130
1131    public String createRouteStaticEndpointJson(String routeId, boolean includeDynamic) {
1132        List<RouteDefinition> routes = new ArrayList<RouteDefinition>();
1133        if (routeId != null) {
1134            RouteDefinition route = getRouteDefinition(routeId);
1135            if (route == null) {
1136                throw new IllegalArgumentException("Route with id " + routeId + " does not exist");
1137            }
1138            routes.add(route);
1139        } else {
1140            routes.addAll(getRouteDefinitions());
1141        }
1142
1143        StringBuilder buffer = new StringBuilder("{\n  \"routes\": {");
1144        boolean firstRoute = true;
1145        for (RouteDefinition route : routes) {
1146            if (!firstRoute) {
1147                buffer.append("\n    },");
1148            } else {
1149                firstRoute = false;
1150            }
1151
1152            String id = route.getId();
1153            buffer.append("\n    \"" + id + "\": {");
1154            buffer.append("\n      \"inputs\": [");
1155            // for inputs we do not need to check dynamic as we have the data from the route definition
1156            Set<String> inputs = RouteDefinitionHelper.gatherAllStaticEndpointUris(this, route, true, false);
1157            boolean first = true;
1158            for (String input : inputs) {
1159                if (!first) {
1160                    buffer.append(",");
1161                } else {
1162                    first = false;
1163                }
1164                buffer.append("\n        ");
1165                buffer.append(StringHelper.toJson("uri", input, true));
1166            }
1167            buffer.append("\n      ]");
1168
1169            buffer.append(",");
1170            buffer.append("\n      \"outputs\": [");
1171            Set<String> outputs = RouteDefinitionHelper.gatherAllEndpointUris(this, route, false, true, includeDynamic);
1172            first = true;
1173            for (String output : outputs) {
1174                if (!first) {
1175                    buffer.append(",");
1176                } else {
1177                    first = false;
1178                }
1179                buffer.append("\n        ");
1180                buffer.append(StringHelper.toJson("uri", output, true));
1181            }
1182            buffer.append("\n      ]");
1183        }
1184        if (!firstRoute) {
1185            buffer.append("\n    }");
1186        }
1187        buffer.append("\n  }\n}\n");
1188
1189        return buffer.toString();
1190    }
1191
1192    // Helper methods
1193    // -----------------------------------------------------------------------
1194
1195    public Language resolveLanguage(String language) {
1196        Language answer;
1197        synchronized (languages) {
1198            answer = languages.get(language);
1199
1200            // check if the language is singleton, if so return the shared instance
1201            if (answer instanceof IsSingleton) {
1202                boolean singleton = ((IsSingleton) answer).isSingleton();
1203                if (singleton) {
1204                    return answer;
1205                }
1206            }
1207
1208            // language not known or not singleton, then use resolver
1209            answer = getLanguageResolver().resolveLanguage(language, this);
1210
1211            // inject CamelContext if aware
1212            if (answer != null) {
1213                if (answer instanceof CamelContextAware) {
1214                    ((CamelContextAware) answer).setCamelContext(this);
1215                }
1216                if (answer instanceof Service) {
1217                    try {
1218                        startService((Service) answer);
1219                    } catch (Exception e) {
1220                        throw ObjectHelper.wrapRuntimeCamelException(e);
1221                    }
1222                }
1223
1224                languages.put(language, answer);
1225            }
1226        }
1227
1228        return answer;
1229    }
1230
1231    public String getPropertyPrefixToken() {
1232        PropertiesComponent pc = getPropertiesComponent();
1233
1234        if (pc != null) {
1235            return pc.getPrefixToken();
1236        } else {
1237            return null;
1238        }
1239    }
1240
1241    public String getPropertySuffixToken() {
1242        PropertiesComponent pc = getPropertiesComponent();
1243
1244        if (pc != null) {
1245            return pc.getSuffixToken();
1246        } else {
1247            return null;
1248        }
1249    }
1250
1251    public String resolvePropertyPlaceholders(String text) throws Exception {
1252        // While it is more efficient to only do the lookup if we are sure we need the component,
1253        // with custom tokens, we cannot know if the URI contains a property or not without having
1254        // the component.  We also lose fail-fast behavior for the missing component with this change.
1255        PropertiesComponent pc = getPropertiesComponent();
1256
1257        // Do not parse uris that are designated for the properties component as it will handle that itself
1258        if (text != null && !text.startsWith("properties:")) {
1259            // No component, assume default tokens.
1260            if (pc == null && text.contains(PropertiesComponent.DEFAULT_PREFIX_TOKEN)) {
1261                // lookup existing properties component, or force create a new default component
1262                pc = (PropertiesComponent) CamelContextHelper.lookupPropertiesComponent(this, true);
1263            }
1264
1265            if (pc != null && text.contains(pc.getPrefixToken())) {
1266                // the parser will throw exception if property key was not found
1267                String answer = pc.parseUri(text);
1268                log.debug("Resolved text: {} -> {}", text, answer);
1269                return answer;
1270            }
1271        }
1272
1273        // return original text as is
1274        return text;
1275    }
1276
1277    // Properties
1278    // -----------------------------------------------------------------------
1279
1280    public TypeConverter getTypeConverter() {
1281        if (typeConverter == null) {
1282            synchronized (this) {
1283                // we can synchronize on this as there is only one instance
1284                // of the camel context (its the container)
1285                typeConverter = createTypeConverter();
1286                try {
1287                    // must add service eager
1288                    addService(typeConverter);
1289                } catch (Exception e) {
1290                    throw ObjectHelper.wrapRuntimeCamelException(e);
1291                }
1292            }
1293        }
1294        return typeConverter;
1295    }
1296
1297    public void setTypeConverter(TypeConverter typeConverter) {
1298        this.typeConverter = typeConverter;
1299        try {
1300            // must add service eager
1301            addService(typeConverter);
1302        } catch (Exception e) {
1303            throw ObjectHelper.wrapRuntimeCamelException(e);
1304        }
1305    }
1306
1307    public TypeConverterRegistry getTypeConverterRegistry() {
1308        if (typeConverterRegistry == null) {
1309            // init type converter as its lazy
1310            if (typeConverter == null) {
1311                getTypeConverter();
1312            }
1313            if (typeConverter instanceof TypeConverterRegistry) {
1314                typeConverterRegistry = (TypeConverterRegistry) typeConverter;
1315            }
1316        }
1317        return typeConverterRegistry;
1318    }
1319
1320    public void setTypeConverterRegistry(TypeConverterRegistry typeConverterRegistry) {
1321        this.typeConverterRegistry = typeConverterRegistry;
1322    }
1323
1324    public Injector getInjector() {
1325        if (injector == null) {
1326            injector = createInjector();
1327        }
1328        return injector;
1329    }
1330
1331    public void setInjector(Injector injector) {
1332        this.injector = injector;
1333    }
1334
1335    public ManagementMBeanAssembler getManagementMBeanAssembler() {
1336        return managementMBeanAssembler;
1337    }
1338
1339    public void setManagementMBeanAssembler(ManagementMBeanAssembler managementMBeanAssembler) {
1340        this.managementMBeanAssembler = managementMBeanAssembler;
1341    }
1342
1343    public ComponentResolver getComponentResolver() {
1344        if (componentResolver == null) {
1345            componentResolver = createComponentResolver();
1346        }
1347        return componentResolver;
1348    }
1349
1350    public void setComponentResolver(ComponentResolver componentResolver) {
1351        this.componentResolver = componentResolver;
1352    }
1353
1354    public LanguageResolver getLanguageResolver() {
1355        if (languageResolver == null) {
1356            languageResolver = new DefaultLanguageResolver();
1357        }
1358        return languageResolver;
1359    }
1360
1361    public void setLanguageResolver(LanguageResolver languageResolver) {
1362        this.languageResolver = languageResolver;
1363    }
1364
1365    public boolean isAutoCreateComponents() {
1366        return autoCreateComponents;
1367    }
1368
1369    public void setAutoCreateComponents(boolean autoCreateComponents) {
1370        this.autoCreateComponents = autoCreateComponents;
1371    }
1372
1373    public Registry getRegistry() {
1374        if (registry == null) {
1375            registry = createRegistry();
1376            setRegistry(registry);
1377        }
1378        return registry;
1379    }
1380
1381    public <T> T getRegistry(Class<T> type) {
1382        Registry reg = getRegistry();
1383
1384        // unwrap the property placeholder delegate
1385        if (reg instanceof PropertyPlaceholderDelegateRegistry) {
1386            reg = ((PropertyPlaceholderDelegateRegistry) reg).getRegistry();
1387        }
1388
1389        if (type.isAssignableFrom(reg.getClass())) {
1390            return type.cast(reg);
1391        } else if (reg instanceof CompositeRegistry) {
1392            List<Registry> list = ((CompositeRegistry) reg).getRegistryList();
1393            for (Registry r : list) {
1394                if (type.isAssignableFrom(r.getClass())) {
1395                    return type.cast(r);
1396                }
1397            }
1398        }
1399        return null;
1400    }
1401
1402    /**
1403     * Sets the registry to the given JNDI context
1404     *
1405     * @param jndiContext is the JNDI context to use as the registry
1406     * @see #setRegistry(org.apache.camel.spi.Registry)
1407     */
1408    public void setJndiContext(Context jndiContext) {
1409        setRegistry(new JndiRegistry(jndiContext));
1410    }
1411
1412    public void setRegistry(Registry registry) {
1413        // wrap the registry so we always do property placeholder lookups
1414        if (!(registry instanceof PropertyPlaceholderDelegateRegistry)) {
1415            registry = new PropertyPlaceholderDelegateRegistry(this, registry);
1416        }
1417        this.registry = registry;
1418    }
1419
1420    public List<LifecycleStrategy> getLifecycleStrategies() {
1421        return lifecycleStrategies;
1422    }
1423
1424    public void setLifecycleStrategies(List<LifecycleStrategy> lifecycleStrategies) {
1425        this.lifecycleStrategies = lifecycleStrategies;
1426    }
1427
1428    public void addLifecycleStrategy(LifecycleStrategy lifecycleStrategy) {
1429        this.lifecycleStrategies.add(lifecycleStrategy);
1430    }
1431
1432    public void setupRoutes(boolean done) {
1433        if (done) {
1434            isSetupRoutes.remove();
1435        } else {
1436            isSetupRoutes.set(true);
1437        }
1438    }
1439
1440    public synchronized List<RouteDefinition> getRouteDefinitions() {
1441        return routeDefinitions;
1442    }
1443
1444    public synchronized RouteDefinition getRouteDefinition(String id) {
1445        for (RouteDefinition route : routeDefinitions) {
1446            if (route.idOrCreate(nodeIdFactory).equals(id)) {
1447                return route;
1448            }
1449        }
1450        return null;
1451    }
1452
1453    public synchronized List<RestDefinition> getRestDefinitions() {
1454        return restDefinitions;
1455    }
1456
1457    public void addRestDefinitions(Collection<RestDefinition> restDefinitions) throws Exception {
1458        if (restDefinitions == null || restDefinitions.isEmpty()) {
1459            return;
1460        }
1461
1462        this.restDefinitions.addAll(restDefinitions);
1463    }
1464
1465    public RestConfiguration getRestConfiguration() {
1466        return restConfiguration;
1467    }
1468
1469    public void setRestConfiguration(RestConfiguration restConfiguration) {
1470        this.restConfiguration = restConfiguration;
1471    }
1472
1473    public List<InterceptStrategy> getInterceptStrategies() {
1474        return interceptStrategies;
1475    }
1476
1477    public void setInterceptStrategies(List<InterceptStrategy> interceptStrategies) {
1478        this.interceptStrategies = interceptStrategies;
1479    }
1480
1481    public void addInterceptStrategy(InterceptStrategy interceptStrategy) {
1482        getInterceptStrategies().add(interceptStrategy);
1483
1484        // for backwards compatible or if user add them here instead of the setXXX methods
1485
1486        if (interceptStrategy instanceof Tracer) {
1487            setTracing(true);
1488        } else if (interceptStrategy instanceof HandleFault) {
1489            setHandleFault(true);
1490        } else if (interceptStrategy instanceof StreamCaching) {
1491            setStreamCaching(true);
1492        } else if (interceptStrategy instanceof Delayer) {
1493            setDelayer(((Delayer)interceptStrategy).getDelay());
1494        }
1495    }
1496
1497    public List<RoutePolicyFactory> getRoutePolicyFactories() {
1498        return routePolicyFactories;
1499    }
1500
1501    public void setRoutePolicyFactories(List<RoutePolicyFactory> routePolicyFactories) {
1502        this.routePolicyFactories = routePolicyFactories;
1503    }
1504
1505    public void addRoutePolicyFactory(RoutePolicyFactory routePolicyFactory) {
1506        getRoutePolicyFactories().add(routePolicyFactory);
1507    }
1508
1509    public void setStreamCaching(Boolean cache) {
1510        this.streamCache = cache;
1511    }
1512
1513    public Boolean isStreamCaching() {
1514        return streamCache;
1515    }
1516
1517    public void setTracing(Boolean tracing) {
1518        this.trace = tracing;
1519    }
1520
1521    public Boolean isTracing() {
1522        return trace;
1523    }
1524
1525    public Boolean isMessageHistory() {
1526        return messageHistory;
1527    }
1528
1529    public void setMessageHistory(Boolean messageHistory) {
1530        this.messageHistory = messageHistory;
1531    }
1532
1533    public Boolean isHandleFault() {
1534        return handleFault;
1535    }
1536
1537    public void setHandleFault(Boolean handleFault) {
1538        this.handleFault = handleFault;
1539    }
1540
1541    public Long getDelayer() {
1542        return delay;
1543    }
1544
1545    public void setDelayer(Long delay) {
1546        this.delay = delay;
1547    }
1548
1549    public ProducerTemplate createProducerTemplate() {
1550        int size = CamelContextHelper.getMaximumCachePoolSize(this);
1551        return createProducerTemplate(size);
1552    }
1553
1554    public ProducerTemplate createProducerTemplate(int maximumCacheSize) {
1555        DefaultProducerTemplate answer = new DefaultProducerTemplate(this);
1556        answer.setMaximumCacheSize(maximumCacheSize);
1557        // start it so its ready to use
1558        try {
1559            startService(answer);
1560        } catch (Exception e) {
1561            throw ObjectHelper.wrapRuntimeCamelException(e);
1562        }
1563        return answer;
1564    }
1565
1566    public ConsumerTemplate createConsumerTemplate() {
1567        int size = CamelContextHelper.getMaximumCachePoolSize(this);
1568        return createConsumerTemplate(size);
1569    }
1570
1571    public ConsumerTemplate createConsumerTemplate(int maximumCacheSize) {
1572        DefaultConsumerTemplate answer = new DefaultConsumerTemplate(this);
1573        answer.setMaximumCacheSize(maximumCacheSize);
1574        // start it so its ready to use
1575        try {
1576            startService(answer);
1577        } catch (Exception e) {
1578            throw ObjectHelper.wrapRuntimeCamelException(e);
1579        }
1580        return answer;
1581    }
1582
1583    public ErrorHandlerBuilder getErrorHandlerBuilder() {
1584        return (ErrorHandlerBuilder)errorHandlerBuilder;
1585    }
1586
1587    public void setErrorHandlerBuilder(ErrorHandlerFactory errorHandlerBuilder) {
1588        this.errorHandlerBuilder = errorHandlerBuilder;
1589    }
1590
1591    public ScheduledExecutorService getErrorHandlerExecutorService() {
1592        synchronized (errorHandlerExecutorServiceLock) {
1593            if (errorHandlerExecutorService == null) {
1594                // setup default thread pool for error handler
1595                errorHandlerExecutorService = getExecutorServiceManager().newDefaultScheduledThreadPool("ErrorHandlerRedeliveryThreadPool", "ErrorHandlerRedeliveryTask");
1596            }
1597        }
1598        return errorHandlerExecutorService;
1599    }
1600
1601    public void setProducerServicePool(ServicePool<Endpoint, Producer> producerServicePool) {
1602        this.producerServicePool = producerServicePool;
1603    }
1604
1605    public ServicePool<Endpoint, Producer> getProducerServicePool() {
1606        return producerServicePool;
1607    }
1608
1609    public UnitOfWorkFactory getUnitOfWorkFactory() {
1610        return unitOfWorkFactory;
1611    }
1612
1613    public void setUnitOfWorkFactory(UnitOfWorkFactory unitOfWorkFactory) {
1614        this.unitOfWorkFactory = unitOfWorkFactory;
1615    }
1616
1617    public RuntimeEndpointRegistry getRuntimeEndpointRegistry() {
1618        return runtimeEndpointRegistry;
1619    }
1620
1621    public void setRuntimeEndpointRegistry(RuntimeEndpointRegistry runtimeEndpointRegistry) {
1622        this.runtimeEndpointRegistry = runtimeEndpointRegistry;
1623    }
1624
1625    public String getUptime() {
1626        // compute and log uptime
1627        if (startDate == null) {
1628            return "not started";
1629        }
1630        long delta = new Date().getTime() - startDate.getTime();
1631        return TimeUtils.printDuration(delta);
1632    }
1633
1634    @Override
1635    protected void doSuspend() throws Exception {
1636        EventHelper.notifyCamelContextSuspending(this);
1637
1638        log.info("Apache Camel " + getVersion() + " (CamelContext: " + getName() + ") is suspending");
1639        StopWatch watch = new StopWatch();
1640
1641        // update list of started routes to be suspended
1642        // because we only want to suspend started routes
1643        // (so when we resume we only resume the routes which actually was suspended)
1644        for (Map.Entry<String, RouteService> entry : getRouteServices().entrySet()) {
1645            if (entry.getValue().getStatus().isStarted()) {
1646                suspendedRouteServices.put(entry.getKey(), entry.getValue());
1647            }
1648        }
1649
1650        // assemble list of startup ordering so routes can be shutdown accordingly
1651        List<RouteStartupOrder> orders = new ArrayList<RouteStartupOrder>();
1652        for (Map.Entry<String, RouteService> entry : suspendedRouteServices.entrySet()) {
1653            Route route = entry.getValue().getRoutes().iterator().next();
1654            Integer order = entry.getValue().getRouteDefinition().getStartupOrder();
1655            if (order == null) {
1656                order = defaultRouteStartupOrder++;
1657            }
1658            orders.add(new DefaultRouteStartupOrder(order, route, entry.getValue()));
1659        }
1660
1661        // suspend routes using the shutdown strategy so it can shutdown in correct order
1662        // routes which doesn't support suspension will be stopped instead
1663        getShutdownStrategy().suspend(this, orders);
1664
1665        // mark the route services as suspended or stopped
1666        for (RouteService service : suspendedRouteServices.values()) {
1667            if (routeSupportsSuspension(service.getId())) {
1668                service.suspend();
1669            } else {
1670                service.stop();
1671            }
1672        }
1673
1674        watch.stop();
1675        if (log.isInfoEnabled()) {
1676            log.info("Apache Camel " + getVersion() + " (CamelContext: " + getName() + ") is suspended in " + TimeUtils.printDuration(watch.taken()));
1677        }
1678
1679        EventHelper.notifyCamelContextSuspended(this);
1680    }
1681
1682    @Override
1683    protected void doResume() throws Exception {
1684        try {
1685            EventHelper.notifyCamelContextResuming(this);
1686
1687            log.info("Apache Camel " + getVersion() + " (CamelContext: " + getName() + ") is resuming");
1688            StopWatch watch = new StopWatch();
1689
1690            // start the suspended routes (do not check for route clashes, and indicate)
1691            doStartOrResumeRoutes(suspendedRouteServices, false, true, true, false);
1692
1693            // mark the route services as resumed (will be marked as started) as well
1694            for (RouteService service : suspendedRouteServices.values()) {
1695                if (routeSupportsSuspension(service.getId())) {
1696                    service.resume();
1697                } else {
1698                    service.start();
1699                }
1700            }
1701
1702            watch.stop();
1703            if (log.isInfoEnabled()) {
1704                log.info("Resumed " + suspendedRouteServices.size() + " routes");
1705                log.info("Apache Camel " + getVersion() + " (CamelContext: " + getName() + ") resumed in " + TimeUtils.printDuration(watch.taken()));
1706            }
1707
1708            // and clear the list as they have been resumed
1709            suspendedRouteServices.clear();
1710
1711            EventHelper.notifyCamelContextResumed(this);
1712        } catch (Exception e) {
1713            EventHelper.notifyCamelContextResumeFailed(this, e);
1714            throw e;
1715        }
1716    }
1717
1718    public void start() throws Exception {
1719        startDate = new Date();
1720        stopWatch.restart();
1721        log.info("Apache Camel " + getVersion() + " (CamelContext: " + getName() + ") is starting");
1722
1723        doNotStartRoutesOnFirstStart = !firstStartDone && !isAutoStartup();
1724
1725        // if the context was configured with auto startup = false, and we are already started,
1726        // then we may need to start the routes on the 2nd start call
1727        if (firstStartDone && !isAutoStartup() && isStarted()) {
1728            // invoke this logic to warm up the routes and if possible also start the routes
1729            doStartOrResumeRoutes(routeServices, true, true, false, true);
1730        }
1731
1732        // super will invoke doStart which will prepare internal services and start routes etc.
1733        try {
1734            firstStartDone = true;
1735            super.start();
1736        } catch (VetoCamelContextStartException e) {
1737            if (e.isRethrowException()) {
1738                throw e;
1739            } else {
1740                log.info("CamelContext ({}) vetoed to not start due {}", getName(), e.getMessage());
1741                // swallow exception and change state of this camel context to stopped
1742                stop();
1743                return;
1744            }
1745        }
1746
1747        stopWatch.stop();
1748        if (log.isInfoEnabled()) {
1749            // count how many routes are actually started
1750            int started = 0;
1751            for (Route route : getRoutes()) {
1752                if (getRouteStatus(route.getId()).isStarted()) {
1753                    started++;
1754                }
1755            }
1756            log.info("Total " + getRoutes().size() + " routes, of which " + started + " is started.");
1757            log.info("Apache Camel " + getVersion() + " (CamelContext: " + getName() + ") started in " + TimeUtils.printDuration(stopWatch.taken()));
1758        }
1759        EventHelper.notifyCamelContextStarted(this);
1760    }
1761
1762    // Implementation methods
1763    // -----------------------------------------------------------------------
1764
1765    protected synchronized void doStart() throws Exception {
1766        try {
1767            doStartCamel();
1768        } catch (Exception e) {
1769            // fire event that we failed to start
1770            EventHelper.notifyCamelContextStartupFailed(this, e);
1771            // rethrow cause
1772            throw e;
1773        }
1774    }
1775
1776    private void doStartCamel() throws Exception {
1777        if (applicationContextClassLoader == null) {
1778            // Using the TCCL as the default value of ApplicationClassLoader
1779            ClassLoader cl = Thread.currentThread().getContextClassLoader();
1780            if (cl == null) {
1781                // use the classloader that loaded this class
1782                cl = this.getClass().getClassLoader();
1783            }
1784            setApplicationContextClassLoader(cl);
1785        }
1786
1787        if (log.isDebugEnabled()) {
1788            log.debug("Using ClassResolver={}, PackageScanClassResolver={}, ApplicationContextClassLoader={}",
1789                    new Object[]{getClassResolver(), getPackageScanClassResolver(), getApplicationContextClassLoader()});
1790        }
1791
1792        if (isStreamCaching()) {
1793            log.info("StreamCaching is enabled on CamelContext: {}", getName());
1794        }
1795
1796        if (isTracing()) {
1797            // tracing is added in the DefaultChannel so we can enable it on the fly
1798            log.info("Tracing is enabled on CamelContext: {}", getName());
1799        }
1800
1801        if (isUseMDCLogging()) {
1802            // log if MDC has been enabled
1803            log.info("MDC logging is enabled on CamelContext: {}", getName());
1804        }
1805
1806        if (isHandleFault()) {
1807            // only add a new handle fault if not already configured
1808            if (HandleFault.getHandleFault(this) == null) {
1809                log.info("HandleFault is enabled on CamelContext: {}", getName());
1810                addInterceptStrategy(new HandleFault());
1811            }
1812        }
1813
1814        if (getDelayer() != null && getDelayer() > 0) {
1815            log.info("Delayer is enabled with: {} ms. on CamelContext: {}", getDelayer(), getName());
1816        }
1817
1818        // register debugger
1819        if (getDebugger() != null) {
1820            log.info("Debugger: {} is enabled on CamelContext: {}", getDebugger(), getName());
1821            // register this camel context on the debugger
1822            getDebugger().setCamelContext(this);
1823            startService(getDebugger());
1824            addInterceptStrategy(new Debug(getDebugger()));
1825        }
1826
1827        // start management strategy before lifecycles are started
1828        ManagementStrategy managementStrategy = getManagementStrategy();
1829        // inject CamelContext if aware
1830        if (managementStrategy instanceof CamelContextAware) {
1831            ((CamelContextAware) managementStrategy).setCamelContext(this);
1832        }
1833        ServiceHelper.startService(managementStrategy);
1834
1835        // start lifecycle strategies
1836        ServiceHelper.startServices(lifecycleStrategies);
1837        Iterator<LifecycleStrategy> it = lifecycleStrategies.iterator();
1838        while (it.hasNext()) {
1839            LifecycleStrategy strategy = it.next();
1840            try {
1841                strategy.onContextStart(this);
1842            } catch (VetoCamelContextStartException e) {
1843                // okay we should not start Camel since it was vetoed
1844                log.warn("Lifecycle strategy vetoed starting CamelContext ({}) due {}", getName(), e.getMessage());
1845                throw e;
1846            } catch (Exception e) {
1847                log.warn("Lifecycle strategy " + strategy + " failed starting CamelContext ({}) due {}", getName(), e.getMessage());
1848                throw e;
1849            }
1850        }
1851
1852        // start notifiers as services
1853        for (EventNotifier notifier : getManagementStrategy().getEventNotifiers()) {
1854            if (notifier instanceof Service) {
1855                Service service = (Service) notifier;
1856                for (LifecycleStrategy strategy : lifecycleStrategies) {
1857                    strategy.onServiceAdd(this, service, null);
1858                }
1859            }
1860            if (notifier instanceof Service) {
1861                startService((Service)notifier);
1862            }
1863        }
1864
1865        // must let some bootstrap service be started before we can notify the starting event
1866        EventHelper.notifyCamelContextStarting(this);
1867
1868        forceLazyInitialization();
1869
1870        // re-create endpoint registry as the cache size limit may be set after the constructor of this instance was called.
1871        // and we needed to create endpoints up-front as it may be accessed before this context is started
1872        endpoints = new EndpointRegistry(this, endpoints);
1873        addService(endpoints);
1874        // special for executorServiceManager as want to stop it manually
1875        doAddService(executorServiceManager, false);
1876        addService(producerServicePool);
1877        addService(inflightRepository);
1878        addService(shutdownStrategy);
1879        addService(packageScanClassResolver);
1880        addService(restRegistry);
1881
1882        if (runtimeEndpointRegistry != null) {
1883            if (runtimeEndpointRegistry instanceof EventNotifier) {
1884                getManagementStrategy().addEventNotifier((EventNotifier) runtimeEndpointRegistry);
1885            }
1886            addService(runtimeEndpointRegistry);
1887        }
1888
1889        // eager lookup any configured properties component to avoid subsequent lookup attempts which may impact performance
1890        // due we use properties component for property placeholder resolution at runtime
1891        Component existing = CamelContextHelper.lookupPropertiesComponent(this, false);
1892        if (existing != null) {
1893            // store reference to the existing properties component
1894            if (existing instanceof PropertiesComponent) {
1895                propertiesComponent = (PropertiesComponent) existing;
1896            } else {
1897                // properties component must be expected type
1898                throw new IllegalArgumentException("Found properties component of type: " + existing.getClass() + " instead of expected: " + PropertiesComponent.class);
1899            }
1900        }
1901
1902        // start components
1903        startServices(components.values());
1904
1905        // start the route definitions before the routes is started
1906        startRouteDefinitions(routeDefinitions);
1907
1908        // 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
1909        boolean streamCachingInUse = isStreamCaching();
1910        if (!streamCachingInUse) {
1911            for (RouteDefinition route : routeDefinitions) {
1912                Boolean routeCache = CamelContextHelper.parseBoolean(this, route.getStreamCache());
1913                if (routeCache != null && routeCache) {
1914                    streamCachingInUse = true;
1915                    break;
1916                }
1917            }
1918        }
1919
1920        if (isAllowUseOriginalMessage()) {
1921            log.info("AllowUseOriginalMessage is enabled. If access to the original message is not needed,"
1922                    + " then its recommended to turn this option off as it may improve performance.");
1923        }
1924
1925        if (streamCachingInUse) {
1926            // stream caching is in use so enable the strategy
1927            getStreamCachingStrategy().setEnabled(true);
1928            addService(getStreamCachingStrategy());
1929        } else {
1930            // log if stream caching is not in use as this can help people to enable it if they use streams
1931            log.info("StreamCaching is not in use. If using streams then its recommended to enable stream caching."
1932                    + " See more details at http://camel.apache.org/stream-caching.html");
1933        }
1934
1935        // start routes
1936        if (doNotStartRoutesOnFirstStart) {
1937            log.debug("Skip starting of routes as CamelContext has been configured with autoStartup=false");
1938        }
1939
1940        // invoke this logic to warmup the routes and if possible also start the routes
1941        doStartOrResumeRoutes(routeServices, true, !doNotStartRoutesOnFirstStart, false, true);
1942
1943        // starting will continue in the start method
1944    }
1945
1946    protected synchronized void doStop() throws Exception {
1947        stopWatch.restart();
1948        log.info("Apache Camel " + getVersion() + " (CamelContext: " + getName() + ") is shutting down");
1949        EventHelper.notifyCamelContextStopping(this);
1950
1951        // stop route inputs in the same order as they was started so we stop the very first inputs first
1952        try {
1953            // force shutting down routes as they may otherwise cause shutdown to hang
1954            shutdownStrategy.shutdownForced(this, getRouteStartupOrder());
1955        } catch (Throwable e) {
1956            log.warn("Error occurred while shutting down routes. This exception will be ignored.", e);
1957        }
1958        getRouteStartupOrder().clear();
1959
1960        shutdownServices(routeServices.values());
1961        // do not clear route services or startup listeners as we can start Camel again and get the route back as before
1962
1963        // but clear any suspend routes
1964        suspendedRouteServices.clear();
1965
1966        // stop consumers from the services to close first, such as POJO consumer (eg @Consumer)
1967        // which we need to stop after the routes, as a POJO consumer is essentially a route also
1968        for (Service service : servicesToClose) {
1969            if (service instanceof Consumer) {
1970                shutdownServices(service);
1971            }
1972        }
1973
1974        // the stop order is important
1975
1976        // shutdown default error handler thread pool
1977        if (errorHandlerExecutorService != null) {
1978            // force shutting down the thread pool
1979            getExecutorServiceManager().shutdownNow(errorHandlerExecutorService);
1980            errorHandlerExecutorService = null;
1981        }
1982
1983        // shutdown debugger
1984        ServiceHelper.stopAndShutdownService(getDebugger());
1985
1986        shutdownServices(endpoints.values());
1987        endpoints.clear();
1988
1989        shutdownServices(components.values());
1990        components.clear();
1991
1992        shutdownServices(languages.values());
1993        languages.clear();
1994
1995        try {
1996            for (LifecycleStrategy strategy : lifecycleStrategies) {
1997                strategy.onContextStop(this);
1998            }
1999        } catch (Throwable e) {
2000            log.warn("Error occurred while stopping lifecycle strategies. This exception will be ignored.", e);
2001        }
2002
2003        // shutdown services as late as possible
2004        shutdownServices(servicesToClose);
2005        servicesToClose.clear();
2006
2007        // must notify that we are stopped before stopping the management strategy
2008        EventHelper.notifyCamelContextStopped(this);
2009
2010        // stop the notifier service
2011        for (EventNotifier notifier : getManagementStrategy().getEventNotifiers()) {
2012            shutdownServices(notifier);
2013        }
2014
2015        // shutdown executor service and management as the last one
2016        shutdownServices(executorServiceManager);
2017        shutdownServices(managementStrategy);
2018        shutdownServices(managementMBeanAssembler);
2019        shutdownServices(lifecycleStrategies);
2020        // do not clear lifecycleStrategies as we can start Camel again and get the route back as before
2021
2022        // stop the lazy created so they can be re-created on restart
2023        forceStopLazyInitialization();
2024
2025        // stop to clear introspection cache
2026        IntrospectionSupport.stop();
2027
2028        stopWatch.stop();
2029        if (log.isInfoEnabled()) {
2030            log.info("Apache Camel " + getVersion() + " (CamelContext: " + getName() + ") uptime {}", getUptime());
2031            log.info("Apache Camel " + getVersion() + " (CamelContext: " + getName() + ") is shutdown in " + TimeUtils.printDuration(stopWatch.taken()));
2032        }
2033
2034        // and clear start date
2035        startDate = null;
2036
2037        Container.Instance.unmanage(this);
2038    }
2039
2040    /**
2041     * Starts or resumes the routes
2042     *
2043     * @param routeServices  the routes to start (will only start a route if its not already started)
2044     * @param checkClash     whether to check for startup ordering clash
2045     * @param startConsumer  whether the route consumer should be started. Can be used to warmup the route without starting the consumer.
2046     * @param resumeConsumer whether the route consumer should be resumed.
2047     * @param addingRoutes   whether we are adding new routes
2048     * @throws Exception is thrown if error starting routes
2049     */
2050    protected void doStartOrResumeRoutes(Map<String, RouteService> routeServices, boolean checkClash,
2051                                         boolean startConsumer, boolean resumeConsumer, boolean addingRoutes) throws Exception {
2052        isStartingRoutes.set(true);
2053        try {
2054            // filter out already started routes
2055            Map<String, RouteService> filtered = new LinkedHashMap<String, RouteService>();
2056            for (Map.Entry<String, RouteService> entry : routeServices.entrySet()) {
2057                boolean startable = false;
2058
2059                Consumer consumer = entry.getValue().getRoutes().iterator().next().getConsumer();
2060                if (consumer instanceof SuspendableService) {
2061                    // consumer could be suspended, which is not reflected in the RouteService status
2062                    startable = ((SuspendableService) consumer).isSuspended();
2063                }
2064
2065                if (!startable && consumer instanceof StatefulService) {
2066                    // consumer could be stopped, which is not reflected in the RouteService status
2067                    startable = ((StatefulService) consumer).getStatus().isStartable();
2068                } else if (!startable) {
2069                    // no consumer so use state from route service
2070                    startable = entry.getValue().getStatus().isStartable();
2071                }
2072
2073                if (startable) {
2074                    filtered.put(entry.getKey(), entry.getValue());
2075                }
2076            }
2077
2078            if (!filtered.isEmpty()) {
2079                // the context is now considered started (i.e. isStarted() == true))
2080                // starting routes is done after, not during context startup
2081                safelyStartRouteServices(checkClash, startConsumer, resumeConsumer, addingRoutes, filtered.values());
2082            }
2083
2084            // we are finished starting routes, so remove flag before we emit the startup listeners below
2085            isStartingRoutes.remove();
2086
2087            // now notify any startup aware listeners as all the routes etc has been started,
2088            // allowing the listeners to do custom work after routes has been started
2089            for (StartupListener startup : startupListeners) {
2090                startup.onCamelContextStarted(this, isStarted());
2091            }
2092        } finally {
2093            isStartingRoutes.remove();
2094        }
2095    }
2096
2097    protected boolean routeSupportsSuspension(String routeId) {
2098        RouteService routeService = routeServices.get(routeId);
2099        if (routeService != null) {
2100            return routeService.getRoutes().iterator().next().supportsSuspension();
2101        }
2102        return false;
2103    }
2104
2105    private void shutdownServices(Object service) {
2106        // do not rethrow exception as we want to keep shutting down in case of problems
2107
2108        // allow us to do custom work before delegating to service helper
2109        try {
2110            if (service instanceof Service) {
2111                ServiceHelper.stopAndShutdownService(service);
2112            } else if (service instanceof Collection) {
2113                ServiceHelper.stopAndShutdownServices((Collection<?>)service);
2114            }
2115        } catch (Throwable e) {
2116            log.warn("Error occurred while shutting down service: " + service + ". This exception will be ignored.", e);
2117            // fire event
2118            EventHelper.notifyServiceStopFailure(this, service, e);
2119        }
2120    }
2121
2122    private void shutdownServices(Collection<?> services) {
2123        // reverse stopping by default
2124        shutdownServices(services, true);
2125    }
2126
2127    private void shutdownServices(Collection<?> services, boolean reverse) {
2128        Collection<?> list = services;
2129        if (reverse) {
2130            List<Object> reverseList = new ArrayList<Object>(services);
2131            Collections.reverse(reverseList);
2132            list = reverseList;
2133        }
2134
2135        for (Object service : list) {
2136            shutdownServices(service);
2137        }
2138    }
2139
2140    private void startService(Service service) throws Exception {
2141        // and register startup aware so they can be notified when
2142        // camel context has been started
2143        if (service instanceof StartupListener) {
2144            StartupListener listener = (StartupListener) service;
2145            addStartupListener(listener);
2146        }
2147
2148        service.start();
2149    }
2150
2151    private void startServices(Collection<?> services) throws Exception {
2152        for (Object element : services) {
2153            if (element instanceof Service) {
2154                startService((Service)element);
2155            }
2156        }
2157    }
2158
2159    private void stopServices(Object service) throws Exception {
2160        // allow us to do custom work before delegating to service helper
2161        try {
2162            ServiceHelper.stopService(service);
2163        } catch (Exception e) {
2164            // fire event
2165            EventHelper.notifyServiceStopFailure(this, service, e);
2166            // rethrow to signal error with stopping
2167            throw e;
2168        }
2169    }
2170
2171    protected void startRouteDefinitions(Collection<RouteDefinition> list) throws Exception {
2172        if (list != null) {
2173            for (RouteDefinition route : list) {
2174                startRoute(route);
2175            }
2176        }
2177    }
2178
2179    /**
2180     * Starts the given route service
2181     */
2182    protected synchronized void startRouteService(RouteService routeService, boolean addingRoutes) throws Exception {
2183        // we may already be starting routes so remember this, so we can unset accordingly in finally block
2184        boolean alreadyStartingRoutes = isStartingRoutes();
2185        if (!alreadyStartingRoutes) {
2186            isStartingRoutes.set(true);
2187        }
2188
2189        try {
2190            // the route service could have been suspended, and if so then resume it instead
2191            if (routeService.getStatus().isSuspended()) {
2192                resumeRouteService(routeService);
2193            } else {
2194                // start the route service
2195                routeServices.put(routeService.getId(), routeService);
2196                if (shouldStartRoutes()) {
2197                    // this method will log the routes being started
2198                    safelyStartRouteServices(true, true, true, false, addingRoutes, routeService);
2199                    // start route services if it was configured to auto startup and we are not adding routes
2200                    boolean autoStartup = routeService.getRouteDefinition().isAutoStartup(this) && this.isAutoStartup();
2201                    if (!addingRoutes || autoStartup) {
2202                        // start the route since auto start is enabled or we are starting a route (not adding new routes)
2203                        routeService.start();
2204                    }
2205                }
2206            }
2207        } finally {
2208            if (!alreadyStartingRoutes) {
2209                isStartingRoutes.remove();
2210            }
2211        }
2212    }
2213
2214    /**
2215     * Resumes the given route service
2216     */
2217    protected synchronized void resumeRouteService(RouteService routeService) throws Exception {
2218        // the route service could have been stopped, and if so then start it instead
2219        if (!routeService.getStatus().isSuspended()) {
2220            startRouteService(routeService, false);
2221        } else {
2222            // resume the route service
2223            if (shouldStartRoutes()) {
2224                // this method will log the routes being started
2225                safelyStartRouteServices(true, false, true, true, false, routeService);
2226                // must resume route service as well
2227                routeService.resume();
2228            }
2229        }
2230    }
2231
2232    protected synchronized void stopRouteService(RouteService routeService, boolean removingRoutes) throws Exception {
2233        routeService.setRemovingRoutes(removingRoutes);
2234        stopRouteService(routeService);
2235    }
2236
2237    protected void logRouteState(Route route, String state) {
2238        if (log.isInfoEnabled()) {
2239            if (route.getConsumer() != null) {
2240                log.info("Route: {} is {}, was consuming from: {}", new Object[]{route.getId(), state, route.getConsumer().getEndpoint()});
2241            } else {
2242                log.info("Route: {} is {}.", route.getId(), state);
2243            }
2244        }
2245    }
2246
2247    protected synchronized void stopRouteService(RouteService routeService) throws Exception {
2248        routeService.stop();
2249        for (Route route : routeService.getRoutes()) {
2250            logRouteState(route, "stopped");
2251        }
2252    }
2253
2254    protected synchronized void shutdownRouteService(RouteService routeService) throws Exception {
2255        routeService.shutdown();
2256        for (Route route : routeService.getRoutes()) {
2257            logRouteState(route, "shutdown and removed");
2258        }
2259    }
2260
2261    protected synchronized void suspendRouteService(RouteService routeService) throws Exception {
2262        routeService.setRemovingRoutes(false);
2263        routeService.suspend();
2264        for (Route route : routeService.getRoutes()) {
2265            logRouteState(route, "suspended");
2266        }
2267    }
2268
2269    /**
2270     * Starts the routes services in a proper manner which ensures the routes will be started in correct order,
2271     * check for clash and that the routes will also be shutdown in correct order as well.
2272     * <p/>
2273     * This method <b>must</b> be used to start routes in a safe manner.
2274     *
2275     * @param checkClash     whether to check for startup order clash
2276     * @param startConsumer  whether the route consumer should be started. Can be used to warmup the route without starting the consumer.
2277     * @param resumeConsumer whether the route consumer should be resumed.
2278     * @param addingRoutes   whether we are adding new routes
2279     * @param routeServices  the routes
2280     * @throws Exception is thrown if error starting the routes
2281     */
2282    protected synchronized void safelyStartRouteServices(boolean checkClash, boolean startConsumer, boolean resumeConsumer,
2283                                                         boolean addingRoutes, Collection<RouteService> routeServices) throws Exception {
2284        // list of inputs to start when all the routes have been prepared for starting
2285        // we use a tree map so the routes will be ordered according to startup order defined on the route
2286        Map<Integer, DefaultRouteStartupOrder> inputs = new TreeMap<Integer, DefaultRouteStartupOrder>();
2287
2288        // figure out the order in which the routes should be started
2289        for (RouteService routeService : routeServices) {
2290            DefaultRouteStartupOrder order = doPrepareRouteToBeStarted(routeService);
2291            // check for clash before we add it as input
2292            if (checkClash) {
2293                doCheckStartupOrderClash(order, inputs);
2294            }
2295            inputs.put(order.getStartupOrder(), order);
2296        }
2297
2298        // warm up routes before we start them
2299        doWarmUpRoutes(inputs, startConsumer);
2300
2301        if (startConsumer) {
2302            if (resumeConsumer) {
2303                // and now resume the routes
2304                doResumeRouteConsumers(inputs, addingRoutes);
2305            } else {
2306                // and now start the routes
2307                // and check for clash with multiple consumers of the same endpoints which is not allowed
2308                doStartRouteConsumers(inputs, addingRoutes);
2309            }
2310        }
2311
2312        // inputs no longer needed
2313        inputs.clear();
2314    }
2315
2316    /**
2317     * @see #safelyStartRouteServices(boolean,boolean,boolean,boolean,java.util.Collection)
2318     */
2319    protected synchronized void safelyStartRouteServices(boolean forceAutoStart, boolean checkClash, boolean startConsumer,
2320                                                         boolean resumeConsumer, boolean addingRoutes, RouteService... routeServices) throws Exception {
2321        safelyStartRouteServices(checkClash, startConsumer, resumeConsumer, addingRoutes, Arrays.asList(routeServices));
2322    }
2323
2324    private DefaultRouteStartupOrder doPrepareRouteToBeStarted(RouteService routeService) {
2325        // add the inputs from this route service to the list to start afterwards
2326        // should be ordered according to the startup number
2327        Integer startupOrder = routeService.getRouteDefinition().getStartupOrder();
2328        if (startupOrder == null) {
2329            // auto assign a default startup order
2330            startupOrder = defaultRouteStartupOrder++;
2331        }
2332
2333        // create holder object that contains information about this route to be started
2334        Route route = routeService.getRoutes().iterator().next();
2335        return new DefaultRouteStartupOrder(startupOrder, route, routeService);
2336    }
2337
2338    private boolean doCheckStartupOrderClash(DefaultRouteStartupOrder answer, Map<Integer, DefaultRouteStartupOrder> inputs) throws FailedToStartRouteException {
2339        // check for clash by startupOrder id
2340        DefaultRouteStartupOrder other = inputs.get(answer.getStartupOrder());
2341        if (other != null && answer != other) {
2342            String otherId = other.getRoute().getId();
2343            throw new FailedToStartRouteException(answer.getRoute().getId(), "startupOrder clash. Route " + otherId + " already has startupOrder "
2344                + answer.getStartupOrder() + " configured which this route have as well. Please correct startupOrder to be unique among all your routes.");
2345        }
2346        // check in existing already started as well
2347        for (RouteStartupOrder order : routeStartupOrder) {
2348            String otherId = order.getRoute().getId();
2349            if (answer.getRoute().getId().equals(otherId)) {
2350                // its the same route id so skip clash check as its the same route (can happen when using suspend/resume)
2351            } else if (answer.getStartupOrder() == order.getStartupOrder()) {
2352                throw new FailedToStartRouteException(answer.getRoute().getId(), "startupOrder clash. Route " + otherId + " already has startupOrder "
2353                    + answer.getStartupOrder() + " configured which this route have as well. Please correct startupOrder to be unique among all your routes.");
2354            }
2355        }
2356        return true;
2357    }
2358
2359    private void doWarmUpRoutes(Map<Integer, DefaultRouteStartupOrder> inputs, boolean autoStartup) throws Exception {
2360        // now prepare the routes by starting its services before we start the input
2361        for (Map.Entry<Integer, DefaultRouteStartupOrder> entry : inputs.entrySet()) {
2362            // defer starting inputs till later as we want to prepare the routes by starting
2363            // all their processors and child services etc.
2364            // then later we open the floods to Camel by starting the inputs
2365            // what this does is to ensure Camel is more robust on starting routes as all routes
2366            // will then be prepared in time before we start inputs which will consume messages to be routed
2367            RouteService routeService = entry.getValue().getRouteService();
2368            log.debug("Warming up route id: {} having autoStartup={}", routeService.getId(), autoStartup);
2369            routeService.warmUp();
2370        }
2371    }
2372
2373    private void doResumeRouteConsumers(Map<Integer, DefaultRouteStartupOrder> inputs, boolean addingRoutes) throws Exception {
2374        doStartOrResumeRouteConsumers(inputs, true, addingRoutes);
2375    }
2376
2377    private void doStartRouteConsumers(Map<Integer, DefaultRouteStartupOrder> inputs, boolean addingRoutes) throws Exception {
2378        doStartOrResumeRouteConsumers(inputs, false, addingRoutes);
2379    }
2380
2381    private void doStartOrResumeRouteConsumers(Map<Integer, DefaultRouteStartupOrder> inputs, boolean resumeOnly, boolean addingRoute) throws Exception {
2382        List<Endpoint> routeInputs = new ArrayList<Endpoint>();
2383
2384        for (Map.Entry<Integer, DefaultRouteStartupOrder> entry : inputs.entrySet()) {
2385            Integer order = entry.getKey();
2386            Route route = entry.getValue().getRoute();
2387            RouteService routeService = entry.getValue().getRouteService();
2388
2389            // if we are starting camel, then skip routes which are configured to not be auto started
2390            boolean autoStartup = routeService.getRouteDefinition().isAutoStartup(this) && this.isAutoStartup();
2391            if (addingRoute && !autoStartup) {
2392                log.info("Skipping starting of route " + routeService.getId() + " as its configured with autoStartup=false");
2393                continue;
2394            }
2395
2396            // start the service
2397            for (Consumer consumer : routeService.getInputs().values()) {
2398                Endpoint endpoint = consumer.getEndpoint();
2399
2400                // check multiple consumer violation, with the other routes to be started
2401                if (!doCheckMultipleConsumerSupportClash(endpoint, routeInputs)) {
2402                    throw new FailedToStartRouteException(routeService.getId(),
2403                        "Multiple consumers for the same endpoint is not allowed: " + endpoint);
2404                }
2405
2406                // check for multiple consumer violations with existing routes which
2407                // have already been started, or is currently starting
2408                List<Endpoint> existingEndpoints = new ArrayList<Endpoint>();
2409                for (Route existingRoute : getRoutes()) {
2410                    if (route.getId().equals(existingRoute.getId())) {
2411                        // skip ourselves
2412                        continue;
2413                    }
2414                    Endpoint existing = existingRoute.getEndpoint();
2415                    ServiceStatus status = getRouteStatus(existingRoute.getId());
2416                    if (status != null && (status.isStarted() || status.isStarting())) {
2417                        existingEndpoints.add(existing);
2418                    }
2419                }
2420                if (!doCheckMultipleConsumerSupportClash(endpoint, existingEndpoints)) {
2421                    throw new FailedToStartRouteException(routeService.getId(),
2422                            "Multiple consumers for the same endpoint is not allowed: " + endpoint);
2423                }
2424
2425                // start the consumer on the route
2426                log.debug("Route: {} >>> {}", route.getId(), route);
2427                if (resumeOnly) {
2428                    log.debug("Resuming consumer (order: {}) on route: {}", order, route.getId());
2429                } else {
2430                    log.debug("Starting consumer (order: {}) on route: {}", order, route.getId());
2431                }
2432
2433                if (resumeOnly && route.supportsSuspension()) {
2434                    // if we are resuming and the route can be resumed
2435                    ServiceHelper.resumeService(consumer);
2436                    log.info("Route: " + route.getId() + " resumed and consuming from: " + endpoint);
2437                } else {
2438                    // when starting we should invoke the lifecycle strategies
2439                    for (LifecycleStrategy strategy : lifecycleStrategies) {
2440                        strategy.onServiceAdd(this, consumer, route);
2441                    }
2442                    startService(consumer);
2443                    log.info("Route: " + route.getId() + " started and consuming from: " + endpoint);
2444                }
2445
2446                routeInputs.add(endpoint);
2447
2448                // add to the order which they was started, so we know how to stop them in reverse order
2449                // but only add if we haven't already registered it before (we dont want to double add when restarting)
2450                boolean found = false;
2451                for (RouteStartupOrder other : routeStartupOrder) {
2452                    if (other.getRoute().getId().equals(route.getId())) {
2453                        found = true;
2454                        break;
2455                    }
2456                }
2457                if (!found) {
2458                    routeStartupOrder.add(entry.getValue());
2459                }
2460            }
2461
2462            if (resumeOnly) {
2463                routeService.resume();
2464            } else {
2465                // and start the route service (no need to start children as they are already warmed up)
2466                routeService.start(false);
2467            }
2468        }
2469    }
2470
2471    private boolean doCheckMultipleConsumerSupportClash(Endpoint endpoint, List<Endpoint> routeInputs) {
2472        // is multiple consumers supported
2473        boolean multipleConsumersSupported = false;
2474        if (endpoint instanceof MultipleConsumersSupport) {
2475            multipleConsumersSupported = ((MultipleConsumersSupport) endpoint).isMultipleConsumersSupported();
2476        }
2477
2478        if (multipleConsumersSupported) {
2479            // multiple consumer allowed, so return true
2480            return true;
2481        }
2482
2483        // check in progress list
2484        if (routeInputs.contains(endpoint)) {
2485            return false;
2486        }
2487
2488        return true;
2489    }
2490
2491    /**
2492     * Force some lazy initialization to occur upfront before we start any
2493     * components and create routes
2494     */
2495    protected void forceLazyInitialization() {
2496        getRegistry();
2497        getInjector();
2498        getLanguageResolver();
2499        getTypeConverterRegistry();
2500        getTypeConverter();
2501        getRuntimeEndpointRegistry();
2502
2503        if (isTypeConverterStatisticsEnabled() != null) {
2504            getTypeConverterRegistry().getStatistics().setStatisticsEnabled(isTypeConverterStatisticsEnabled());
2505        }
2506    }
2507
2508    /**
2509     * Force clear lazy initialization so they can be re-created on restart
2510     */
2511    protected void forceStopLazyInitialization() {
2512        injector = null;
2513        languageResolver = null;
2514        typeConverterRegistry = null;
2515        typeConverter = null;
2516    }
2517
2518    /**
2519     * Lazily create a default implementation
2520     */
2521    protected TypeConverter createTypeConverter() {
2522        BaseTypeConverterRegistry answer;
2523        if (isLazyLoadTypeConverters()) {
2524            answer = new LazyLoadingTypeConverter(packageScanClassResolver, getInjector(), getDefaultFactoryFinder());
2525        } else {
2526            answer = new DefaultTypeConverter(packageScanClassResolver, getInjector(), getDefaultFactoryFinder());
2527        }
2528        setTypeConverterRegistry(answer);
2529        return answer;
2530    }
2531
2532    /**
2533     * Lazily create a default implementation
2534     */
2535    protected Injector createInjector() {
2536        FactoryFinder finder = getDefaultFactoryFinder();
2537        try {
2538            return (Injector) finder.newInstance("Injector");
2539        } catch (NoFactoryAvailableException e) {
2540            // lets use the default injector
2541            return new DefaultInjector(this);
2542        }
2543    }
2544
2545    /**
2546     * Lazily create a default implementation
2547     */
2548    protected ManagementMBeanAssembler createManagementMBeanAssembler() {
2549        return new DefaultManagementMBeanAssembler(this);
2550    }
2551
2552    /**
2553     * Lazily create a default implementation
2554     */
2555    protected ComponentResolver createComponentResolver() {
2556        return new DefaultComponentResolver();
2557    }
2558
2559    /**
2560     * Lazily create a default implementation
2561     */
2562    protected Registry createRegistry() {
2563        JndiRegistry jndi = new JndiRegistry();
2564        try {
2565            // getContext() will force setting up JNDI
2566            jndi.getContext();
2567            return jndi;
2568        } catch (Throwable e) {
2569            log.debug("Cannot create javax.naming.InitialContext due " + e.getMessage() + ". Will fallback and use SimpleRegistry instead. This exception is ignored.", e);
2570            return new SimpleRegistry();
2571        }
2572    }
2573
2574    /**
2575     * A pluggable strategy to allow an endpoint to be created without requiring
2576     * a component to be its factory, such as for looking up the URI inside some
2577     * {@link Registry}
2578     *
2579     * @param uri the uri for the endpoint to be created
2580     * @return the newly created endpoint or null if it could not be resolved
2581     */
2582    protected Endpoint createEndpoint(String uri) {
2583        Object value = getRegistry().lookupByName(uri);
2584        if (value instanceof Endpoint) {
2585            return (Endpoint) value;
2586        } else if (value instanceof Processor) {
2587            return new ProcessorEndpoint(uri, this, (Processor) value);
2588        } else if (value != null) {
2589            return convertBeanToEndpoint(uri, value);
2590        }
2591        return null;
2592    }
2593
2594    /**
2595     * Strategy method for attempting to convert the bean from a {@link Registry} to an endpoint using
2596     * some kind of transformation or wrapper
2597     *
2598     * @param uri  the uri for the endpoint (and name in the registry)
2599     * @param bean the bean to be converted to an endpoint, which will be not null
2600     * @return a new endpoint
2601     */
2602    protected Endpoint convertBeanToEndpoint(String uri, Object bean) {
2603        throw new IllegalArgumentException("uri: " + uri + " bean: " + bean
2604                + " could not be converted to an Endpoint");
2605    }
2606
2607    /**
2608     * Should we start newly added routes?
2609     */
2610    protected boolean shouldStartRoutes() {
2611        return isStarted() && !isStarting();
2612    }
2613
2614    /**
2615     * Gets the properties component in use.
2616     * Returns {@code null} if no properties component is in use.
2617     */
2618    protected PropertiesComponent getPropertiesComponent() {
2619        return propertiesComponent;
2620    }
2621
2622    public void setDataFormats(Map<String, DataFormatDefinition> dataFormats) {
2623        this.dataFormats = dataFormats;
2624    }
2625
2626    public Map<String, DataFormatDefinition> getDataFormats() {
2627        return dataFormats;
2628    }
2629
2630    public Map<String, String> getProperties() {
2631        return properties;
2632    }
2633
2634    public void setProperties(Map<String, String> properties) {
2635        this.properties = properties;
2636    }
2637
2638    public FactoryFinder getDefaultFactoryFinder() {
2639        if (defaultFactoryFinder == null) {
2640            defaultFactoryFinder = factoryFinderResolver.resolveDefaultFactoryFinder(getClassResolver());
2641        }
2642        return defaultFactoryFinder;
2643    }
2644
2645    public void setFactoryFinderResolver(FactoryFinderResolver resolver) {
2646        this.factoryFinderResolver = resolver;
2647    }
2648
2649    public FactoryFinder getFactoryFinder(String path) throws NoFactoryAvailableException {
2650        synchronized (factories) {
2651            FactoryFinder answer = factories.get(path);
2652            if (answer == null) {
2653                answer = factoryFinderResolver.resolveFactoryFinder(getClassResolver(), path);
2654                factories.put(path, answer);
2655            }
2656            return answer;
2657        }
2658    }
2659
2660    public ClassResolver getClassResolver() {
2661        return classResolver;
2662    }
2663
2664    public void setClassResolver(ClassResolver classResolver) {
2665        this.classResolver = classResolver;
2666    }
2667
2668    public PackageScanClassResolver getPackageScanClassResolver() {
2669        return packageScanClassResolver;
2670    }
2671
2672    public void setPackageScanClassResolver(PackageScanClassResolver packageScanClassResolver) {
2673        this.packageScanClassResolver = packageScanClassResolver;
2674    }
2675
2676    public List<String> getComponentNames() {
2677        synchronized (components) {
2678            List<String> answer = new ArrayList<String>();
2679            for (String name : components.keySet()) {
2680                answer.add(name);
2681            }
2682            return answer;
2683        }
2684    }
2685
2686    public List<String> getLanguageNames() {
2687        synchronized (languages) {
2688            List<String> answer = new ArrayList<String>();
2689            for (String name : languages.keySet()) {
2690                answer.add(name);
2691            }
2692            return answer;
2693        }
2694    }
2695
2696    public NodeIdFactory getNodeIdFactory() {
2697        return nodeIdFactory;
2698    }
2699
2700    public void setNodeIdFactory(NodeIdFactory idFactory) {
2701        this.nodeIdFactory = idFactory;
2702    }
2703
2704    public ManagementStrategy getManagementStrategy() {
2705        return managementStrategy;
2706    }
2707
2708    public void setManagementStrategy(ManagementStrategy managementStrategy) {
2709        this.managementStrategy = managementStrategy;
2710    }
2711
2712    public InterceptStrategy getDefaultTracer() {
2713        if (defaultTracer == null) {
2714            defaultTracer = new Tracer();
2715        }
2716        return defaultTracer;
2717    }
2718
2719    public void setDefaultTracer(InterceptStrategy tracer) {
2720        this.defaultTracer = tracer;
2721    }
2722
2723    public InterceptStrategy getDefaultBacklogTracer() {
2724        if (defaultBacklogTracer == null) {
2725            defaultBacklogTracer = new BacklogTracer(this);
2726        }
2727        return defaultBacklogTracer;
2728    }
2729
2730    public void setDefaultBacklogTracer(InterceptStrategy backlogTracer) {
2731        this.defaultBacklogTracer = backlogTracer;
2732    }
2733
2734    public InterceptStrategy getDefaultBacklogDebugger() {
2735        if (defaultBacklogDebugger == null) {
2736            defaultBacklogDebugger = new BacklogDebugger(this);
2737        }
2738        return defaultBacklogDebugger;
2739    }
2740
2741    public void setDefaultBacklogDebugger(InterceptStrategy defaultBacklogDebugger) {
2742        this.defaultBacklogDebugger = defaultBacklogDebugger;
2743    }
2744
2745    public void disableJMX() {
2746        if (isStarting() || isStarted()) {
2747            throw new IllegalStateException("Disabling JMX can only be done when CamelContext has not been started");
2748        }
2749        managementStrategy = new DefaultManagementStrategy(this);
2750        // must clear lifecycle strategies as we add DefaultManagementLifecycleStrategy by default for JMX support
2751        lifecycleStrategies.clear();
2752    }
2753
2754    public InflightRepository getInflightRepository() {
2755        return inflightRepository;
2756    }
2757
2758    public void setInflightRepository(InflightRepository repository) {
2759        this.inflightRepository = repository;
2760    }
2761
2762    public void setAutoStartup(Boolean autoStartup) {
2763        this.autoStartup = autoStartup;
2764    }
2765
2766    public Boolean isAutoStartup() {
2767        return autoStartup != null && autoStartup;
2768    }
2769
2770    @Deprecated
2771    public Boolean isLazyLoadTypeConverters() {
2772        return lazyLoadTypeConverters != null && lazyLoadTypeConverters;
2773    }
2774
2775    @Deprecated
2776    public void setLazyLoadTypeConverters(Boolean lazyLoadTypeConverters) {
2777        this.lazyLoadTypeConverters = lazyLoadTypeConverters;
2778    }
2779
2780    public Boolean isTypeConverterStatisticsEnabled() {
2781        return typeConverterStatisticsEnabled != null && typeConverterStatisticsEnabled;
2782    }
2783
2784    public void setTypeConverterStatisticsEnabled(Boolean typeConverterStatisticsEnabled) {
2785        this.typeConverterStatisticsEnabled = typeConverterStatisticsEnabled;
2786    }
2787
2788    public Boolean isUseMDCLogging() {
2789        return useMDCLogging != null && useMDCLogging;
2790    }
2791
2792    public void setUseMDCLogging(Boolean useMDCLogging) {
2793        this.useMDCLogging = useMDCLogging;
2794    }
2795
2796    public Boolean isUseBreadcrumb() {
2797        return useBreadcrumb != null && useBreadcrumb;
2798    }
2799
2800    public void setUseBreadcrumb(Boolean useBreadcrumb) {
2801        this.useBreadcrumb = useBreadcrumb;
2802    }
2803
2804    public ClassLoader getApplicationContextClassLoader() {
2805        return applicationContextClassLoader;
2806    }
2807
2808    public void setApplicationContextClassLoader(ClassLoader classLoader) {
2809        applicationContextClassLoader = classLoader;
2810    }
2811
2812    public DataFormatResolver getDataFormatResolver() {
2813        return dataFormatResolver;
2814    }
2815
2816    public void setDataFormatResolver(DataFormatResolver dataFormatResolver) {
2817        this.dataFormatResolver = dataFormatResolver;
2818    }
2819
2820    public DataFormat resolveDataFormat(String name) {
2821        DataFormat answer = dataFormatResolver.resolveDataFormat(name, this);
2822
2823        // inject CamelContext if aware
2824        if (answer != null && answer instanceof CamelContextAware) {
2825            ((CamelContextAware) answer).setCamelContext(this);
2826        }
2827
2828        return answer;
2829    }
2830
2831    public DataFormatDefinition resolveDataFormatDefinition(String name) {
2832        // lookup type and create the data format from it
2833        DataFormatDefinition type = lookup(this, name, DataFormatDefinition.class);
2834        if (type == null && getDataFormats() != null) {
2835            type = getDataFormats().get(name);
2836        }
2837        return type;
2838    }
2839
2840    private static <T> T lookup(CamelContext context, String ref, Class<T> type) {
2841        try {
2842            return context.getRegistry().lookupByNameAndType(ref, type);
2843        } catch (Exception e) {
2844            // need to ignore not same type and return it as null
2845            return null;
2846        }
2847    }
2848
2849    /**
2850     * @deprecated use {@link org.apache.camel.util.CamelContextHelper#lookupPropertiesComponent(org.apache.camel.CamelContext, boolean)}
2851     */
2852    @Deprecated
2853    protected Component lookupPropertiesComponent() {
2854        return CamelContextHelper.lookupPropertiesComponent(this, false);
2855    }
2856
2857    public ShutdownStrategy getShutdownStrategy() {
2858        return shutdownStrategy;
2859    }
2860
2861    public void setShutdownStrategy(ShutdownStrategy shutdownStrategy) {
2862        this.shutdownStrategy = shutdownStrategy;
2863    }
2864
2865    public ShutdownRoute getShutdownRoute() {
2866        return shutdownRoute;
2867    }
2868
2869    public void setShutdownRoute(ShutdownRoute shutdownRoute) {
2870        this.shutdownRoute = shutdownRoute;
2871    }
2872
2873    public ShutdownRunningTask getShutdownRunningTask() {
2874        return shutdownRunningTask;
2875    }
2876
2877    public void setShutdownRunningTask(ShutdownRunningTask shutdownRunningTask) {
2878        this.shutdownRunningTask = shutdownRunningTask;
2879    }
2880
2881    public void setAllowUseOriginalMessage(Boolean allowUseOriginalMessage) {
2882        this.allowUseOriginalMessage = allowUseOriginalMessage;
2883    }
2884
2885    public Boolean isAllowUseOriginalMessage() {
2886        return allowUseOriginalMessage != null && allowUseOriginalMessage;
2887    }
2888
2889    public ExecutorServiceManager getExecutorServiceManager() {
2890        return this.executorServiceManager;
2891    }
2892
2893    @Deprecated
2894    public org.apache.camel.spi.ExecutorServiceStrategy getExecutorServiceStrategy() {
2895        // its okay to create a new instance as its stateless, and just delegate
2896        // ExecutorServiceManager which is the new API
2897        return new DefaultExecutorServiceStrategy(this);
2898    }
2899
2900    public void setExecutorServiceManager(ExecutorServiceManager executorServiceManager) {
2901        this.executorServiceManager = executorServiceManager;
2902    }
2903
2904    public ProcessorFactory getProcessorFactory() {
2905        return processorFactory;
2906    }
2907
2908    public void setProcessorFactory(ProcessorFactory processorFactory) {
2909        this.processorFactory = processorFactory;
2910    }
2911
2912    public Debugger getDebugger() {
2913        return debugger;
2914    }
2915
2916    public void setDebugger(Debugger debugger) {
2917        this.debugger = debugger;
2918    }
2919
2920    public UuidGenerator getUuidGenerator() {
2921        return uuidGenerator;
2922    }
2923
2924    public void setUuidGenerator(UuidGenerator uuidGenerator) {
2925        this.uuidGenerator = uuidGenerator;
2926    }
2927
2928    public StreamCachingStrategy getStreamCachingStrategy() {
2929        if (streamCachingStrategy == null) {
2930            streamCachingStrategy = new DefaultStreamCachingStrategy();
2931        }
2932        return streamCachingStrategy;
2933    }
2934
2935    public void setStreamCachingStrategy(StreamCachingStrategy streamCachingStrategy) {
2936        this.streamCachingStrategy = streamCachingStrategy;
2937    }
2938
2939    public RestRegistry getRestRegistry() {
2940        return restRegistry;
2941    }
2942
2943    public void setRestRegistry(RestRegistry restRegistry) {
2944        this.restRegistry = restRegistry;
2945    }
2946
2947    @Override
2948    public String getProperty(String name) {
2949        String value = getProperties().get(name);
2950        if (ObjectHelper.isNotEmpty(value)) {
2951            try {
2952                value = resolvePropertyPlaceholders(value);
2953            } catch (Exception e) {
2954                throw new RuntimeCamelException("Error getting property: " + name, e);
2955            }
2956        }
2957        return value;
2958    }
2959
2960    protected Map<String, RouteService> getRouteServices() {
2961        return routeServices;
2962    }
2963
2964    protected ManagementStrategy createManagementStrategy() {
2965        return new ManagementStrategyFactory().create(this, disableJMX || Boolean.getBoolean(JmxSystemPropertyKeys.DISABLED));
2966    }
2967
2968    /**
2969     * Reset context counter to a preset value. Mostly used for tests to ensure a predictable getName()
2970     *
2971     * @param value new value for the context counter
2972     */
2973    public static void setContextCounter(int value) {
2974        DefaultCamelContextNameStrategy.setCounter(value);
2975        DefaultManagementNameStrategy.setCounter(value);
2976    }
2977
2978    private static UuidGenerator createDefaultUuidGenerator() {
2979        if (System.getProperty("com.google.appengine.runtime.environment") != null) {
2980            // either "Production" or "Development"
2981            return new JavaUuidGenerator();
2982        } else {
2983            return new ActiveMQUuidGenerator();
2984        }
2985    }
2986
2987    @Override
2988    public String toString() {
2989        return "CamelContext(" + getName() + ")";
2990    }
2991}