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