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