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