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