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