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