
org.apache.camel.impl.engine.AbstractCamelContext Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.impl.engine;
import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.function.Supplier;
import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
import org.apache.camel.CatalogCamelContext;
import org.apache.camel.Component;
import org.apache.camel.Consumer;
import org.apache.camel.ConsumerTemplate;
import org.apache.camel.Endpoint;
import org.apache.camel.ErrorHandlerFactory;
import org.apache.camel.ExchangeConstantProvider;
import org.apache.camel.ExtendedCamelContext;
import org.apache.camel.FailedToStartComponentException;
import org.apache.camel.FluentProducerTemplate;
import org.apache.camel.GlobalEndpointConfiguration;
import org.apache.camel.IsSingleton;
import org.apache.camel.LoggingLevel;
import org.apache.camel.NoSuchEndpointException;
import org.apache.camel.Processor;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.ResolveEndpointFailedException;
import org.apache.camel.Route;
import org.apache.camel.RouteAware;
import org.apache.camel.RouteConfigurationsBuilder;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.Service;
import org.apache.camel.ServiceStatus;
import org.apache.camel.ShutdownRoute;
import org.apache.camel.ShutdownRunningTask;
import org.apache.camel.StartupListener;
import org.apache.camel.StartupStep;
import org.apache.camel.StartupSummaryLevel;
import org.apache.camel.Suspendable;
import org.apache.camel.SuspendableService;
import org.apache.camel.TypeConverter;
import org.apache.camel.VetoCamelContextStartException;
import org.apache.camel.api.management.JmxSystemPropertyKeys;
import org.apache.camel.catalog.RuntimeCamelCatalog;
import org.apache.camel.console.DevConsoleRegistry;
import org.apache.camel.console.DevConsoleResolver;
import org.apache.camel.health.HealthCheckRegistry;
import org.apache.camel.health.HealthCheckResolver;
import org.apache.camel.spi.AnnotationBasedProcessorFactory;
import org.apache.camel.spi.AnnotationScanTypeConverters;
import org.apache.camel.spi.AsyncProcessorAwaitManager;
import org.apache.camel.spi.BeanIntrospection;
import org.apache.camel.spi.BeanProcessorFactory;
import org.apache.camel.spi.BeanProxyFactory;
import org.apache.camel.spi.BootstrapCloseable;
import org.apache.camel.spi.CamelBeanPostProcessor;
import org.apache.camel.spi.CamelContextNameStrategy;
import org.apache.camel.spi.CamelContextTracker;
import org.apache.camel.spi.CamelDependencyInjectionAnnotationFactory;
import org.apache.camel.spi.CamelLogger;
import org.apache.camel.spi.ClassResolver;
import org.apache.camel.spi.CliConnector;
import org.apache.camel.spi.CliConnectorFactory;
import org.apache.camel.spi.ComponentNameResolver;
import org.apache.camel.spi.ComponentResolver;
import org.apache.camel.spi.ConfigurerResolver;
import org.apache.camel.spi.DataFormat;
import org.apache.camel.spi.DataFormatResolver;
import org.apache.camel.spi.DataType;
import org.apache.camel.spi.Debugger;
import org.apache.camel.spi.DebuggerFactory;
import org.apache.camel.spi.DeferServiceFactory;
import org.apache.camel.spi.EndpointRegistry;
import org.apache.camel.spi.EndpointStrategy;
import org.apache.camel.spi.EndpointUriFactory;
import org.apache.camel.spi.EventNotifier;
import org.apache.camel.spi.ExchangeFactory;
import org.apache.camel.spi.ExchangeFactoryManager;
import org.apache.camel.spi.ExecutorServiceManager;
import org.apache.camel.spi.FactoryFinder;
import org.apache.camel.spi.FactoryFinderResolver;
import org.apache.camel.spi.HeadersMapFactory;
import org.apache.camel.spi.InflightRepository;
import org.apache.camel.spi.Injector;
import org.apache.camel.spi.InterceptEndpointFactory;
import org.apache.camel.spi.InterceptSendToEndpoint;
import org.apache.camel.spi.InterceptStrategy;
import org.apache.camel.spi.InternalProcessorFactory;
import org.apache.camel.spi.Language;
import org.apache.camel.spi.LanguageResolver;
import org.apache.camel.spi.LifecycleStrategy;
import org.apache.camel.spi.LogListener;
import org.apache.camel.spi.ManagementMBeanAssembler;
import org.apache.camel.spi.ManagementNameStrategy;
import org.apache.camel.spi.ManagementStrategy;
import org.apache.camel.spi.ManagementStrategyFactory;
import org.apache.camel.spi.MessageHistoryFactory;
import org.apache.camel.spi.ModelJAXBContextFactory;
import org.apache.camel.spi.ModelToXMLDumper;
import org.apache.camel.spi.ModelineFactory;
import org.apache.camel.spi.NodeIdFactory;
import org.apache.camel.spi.NormalizedEndpointUri;
import org.apache.camel.spi.PackageScanClassResolver;
import org.apache.camel.spi.PackageScanResourceResolver;
import org.apache.camel.spi.PeriodTaskResolver;
import org.apache.camel.spi.PeriodTaskScheduler;
import org.apache.camel.spi.ProcessorExchangeFactory;
import org.apache.camel.spi.ProcessorFactory;
import org.apache.camel.spi.PropertiesComponent;
import org.apache.camel.spi.ReactiveExecutor;
import org.apache.camel.spi.Registry;
import org.apache.camel.spi.ReifierStrategy;
import org.apache.camel.spi.ResourceLoader;
import org.apache.camel.spi.RestBindingJaxbDataFormatFactory;
import org.apache.camel.spi.RestConfiguration;
import org.apache.camel.spi.RestRegistry;
import org.apache.camel.spi.RestRegistryFactory;
import org.apache.camel.spi.RouteController;
import org.apache.camel.spi.RouteError.Phase;
import org.apache.camel.spi.RouteFactory;
import org.apache.camel.spi.RoutePolicyFactory;
import org.apache.camel.spi.RouteStartupOrder;
import org.apache.camel.spi.RouteTemplateParameterSource;
import org.apache.camel.spi.RoutesLoader;
import org.apache.camel.spi.RuntimeEndpointRegistry;
import org.apache.camel.spi.ShutdownStrategy;
import org.apache.camel.spi.StartupStepRecorder;
import org.apache.camel.spi.StreamCachingStrategy;
import org.apache.camel.spi.Tracer;
import org.apache.camel.spi.Transformer;
import org.apache.camel.spi.TransformerRegistry;
import org.apache.camel.spi.TypeConverterRegistry;
import org.apache.camel.spi.UnitOfWorkFactory;
import org.apache.camel.spi.UriFactoryResolver;
import org.apache.camel.spi.UuidGenerator;
import org.apache.camel.spi.Validator;
import org.apache.camel.spi.ValidatorRegistry;
import org.apache.camel.spi.XMLRoutesDefinitionLoader;
import org.apache.camel.support.CamelContextHelper;
import org.apache.camel.support.EndpointHelper;
import org.apache.camel.support.EventHelper;
import org.apache.camel.support.LRUCacheFactory;
import org.apache.camel.support.NormalizedUri;
import org.apache.camel.support.OrderedComparator;
import org.apache.camel.support.ProcessorEndpoint;
import org.apache.camel.support.ResolverHelper;
import org.apache.camel.support.jsse.SSLContextParameters;
import org.apache.camel.support.service.BaseService;
import org.apache.camel.support.service.ServiceHelper;
import org.apache.camel.support.startup.DefaultStartupStepRecorder;
import org.apache.camel.util.IOHelper;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.StopWatch;
import org.apache.camel.util.StringHelper;
import org.apache.camel.util.TimeUtils;
import org.apache.camel.util.URISupport;
import org.apache.camel.vault.VaultConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import static org.apache.camel.spi.UnitOfWork.MDC_CAMEL_CONTEXT_ID;
/**
* Represents the context used to configure routes and the policies to use.
*/
public abstract class AbstractCamelContext extends BaseService
implements ExtendedCamelContext, CatalogCamelContext, Suspendable {
private static final Logger LOG = LoggerFactory.getLogger(AbstractCamelContext.class);
// start auto assigning route ids using numbering 1000 and upwards
int defaultRouteStartupOrder = 1000;
private final AtomicInteger endpointKeyCounter = new AtomicInteger();
private final List endpointStrategies = new ArrayList<>();
private final GlobalEndpointConfiguration globalEndpointConfiguration = new DefaultGlobalEndpointConfiguration();
private final Map components = new ConcurrentHashMap<>();
private final Set routes = new LinkedHashSet<>();
private final List servicesToStop = new CopyOnWriteArrayList<>();
private final List bootstraps = new CopyOnWriteArrayList<>();
private final List startupListeners = new CopyOnWriteArrayList<>();
private final DeferServiceStartupListener deferStartupListener = new DeferServiceStartupListener();
private final Map languages = new ConcurrentHashMap<>();
private final Map dataformats = new ConcurrentHashMap<>();
private final List lifecycleStrategies = new CopyOnWriteArrayList<>();
private final ThreadLocal isStartingRoutes = new ThreadLocal<>();
private final ThreadLocal isSetupRoutes = new ThreadLocal<>();
private final ThreadLocal isLockModel = new ThreadLocal<>();
private final Map factories = new ConcurrentHashMap<>();
private final Map bootstrapFactories = new ConcurrentHashMap<>();
private volatile FactoryFinder bootstrapFactoryFinder;
private volatile ConfigurerResolver bootstrapConfigurerResolver;
private final Map routeServices = new LinkedHashMap<>();
private final Map suspendedRouteServices = new LinkedHashMap<>();
private final Object lock = new Object();
private final RouteController internalRouteController = new InternalRouteController(this);
private final InternalRouteStartupManager internalRouteStartupManager = new InternalRouteStartupManager(this);
private volatile DeferServiceFactory deferServiceFactory;
private volatile AnnotationBasedProcessorFactory annotationBasedProcessorFactory;
private final List routeStartupOrder = new ArrayList<>();
private final StopWatch stopWatch = new StopWatch(false);
private final Map, Object> extensions = new ConcurrentHashMap<>();
private Set logListeners;
private final ThreadLocal> componentsInCreation = new ThreadLocal>() {
@Override
public Set initialValue() {
return new HashSet<>();
}
};
private VetoCamelContextStartException vetoed;
private String managementName;
private ClassLoader applicationContextClassLoader;
private boolean autoCreateComponents = true;
private volatile RestConfiguration restConfiguration;
private volatile VaultConfiguration vaultConfiguration = new VaultConfiguration();
private List interceptStrategies = new ArrayList<>();
private List routePolicyFactories = new ArrayList<>();
// special flags to control the first startup which can are special
private volatile boolean firstStartDone;
private volatile boolean doNotStartRoutesOnFirstStart;
private Initialization initialization = Initialization.Default;
private Boolean autoStartup = Boolean.TRUE;
private Boolean backlogTrace = Boolean.FALSE;
private Boolean backlogTraceStandby = Boolean.FALSE;
private Boolean trace = Boolean.FALSE;
private Boolean traceStandby = Boolean.FALSE;
private String tracePattern;
private String tracingLoggingFormat;
private Boolean modeline = Boolean.FALSE;
private Boolean debug = Boolean.FALSE;
private Boolean messageHistory = Boolean.FALSE;
private Boolean logMask = Boolean.FALSE;
private Boolean logExhaustedMessageBody = Boolean.FALSE;
private Boolean streamCache = Boolean.TRUE;
private Boolean disableJMX = Boolean.FALSE;
private Boolean loadTypeConverters = Boolean.FALSE;
private Boolean loadHealthChecks = Boolean.FALSE;
private Boolean devConsole = Boolean.FALSE;
private Boolean sourceLocationEnabled = Boolean.FALSE;
private Boolean typeConverterStatisticsEnabled = Boolean.FALSE;
private Boolean dumpRoutes = Boolean.FALSE;
private Boolean useMDCLogging = Boolean.FALSE;
private String mdcLoggingKeysPattern;
private Boolean useDataType = Boolean.FALSE;
private Boolean useBreadcrumb = Boolean.FALSE;
private Boolean allowUseOriginalMessage = Boolean.FALSE;
private Boolean caseInsensitiveHeaders = Boolean.TRUE;
private Boolean autowiredEnabled = Boolean.TRUE;
private String basePackageScan;
private boolean lightweight;
private Long delay;
@Deprecated
private ErrorHandlerFactory errorHandlerFactory;
private Map globalOptions = new HashMap<>();
private volatile String version;
private volatile PropertiesComponent propertiesComponent;
private volatile CamelContextNameStrategy nameStrategy;
private volatile String description;
private volatile ExchangeFactoryManager exchangeFactoryManager;
private volatile ExchangeFactory exchangeFactory;
private volatile ProcessorExchangeFactory processorExchangeFactory;
private volatile ReactiveExecutor reactiveExecutor;
private volatile ManagementNameStrategy managementNameStrategy;
private volatile Registry registry;
private volatile TypeConverter typeConverter;
private volatile TypeConverterRegistry typeConverterRegistry;
private volatile Injector injector;
private volatile CamelBeanPostProcessor beanPostProcessor;
private volatile CamelDependencyInjectionAnnotationFactory dependencyInjectionAnnotationFactory;
private volatile ComponentResolver componentResolver;
private volatile ComponentNameResolver componentNameResolver;
private volatile LanguageResolver languageResolver;
private volatile ConfigurerResolver configurerResolver;
private volatile UriFactoryResolver uriFactoryResolver;
private volatile DataFormatResolver dataFormatResolver;
private volatile HealthCheckResolver healthCheckResolver;
private volatile DevConsoleResolver devConsoleResolver;
private volatile ManagementStrategy managementStrategy;
private volatile ManagementMBeanAssembler managementMBeanAssembler;
private volatile RestRegistryFactory restRegistryFactory;
private volatile RestRegistry restRegistry;
private volatile HeadersMapFactory headersMapFactory;
private volatile CliConnectorFactory cliConnectorFactory;
private volatile BeanProxyFactory beanProxyFactory;
private volatile BeanProcessorFactory beanProcessorFactory;
private volatile XMLRoutesDefinitionLoader xmlRoutesDefinitionLoader;
private volatile RoutesLoader routesLoader;
private volatile ResourceLoader resourceLoader;
private volatile ModelToXMLDumper modelToXMLDumper;
private volatile RestBindingJaxbDataFormatFactory restBindingJaxbDataFormatFactory;
private volatile RuntimeCamelCatalog runtimeCamelCatalog;
private volatile ClassResolver classResolver;
private volatile PackageScanClassResolver packageScanClassResolver;
private volatile PackageScanResourceResolver packageScanResourceResolver;
private volatile NodeIdFactory nodeIdFactory;
private volatile ModelineFactory modelineFactory;
private volatile ProcessorFactory processorFactory;
private volatile PeriodTaskResolver periodTaskResolver;
private volatile PeriodTaskScheduler periodTaskScheduler;
private volatile InternalProcessorFactory internalProcessorFactory;
private volatile InterceptEndpointFactory interceptEndpointFactory;
private volatile RouteFactory routeFactory;
private volatile MessageHistoryFactory messageHistoryFactory;
private volatile FactoryFinderResolver factoryFinderResolver;
private volatile StreamCachingStrategy streamCachingStrategy;
private volatile InflightRepository inflightRepository;
private volatile AsyncProcessorAwaitManager asyncProcessorAwaitManager;
private volatile ShutdownStrategy shutdownStrategy;
private volatile ModelJAXBContextFactory modelJAXBContextFactory;
private volatile ExecutorServiceManager executorServiceManager;
private volatile UuidGenerator uuidGenerator;
private volatile UnitOfWorkFactory unitOfWorkFactory;
private volatile RouteController routeController;
private volatile ScheduledExecutorService errorHandlerExecutorService;
private volatile BeanIntrospection beanIntrospection;
private volatile Tracer tracer;
private volatile boolean eventNotificationApplicable;
private volatile TransformerRegistry transformerRegistry;
private volatile ValidatorRegistry validatorRegistry;
private volatile StartupStepRecorder startupStepRecorder = new DefaultStartupStepRecorder();
private EndpointRegistry endpoints;
private RuntimeEndpointRegistry runtimeEndpointRegistry;
private ShutdownRoute shutdownRoute = ShutdownRoute.Default;
private ShutdownRunningTask shutdownRunningTask = ShutdownRunningTask.CompleteCurrentTaskOnly;
private Debugger debugger;
private long buildTaken;
private long initTaken;
private long startDate;
private SSLContextParameters sslContextParameters;
private StartupSummaryLevel startupSummaryLevel = StartupSummaryLevel.Default;
private boolean logJvmUptime;
/**
* Creates the {@link CamelContext} using {@link org.apache.camel.support.DefaultRegistry} as registry.
*
* Use one of the other constructors to force use an explicit registry.
*/
public AbstractCamelContext() {
this(true);
}
/**
* Creates the {@link CamelContext} using the given registry
*
* @param registry the registry
*/
public AbstractCamelContext(Registry registry) {
this();
setRegistry(registry);
}
public AbstractCamelContext(boolean build) {
// create a provisional (temporary) endpoint registry at first since end
// users may access endpoints before CamelContext is started
// we will later transfer the endpoints to the actual
// DefaultEndpointRegistry later, but we do this to startup Camel faster.
this.endpoints = new ProvisionalEndpointRegistry();
// add the defer service startup listener
this.startupListeners.add(deferStartupListener);
// add a default LifecycleStrategy that discover strategies on the registry and invoke them
this.lifecycleStrategies.add(new OnCamelContextLifecycleStrategy());
// add a default LifecycleStrategy to customize services using customizers from registry
this.lifecycleStrategies.add(new CustomizersLifecycleStrategy(this));
// add a default autowired strategy
this.lifecycleStrategies.add(new DefaultAutowiredLifecycleStrategy(this));
// add the default bootstrap closer
this.bootstraps.add(new DefaultServiceBootstrapCloseable(this));
// add a cleaner for FactoryFinder used only when bootstrapping the context
this.bootstraps.add(new BootstrapCloseable() {
@Override
public void close() throws IOException {
bootstrapFactories.clear();
}
});
if (build) {
try {
build();
} catch (Exception e) {
throw new RuntimeException("Error initializing CamelContext", e);
}
}
}
protected static T lookup(CamelContext context, String ref, Class type) {
try {
return context.getRegistry().lookupByNameAndType(ref, type);
} catch (Exception e) {
// need to ignore not same type and return it as null
return null;
}
}
/**
* Reset context counter to a preset value. Mostly used for tests to ensure a predictable getName()
*
* @param value new value for the context counter
*/
public static void setContextCounter(int value) {
DefaultCamelContextNameStrategy.setCounter(value);
DefaultManagementNameStrategy.setCounter(value);
}
public void close() throws IOException {
try {
stop();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new IOException(e);
}
}
public CamelContext getCamelContextReference() {
return this;
}
@Override
public byte getStatusPhase() {
return status;
}
/**
* Whether to eager create {@link TypeConverter} during initialization of CamelContext. This is enabled by default
* to optimize camel-core.
*/
protected boolean eagerCreateTypeConverter() {
return true;
}
@Override
public T adapt(Class type) {
return type.cast(this);
}
@Override
public T getExtension(Class type) {
if (type.isInstance(this)) {
return type.cast(this);
}
Object extension = extensions.get(type);
if (extension instanceof Supplier) {
extension = ((Supplier) extension).get();
setExtension(type, (T) extension);
}
return (T) extension;
}
@Override
public void setExtension(Class type, T module) {
if (module != null) {
try {
extensions.put(type, doAddService(module));
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
}
}
public void setDefaultExtension(Class type, Supplier module) {
if (module != null) {
extensions.putIfAbsent(type, module);
}
}
@Override
public boolean isVetoStarted() {
return vetoed != null;
}
@Deprecated
public Initialization getInitialization() {
return initialization;
}
@Deprecated
public void setInitialization(Initialization initialization) {
this.initialization = initialization;
}
@Override
public String getName() {
return getNameStrategy().getName();
}
@Override
public void setName(String name) {
// use an explicit name strategy since an explicit name was provided to be used
setNameStrategy(new ExplicitCamelContextNameStrategy(name));
}
@Override
public CamelContextNameStrategy getNameStrategy() {
if (nameStrategy == null) {
synchronized (lock) {
if (nameStrategy == null) {
setNameStrategy(createCamelContextNameStrategy());
}
}
}
return nameStrategy;
}
@Override
public void setNameStrategy(CamelContextNameStrategy nameStrategy) {
this.nameStrategy = doAddService(nameStrategy);
}
@Override
public String getDescription() {
return description;
}
@Override
public void setDescription(String description) {
this.description = description;
}
@Override
public ManagementNameStrategy getManagementNameStrategy() {
if (managementNameStrategy == null) {
synchronized (lock) {
if (managementNameStrategy == null) {
setManagementNameStrategy(createManagementNameStrategy());
}
}
}
return managementNameStrategy;
}
@Override
public void setManagementNameStrategy(ManagementNameStrategy managementNameStrategy) {
this.managementNameStrategy = doAddService(managementNameStrategy);
}
@Override
public String getManagementName() {
return managementName;
}
@Override
public void setManagementName(String managementName) {
this.managementName = managementName;
}
@Override
public Component hasComponent(String componentName) {
if (components.isEmpty()) {
return null;
}
return components.get(componentName);
}
@Override
public void addComponent(String componentName, final Component component) {
ObjectHelper.notNull(component, "component");
component.setCamelContext(getCamelContextReference());
if (isStarted()) {
// start component if context is already started (camel will start components when it starts)
ServiceHelper.startService(component);
} else {
// otherwise init the component
ServiceHelper.initService(component);
}
Component oldValue = components.putIfAbsent(componentName, component);
if (oldValue != null) {
throw new IllegalArgumentException("Cannot add component as its already previously added: " + componentName);
}
postInitComponent(componentName, component);
}
private void postInitComponent(String componentName, final Component component) {
for (LifecycleStrategy strategy : lifecycleStrategies) {
strategy.onComponentAdd(componentName, component);
}
}
@Override
public Component getComponent(String name) {
return getComponent(name, autoCreateComponents, true);
}
@Override
public Component getComponent(String name, boolean autoCreateComponents) {
return getComponent(name, autoCreateComponents, true);
}
@Override
public Component getComponent(String name, boolean autoCreateComponents, boolean autoStart) {
// ensure CamelContext are initialized before we can get a component
build();
// Check if the named component is already being created, that would mean
// that the initComponent has triggered a new getComponent
if (componentsInCreation.get().contains(name)) {
throw new IllegalStateException(
"Circular dependency detected, the component " + name + " is already being created");
}
try {
// Flag used to mark a component of being created.
final AtomicBoolean created = new AtomicBoolean();
// atomic operation to get/create a component. Avoid global locks.
final Component component = components.computeIfAbsent(name, new Function() {
@Override
public Component apply(String comp) {
created.set(true);
return AbstractCamelContext.this.initComponent(name, autoCreateComponents);
}
});
// Start the component after its creation as if it is a component proxy
// that creates/start a delegated component, we may end up in a deadlock
if (component != null && created.get() && autoStart && (isStarted() || isStarting())) {
// If the component is looked up after the context is started,
// lets start it up.
StartupStep step = startupStepRecorder.beginStep(Component.class, name, "Start Component");
startService(component);
startupStepRecorder.endStep(step);
}
return component;
} catch (Exception e) {
throw new RuntimeCamelException("Cannot auto create component: " + name, e);
} finally {
// remove the reference to the component being created
componentsInCreation.get().remove(name);
}
}
/**
* Function to initialize a component and auto start. Returns null if the autoCreateComponents is disabled
*/
private Component initComponent(String name, boolean autoCreateComponents) {
Component component = null;
if (autoCreateComponents) {
StartupStep step = startupStepRecorder.beginStep(Component.class, name, "Resolve Component");
try {
if (LOG.isDebugEnabled()) {
LOG.debug("Using ComponentResolver: {} to resolve component with name: {}", getComponentResolver(), name);
}
// Mark the component as being created so we can detect circular
// requests.
//
// In spring apps, the component resolver may trigger a new
// getComponent because of the underlying bean factory and as
// the endpoints are registered as singleton, the spring factory
// creates the bean and then check the type so the getComponent
// is always triggered.
//
// Simple circular dependency:
//
//
//
//
//
//
//
//
// Complex circular dependency:
//
//
//
//
//
//
//
//
// This would freeze the app (lock or infinite loop).
//
// See https://issues.apache.org/jira/browse/CAMEL-11225
componentsInCreation.get().add(name);
component = ResolverHelper.lookupComponentInRegistryWithFallback(getCamelContextReference(), name);
if (component == null) {
component = getComponentResolver().resolveComponent(name, getCamelContextReference());
}
if (component != null) {
component.setCamelContext(getCamelContextReference());
ServiceHelper.buildService(component);
postInitComponent(name, component);
}
} catch (Exception e) {
throw new RuntimeCamelException("Cannot auto create component: " + name, e);
}
startupStepRecorder.endStep(step);
}
return component;
}
@Override
public T getComponent(String name, Class componentType) {
Component component = getComponent(name);
if (componentType.isInstance(component)) {
return componentType.cast(component);
} else {
String message;
if (component == null) {
message = "Did not find component given by the name: " + name;
} else {
message = "Found component of type: " + component.getClass() + " instead of expected: " + componentType;
}
throw new IllegalArgumentException(message);
}
}
// Endpoint Management Methods
// -----------------------------------------------------------------------
@Override
public Component removeComponent(String componentName) {
Component oldComponent = components.remove(componentName);
if (oldComponent != null) {
try {
stopServices(oldComponent);
} catch (Exception e) {
LOG.warn("Error stopping component " + oldComponent + ". This exception will be ignored.", e);
}
for (LifecycleStrategy strategy : lifecycleStrategies) {
strategy.onComponentRemove(componentName, oldComponent);
}
}
return oldComponent;
}
@Override
public EndpointRegistry getEndpointRegistry() {
return endpoints;
}
@Override
public Collection getEndpoints() {
return endpoints.getReadOnlyValues();
}
@Override
public Map getEndpointMap() {
Map answer = new TreeMap<>();
for (Map.Entry entry : endpoints.entrySet()) {
answer.put(entry.getKey().get(), entry.getValue());
}
return answer;
}
@Override
public Endpoint hasEndpoint(String uri) {
if (endpoints.isEmpty()) {
return null;
}
return endpoints.get(getEndpointKey(uri));
}
@Override
public Endpoint hasEndpoint(NormalizedEndpointUri uri) {
if (endpoints.isEmpty()) {
return null;
}
return endpoints.get(uri);
}
@Override
public Endpoint addEndpoint(String uri, Endpoint endpoint) throws Exception {
Endpoint oldEndpoint;
startService(endpoint);
oldEndpoint = endpoints.remove(getEndpointKey(uri));
for (LifecycleStrategy strategy : lifecycleStrategies) {
strategy.onEndpointAdd(endpoint);
}
addEndpointToRegistry(uri, endpoint);
if (oldEndpoint != null && oldEndpoint != endpoint) {
stopServices(oldEndpoint);
}
return oldEndpoint;
}
@Override
public void removeEndpoint(Endpoint endpoint) throws Exception {
removeEndpoints(endpoint.getEndpointUri());
}
@Override
public Collection removeEndpoints(String uri) throws Exception {
Collection answer = new ArrayList<>();
Endpoint oldEndpoint = endpoints.remove(getEndpointKey(uri));
if (oldEndpoint != null) {
answer.add(oldEndpoint);
stopServices(oldEndpoint);
} else {
List toRemove = new ArrayList<>();
for (Map.Entry entry : endpoints.entrySet()) {
oldEndpoint = entry.getValue();
if (EndpointHelper.matchEndpoint(this, oldEndpoint.getEndpointUri(), uri)) {
try {
stopServices(oldEndpoint);
} catch (Exception e) {
LOG.warn("Error stopping endpoint " + oldEndpoint + ". This exception will be ignored.", e);
}
answer.add(oldEndpoint);
toRemove.add(entry.getKey());
}
}
for (NormalizedUri key : toRemove) {
endpoints.remove(key);
}
}
// notify lifecycle its being removed
for (Endpoint endpoint : answer) {
for (LifecycleStrategy strategy : lifecycleStrategies) {
strategy.onEndpointRemove(endpoint);
}
}
return answer;
}
@Override
public NormalizedEndpointUri normalizeUri(String uri) {
try {
uri = EndpointHelper.resolveEndpointUriPropertyPlaceholders(this, uri);
return NormalizedUri.newNormalizedUri(uri, false);
} catch (ResolveEndpointFailedException e) {
throw e;
} catch (Exception e) {
throw new ResolveEndpointFailedException(uri, e);
}
}
@Override
public Endpoint getEndpoint(String uri) {
StartupStep step = null;
// only record startup step during startup (not started)
if (!isStarted() && startupStepRecorder.isEnabled()) {
String u = URISupport.sanitizeUri(uri);
step = startupStepRecorder.beginStep(Endpoint.class, u, "Get Endpoint");
}
Endpoint answer = doGetEndpoint(uri, null, false, false);
if (step != null) {
startupStepRecorder.endStep(step);
}
return answer;
}
@Override
public Endpoint getEndpoint(NormalizedEndpointUri uri) {
return doGetEndpoint(uri.getUri(), null, true, false);
}
@Override
public Endpoint getPrototypeEndpoint(String uri) {
return doGetEndpoint(uri, null, false, true);
}
@Override
public Endpoint getPrototypeEndpoint(NormalizedEndpointUri uri) {
return doGetEndpoint(uri.getUri(), null, true, true);
}
@Override
public Endpoint getEndpoint(String uri, Map parameters) {
return doGetEndpoint(uri, parameters, false, false);
}
@Override
public Endpoint getEndpoint(NormalizedEndpointUri uri, Map parameters) {
return doGetEndpoint(uri.getUri(), parameters, true, false);
}
protected Endpoint doGetEndpoint(String uri, Map parameters, boolean normalized, boolean prototype) {
// ensure CamelContext are initialized before we can get an endpoint
build();
StringHelper.notEmpty(uri, "uri");
LOG.trace("Getting endpoint with uri: {} and parameters: {}", uri, parameters);
// in case path has property placeholders then try to let property component resolve those
if (!normalized) {
uri = EndpointHelper.resolveEndpointUriPropertyPlaceholders(this, uri);
}
final String rawUri = uri;
// normalize uri so we can do endpoint hits with minor mistakes and
// parameters is not in the same order
if (!normalized) {
uri = EndpointHelper.normalizeEndpointUri(uri);
}
LOG.trace("Getting endpoint with raw uri: {}, normalized uri: {}", rawUri, uri);
String scheme;
Endpoint answer = null;
if (!prototype) {
// use optimized method to get the endpoint uri
NormalizedUri key = NormalizedUri.newNormalizedUri(uri, true);
// only lookup and reuse existing endpoints if not prototype scoped
answer = endpoints.get(key);
}
if (answer == null) {
try {
scheme = StringHelper.before(uri, ":");
if (scheme == null) {
// it may refer to a logical endpoint
answer = getRegistry().lookupByNameAndType(uri, Endpoint.class);
if (answer != null) {
return answer;
} else {
throw new NoSuchEndpointException(uri);
}
}
LOG.trace("Endpoint uri: {} is from component with name: {}", uri, scheme);
Component component = getComponent(scheme);
ServiceHelper.initService(component);
// Ask the component to resolve the endpoint.
if (component != null) {
LOG.trace("Creating endpoint from uri: {} using component: {}", uri, component);
// Have the component create the endpoint if it can.
answer = component.createEndpoint(
component.useRawUri() ? rawUri : uri,
parameters);
if (answer != null && LOG.isDebugEnabled()) {
LOG.debug("{} converted to endpoint: {} by component: {}", URISupport.sanitizeUri(uri), answer,
component);
}
}
if (answer == null) {
// no component then try in registry and elsewhere
answer = createEndpoint(uri);
LOG.trace("No component to create endpoint from uri: {} fallback lookup in registry -> {}", uri, answer);
}
if (answer != null) {
if (!prototype) {
addService(answer);
// register in registry
answer = addEndpointToRegistry(uri, answer);
} else {
addPrototypeService(answer);
// if there is endpoint strategies, then use the endpoints they return
// as this allows to intercept endpoints etc.
for (EndpointStrategy strategy : endpointStrategies) {
answer = strategy.registerEndpoint(uri, answer);
}
}
}
} catch (NoSuchEndpointException e) {
// throw as-is
throw e;
} catch (Exception e) {
throw new ResolveEndpointFailedException(uri, e);
}
}
// unknown scheme
if (answer == null) {
throw new NoSuchEndpointException(uri);
}
return answer;
}
@Override
public T getEndpoint(String name, Class endpointType) {
Endpoint endpoint = getEndpoint(name);
if (endpoint == null) {
throw new NoSuchEndpointException(name);
}
if (endpoint instanceof InterceptSendToEndpoint) {
endpoint = ((InterceptSendToEndpoint) endpoint).getOriginalEndpoint();
}
if (endpointType.isInstance(endpoint)) {
return endpointType.cast(endpoint);
} else {
throw new IllegalArgumentException(
"The endpoint is not of type: " + endpointType + " but is: " + endpoint.getClass().getCanonicalName());
}
}
@Override
public void registerEndpointCallback(EndpointStrategy strategy) {
if (!endpointStrategies.contains(strategy)) {
// let it be invoked for already registered endpoints so it can
// catch-up.
endpointStrategies.add(strategy);
for (Endpoint endpoint : getEndpoints()) {
Endpoint newEndpoint = strategy.registerEndpoint(endpoint.getEndpointUri(), endpoint);
if (newEndpoint != null) {
// put will replace existing endpoint with the new endpoint
endpoints.put(getEndpointKey(endpoint.getEndpointUri()), newEndpoint);
}
}
}
}
/**
* Strategy to add the given endpoint to the internal endpoint registry
*
* @param uri uri of the endpoint
* @param endpoint the endpoint to add
* @return the added endpoint
*/
protected Endpoint addEndpointToRegistry(String uri, Endpoint endpoint) {
StringHelper.notEmpty(uri, "uri");
ObjectHelper.notNull(endpoint, "endpoint");
// if there is endpoint strategies, then use the endpoints they return
// as this allows to intercept endpoints etc.
for (EndpointStrategy strategy : endpointStrategies) {
endpoint = strategy.registerEndpoint(uri, endpoint);
}
endpoints.put(getEndpointKey(uri, endpoint), endpoint);
return endpoint;
}
/**
* Gets the endpoint key to use for lookup or whe adding endpoints to the {@link DefaultEndpointRegistry}
*
* @param uri the endpoint uri
* @return the key
*/
protected NormalizedUri getEndpointKey(String uri) {
return NormalizedUri.newNormalizedUri(uri, false);
}
/**
* Gets the endpoint key to use for lookup or whe adding endpoints to the {@link DefaultEndpointRegistry}
*
* @param uri the endpoint uri
* @param endpoint the endpoint
* @return the key
*/
protected NormalizedUri getEndpointKey(String uri, Endpoint endpoint) {
if (endpoint != null && !endpoint.isSingleton()) {
int counter = endpointKeyCounter.incrementAndGet();
return NormalizedUri.newNormalizedUri(uri + ":" + counter, false);
} else {
return NormalizedUri.newNormalizedUri(uri, false);
}
}
// Route Management Methods
// -----------------------------------------------------------------------
@Override
public GlobalEndpointConfiguration getGlobalEndpointConfiguration() {
return globalEndpointConfiguration;
}
@Override
public RouteController getRouteController() {
if (routeController == null) {
synchronized (lock) {
if (routeController == null) {
setRouteController(createRouteController());
}
}
}
return routeController;
}
@Override
public void setRouteController(RouteController routeController) {
this.routeController = doAddService(routeController);
}
@Override
public List getRouteStartupOrder() {
return routeStartupOrder;
}
@Override
public List getRoutes() {
// lets return a copy of the collection as objects are removed later
// when services are stopped
if (routes.isEmpty()) {
return Collections.emptyList();
} else {
synchronized (routes) {
return new ArrayList<>(routes);
}
}
}
@Override
public int getRoutesSize() {
return routes.size();
}
@Override
public Route getRoute(String id) {
if (id != null) {
for (Route route : getRoutes()) {
if (route.getId().equals(id)) {
return route;
}
}
}
return null;
}
@Override
public Processor getProcessor(String id) {
for (Route route : getRoutes()) {
List list = route.filter(id);
if (list.size() == 1) {
return list.get(0);
}
}
return null;
}
@Override
public T getProcessor(String id, Class type) {
Processor answer = getProcessor(id);
if (answer != null) {
return type.cast(answer);
}
return null;
}
public void removeRoute(Route route) {
synchronized (this.routes) {
this.routes.remove(route);
}
}
public void addRoute(Route route) {
synchronized (this.routes) {
this.routes.add(route);
}
}
@Override
public void addRoutes(RoutesBuilder builder) throws Exception {
// in case the builder is also a route configuration builder
// then we need to add the configuration first
if (builder instanceof RouteConfigurationsBuilder) {
addRoutesConfigurations((RouteConfigurationsBuilder) builder);
}
try (LifecycleHelper helper = new LifecycleHelper()) {
build();
LOG.debug("Adding routes from builder: {}", builder);
builder.addRoutesToCamelContext(AbstractCamelContext.this);
}
}
@Override
public void addTemplatedRoutes(RoutesBuilder builder) throws Exception {
try (LifecycleHelper helper = new LifecycleHelper()) {
build();
LOG.debug("Adding templated routes from builder: {}", builder);
builder.addTemplatedRoutesToCamelContext(AbstractCamelContext.this);
}
}
@Override
public void addRoutesConfigurations(RouteConfigurationsBuilder builder) throws Exception {
try (LifecycleHelper helper = new LifecycleHelper()) {
build();
LOG.debug("Adding route configurations from builder: {}", builder);
builder.addRouteConfigurationsToCamelContext(AbstractCamelContext.this);
}
}
public ServiceStatus getRouteStatus(String key) {
RouteService routeService = routeServices.get(key);
if (routeService != null) {
return routeService.getStatus();
}
return null;
}
public boolean isStartingRoutes() {
Boolean answer = isStartingRoutes.get();
return answer != null && answer;
}
public void setStartingRoutes(boolean starting) {
if (starting) {
isStartingRoutes.set(true);
} else {
isStartingRoutes.remove();
}
}
public boolean isLockModel() {
Boolean answer = isLockModel.get();
return answer != null && answer;
}
public void setLockModel(boolean lockModel) {
if (lockModel) {
isLockModel.set(true);
} else {
isLockModel.remove();
}
}
@Override
public boolean isSetupRoutes() {
Boolean answer = isSetupRoutes.get();
return answer != null && answer;
}
public void startAllRoutes() throws Exception {
internalRouteStartupManager.doStartOrResumeRoutes(routeServices, true, true, false, false);
}
public void stopAllRoutes() throws Exception {
RouteController controller = getRouteController();
if (controller == null) {
// in case we are called during shutdown and controller is null
return;
}
// stop all routes in reverse order that they were started
Comparator comparator = Comparator.comparingInt(RouteStartupOrder::getStartupOrder);
if (shutdownStrategy == null || shutdownStrategy.isShutdownRoutesInReverseOrder()) {
comparator = comparator.reversed();
}
List routesOrdered = new ArrayList<>(getRouteStartupOrder());
routesOrdered.sort(comparator);
for (RouteStartupOrder order : routesOrdered) {
Route route = order.getRoute();
boolean stopped = controller.getRouteStatus(route.getRouteId()).isStopped();
if (!stopped) {
stopRoute(route.getRouteId(), LoggingLevel.DEBUG);
}
}
// stop any remainder routes
for (Route route : getRoutes()) {
boolean stopped = controller.getRouteStatus(route.getRouteId()).isStopped();
if (!stopped) {
stopRoute(route.getRouteId(), LoggingLevel.DEBUG);
}
}
if (startupSummaryLevel != StartupSummaryLevel.Oneline
&& startupSummaryLevel != StartupSummaryLevel.Off) {
logRouteStopSummary(LoggingLevel.INFO);
}
}
public void removeAllRoutes() throws Exception {
// stop all routes in reverse order that they were started
Comparator comparator = Comparator.comparingInt(RouteStartupOrder::getStartupOrder);
if (shutdownStrategy == null || shutdownStrategy.isShutdownRoutesInReverseOrder()) {
comparator = comparator.reversed();
}
List routesOrdered = new ArrayList<>(getRouteStartupOrder());
routesOrdered.sort(comparator);
for (RouteStartupOrder order : routesOrdered) {
Route route = order.getRoute();
boolean stopped = getRouteController().getRouteStatus(route.getRouteId()).isStopped();
if (!stopped) {
stopRoute(route.getRouteId(), LoggingLevel.DEBUG);
}
}
// stop any remainder routes
for (Route route : getRoutes()) {
boolean stopped = getRouteController().getRouteStatus(route.getRouteId()).isStopped();
if (!stopped) {
stopRoute(route.getRouteId(), LoggingLevel.DEBUG);
}
}
// do not be noisy when removing routes
// as this is used by route-reload functionality, so lets be brief
logRouteStopSummary(LoggingLevel.DEBUG);
// remove all routes
for (Route route : getRoutes()) {
removeRoute(route.getRouteId(), LoggingLevel.DEBUG);
}
}
public synchronized void startRoute(String routeId) throws Exception {
DefaultRouteError.reset(this, routeId);
RouteService routeService = routeServices.get(routeId);
if (routeService != null) {
try {
startRouteService(routeService, false);
} catch (Exception e) {
DefaultRouteError.set(this, routeId, Phase.START, e);
throw e;
}
}
}
public synchronized void resumeRoute(String routeId) throws Exception {
DefaultRouteError.reset(this, routeId);
try {
if (!routeSupportsSuspension(routeId)) {
// start route if suspension is not supported
startRoute(routeId);
return;
}
RouteService routeService = routeServices.get(routeId);
if (routeService != null) {
resumeRouteService(routeService);
// must resume the route as well
Route route = getRoute(routeId);
ServiceHelper.resumeService(route);
}
} catch (Exception e) {
DefaultRouteError.set(this, routeId, Phase.RESUME, e);
throw e;
}
}
public synchronized boolean stopRoute(
String routeId, long timeout, TimeUnit timeUnit, boolean abortAfterTimeout, LoggingLevel loggingLevel)
throws Exception {
DefaultRouteError.reset(this, routeId);
RouteService routeService = routeServices.get(routeId);
if (routeService != null) {
try {
RouteStartupOrder route = new DefaultRouteStartupOrder(1, routeService.getRoute(), routeService);
boolean completed = getShutdownStrategy().shutdown(this, route, timeout, timeUnit, abortAfterTimeout);
if (completed) {
// must stop route service as well
stopRouteService(routeService, false, loggingLevel);
} else {
// shutdown was aborted, make sure route is re-started properly
startRouteService(routeService, false);
}
return completed;
} catch (Exception e) {
DefaultRouteError.set(this, routeId, Phase.STOP, e);
throw e;
}
}
return false;
}
public void stopRoute(String routeId) throws Exception {
stopRoute(routeId, LoggingLevel.INFO);
}
public void stopRoute(String routeId, LoggingLevel loggingLevel) throws Exception {
doShutdownRoute(routeId, getShutdownStrategy().getTimeout(), getShutdownStrategy().getTimeUnit(), false, loggingLevel);
}
public void stopRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception {
doShutdownRoute(routeId, timeout, timeUnit, false, LoggingLevel.INFO);
}
protected synchronized void doShutdownRoute(
String routeId, long timeout, TimeUnit timeUnit, boolean removingRoutes, LoggingLevel loggingLevel)
throws Exception {
DefaultRouteError.reset(this, routeId);
RouteService routeService = routeServices.get(routeId);
if (routeService != null) {
try {
List routeList = new ArrayList<>(1);
RouteStartupOrder order = new DefaultRouteStartupOrder(1, routeService.getRoute(), routeService);
routeList.add(order);
getShutdownStrategy().shutdown(this, routeList, timeout, timeUnit);
// must stop route service as well (and remove the routes from
// management)
stopRouteService(routeService, removingRoutes, loggingLevel);
} catch (Exception e) {
DefaultRouteError.set(this, routeId, removingRoutes ? Phase.SHUTDOWN : Phase.STOP, e);
throw e;
}
}
}
@Override
public synchronized boolean removeRoute(String routeId) throws Exception {
return removeRoute(routeId, LoggingLevel.INFO);
}
protected synchronized boolean removeRoute(String routeId, LoggingLevel loggingLevel) throws Exception {
DefaultRouteError.reset(this, routeId);
// gather a map of all the endpoints in use by the routes, so we can
// known if a given endpoints is in use
// by one or more routes, when we remove the route
Map> endpointsInUse = new HashMap<>();
for (Map.Entry entry : routeServices.entrySet()) {
endpointsInUse.put(entry.getKey(), entry.getValue().gatherEndpoints());
}
RouteService routeService = routeServices.get(routeId);
if (routeService != null) {
if (getRouteStatus(routeId).isStopped()) {
try {
routeService.setRemovingRoutes(true);
shutdownRouteService(routeService, loggingLevel);
routeServices.remove(routeId);
// remove route from startup order as well, as it was
// removed
routeStartupOrder.removeIf(order -> order.getRoute().getId().equals(routeId));
// from the route which we have removed, then remove all its
// private endpoints
// (eg the endpoints which are not in use by other routes)
Set toRemove = new LinkedHashSet<>();
for (Endpoint endpoint : endpointsInUse.get(routeId)) {
// how many times is the endpoint in use
int count = 0;
for (Set endpointSet : endpointsInUse.values()) {
if (endpointSet.contains(endpoint)) {
count++;
}
}
// notice we will count ourselves so if there is only 1
// then its safe to remove
if (count <= 1) {
toRemove.add(endpoint);
}
}
for (Endpoint endpoint : toRemove) {
LOG.debug("Removing: {} which was only in use by route: {}", endpoint, routeId);
removeEndpoint(endpoint);
}
} catch (Exception e) {
DefaultRouteError.set(this, routeId, Phase.REMOVE, e);
throw e;
}
return true;
} else {
return false;
}
}
return false;
}
public void suspendRoute(String routeId) throws Exception {
suspendRoute(routeId, getShutdownStrategy().getTimeout(), getShutdownStrategy().getTimeUnit());
}
public synchronized void suspendRoute(String routeId, long timeout, TimeUnit timeUnit) throws Exception {
DefaultRouteError.reset(this, routeId);
try {
if (!routeSupportsSuspension(routeId)) {
stopRoute(routeId, timeout, timeUnit);
return;
}
RouteService routeService = routeServices.get(routeId);
if (routeService != null) {
List routeList = new ArrayList<>(1);
Route route = routeService.getRoute();
RouteStartupOrder order = new DefaultRouteStartupOrder(1, route, routeService);
routeList.add(order);
getShutdownStrategy().suspend(this, routeList, timeout, timeUnit);
// must suspend route service as well
suspendRouteService(routeService);
// must suspend the route as well
if (route instanceof SuspendableService) {
((SuspendableService) route).suspend();
}
}
} catch (Exception e) {
DefaultRouteError.set(this, routeId, Phase.SUSPEND, e);
throw e;
}
}
@Override
public void addService(Object object) throws Exception {
addService(object, true);
}
@Override
public void addService(Object object, boolean stopOnShutdown) throws Exception {
addService(object, stopOnShutdown, false);
}
@Override
public void addService(Object object, boolean stopOnShutdown, boolean forceStart) throws Exception {
internalAddService(object, stopOnShutdown, forceStart, true);
}
@Override
public void addPrototypeService(Object object) throws Exception {
doAddService(object, false, true, false);
}
protected T doAddService(T object) {
return doAddService(object, true);
}
protected T doAddService(T object, boolean stopOnShutdown) {
return doAddService(object, stopOnShutdown, true, true);
}
protected T doAddService(T object, boolean stopOnShutdown, boolean forceStart, boolean useLifecycleStrategies) {
try {
internalAddService(object, stopOnShutdown, forceStart, useLifecycleStrategies);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
return object;
}
private void internalAddService(
Object object, boolean stopOnShutdown,
boolean forceStart, boolean useLifecycleStrategies)
throws Exception {
if (object == null) {
return;
}
// inject CamelContext
CamelContextAware.trySetCamelContext(object, getCamelContextReference());
if (object instanceof Service) {
Service service = (Service) object;
if (useLifecycleStrategies) {
for (LifecycleStrategy strategy : lifecycleStrategies) {
if (service instanceof Endpoint) {
// use specialized endpoint add
strategy.onEndpointAdd((Endpoint) service);
} else {
Route route;
if (service instanceof RouteAware) {
route = ((RouteAware) service).getRoute();
} else {
// if the service is added while creating a new route then grab the route from the startup manager
route = internalRouteStartupManager.getSetupRoute();
}
strategy.onServiceAdd(getCamelContextReference(), service, route);
}
}
}
if (!forceStart) {
ServiceHelper.initService(service);
// now start the service (and defer starting if CamelContext is
// starting up itself)
deferStartService(object, stopOnShutdown);
} else {
// only add to services to close if its a singleton
// otherwise we could for example end up with a lot of prototype
// scope endpoints
boolean singleton = true; // assume singleton by default
if (object instanceof IsSingleton) {
singleton = ((IsSingleton) service).isSingleton();
}
// do not add endpoints as they have their own list
if (singleton && !(service instanceof Endpoint)) {
// only add to list of services to stop if its not already there
if (stopOnShutdown && !hasService(service)) {
// special for type converter / type converter registry which is stopped manual later
boolean tc = service instanceof TypeConverter || service instanceof TypeConverterRegistry;
if (!tc) {
servicesToStop.add(service);
}
}
}
if (isStartingOrStarted()) {
ServiceHelper.startService(service);
} else {
ServiceHelper.initService(service);
deferStartService(object, stopOnShutdown, true);
}
}
}
}
@Override
public boolean removeService(Object object) throws Exception {
if (object instanceof Endpoint) {
removeEndpoint((Endpoint) object);
return true;
}
if (object instanceof Service) {
Service service = (Service) object;
for (LifecycleStrategy strategy : lifecycleStrategies) {
strategy.onServiceRemove(this, service, null);
}
return servicesToStop.remove(service);
}
return false;
}
@Override
public void addBootstrap(BootstrapCloseable bootstrap) {
bootstraps.add(bootstrap);
}
@Override
public List getServices() {
return Collections.unmodifiableList(servicesToStop);
}
@Override
public boolean hasService(Object object) {
if (servicesToStop.isEmpty()) {
return false;
}
if (object instanceof Service) {
Service service = (Service) object;
return servicesToStop.contains(service);
}
return false;
}
@Override
public T hasService(Class type) {
if (servicesToStop.isEmpty()) {
return null;
}
for (Service service : servicesToStop) {
if (type.isInstance(service)) {
return type.cast(service);
}
}
return null;
}
@Override
@SuppressWarnings("unchecked")
public Set hasServices(Class type) {
if (servicesToStop.isEmpty()) {
return Collections.emptySet();
}
Set set = new HashSet<>();
for (Service service : servicesToStop) {
if (type.isInstance(service)) {
set.add((T) service);
}
}
return set;
}
@Override
public void deferStartService(Object object, boolean stopOnShutdown) throws Exception {
deferStartService(object, stopOnShutdown, false);
}
public void deferStartService(Object object, boolean stopOnShutdown, boolean startEarly) throws Exception {
if (object instanceof Service) {
Service service = (Service) object;
// only add to services to close if its a singleton
// otherwise we could for example end up with a lot of prototype
// scope endpoints
boolean singleton = true; // assume singleton by default
if (object instanceof IsSingleton) {
singleton = ((IsSingleton) service).isSingleton();
}
// do not add endpoints as they have their own list
if (singleton && !(service instanceof Endpoint)) {
// only add to list of services to stop if its not already there
if (stopOnShutdown && !hasService(service)) {
servicesToStop.add(service);
}
}
// are we already started?
if (isStarted()) {
ServiceHelper.startService(service);
} else {
deferStartupListener.addService(service, startEarly);
}
}
}
protected List getStartupListeners() {
return startupListeners;
}
@Override
public void addStartupListener(StartupListener listener) throws Exception {
// either add to listener so we can invoke then later when CamelContext
// has been started
// or invoke the callback right now
if (isStarted()) {
listener.onCamelContextStarted(this, true);
} else {
startupListeners.add(listener);
}
}
public String getComponentParameterJsonSchema(String componentName) throws IOException {
// use the component factory finder to find the package name of the
// component class, which is the location
// where the documentation exists as well
FactoryFinder finder = getFactoryFinder(DefaultComponentResolver.RESOURCE_PATH);
Class> clazz = finder.findClass(componentName).orElse(null);
if (clazz == null) {
// fallback and find existing component
Component existing = hasComponent(componentName);
if (existing != null) {
clazz = existing.getClass();
} else {
return null;
}
}
String packageName = clazz.getPackage().getName();
packageName = packageName.replace('.', '/');
String path = packageName + "/" + componentName + ".json";
ClassResolver resolver = getClassResolver();
InputStream inputStream = resolver.loadResourceAsStream(path);
LOG.debug("Loading component JSON Schema for: {} using class resolver: {} -> {}", componentName, resolver, inputStream);
if (inputStream != null) {
try {
return IOHelper.loadText(inputStream);
} finally {
IOHelper.close(inputStream);
}
}
// special for ActiveMQ as it is really just JMS
if ("ActiveMQComponent".equals(clazz.getSimpleName())) {
return getComponentParameterJsonSchema("jms");
} else {
return null;
}
}
public String getDataFormatParameterJsonSchema(String dataFormatName) throws IOException {
// use the dataformat factory finder to find the package name of the
// dataformat class, which is the location
// where the documentation exists as well
FactoryFinder finder = getFactoryFinder(DefaultDataFormatResolver.DATAFORMAT_RESOURCE_PATH);
Class> clazz = finder.findClass(dataFormatName).orElse(null);
if (clazz == null) {
return null;
}
String packageName = clazz.getPackage().getName();
packageName = packageName.replace('.', '/');
String path = packageName + "/" + dataFormatName + ".json";
ClassResolver resolver = getClassResolver();
InputStream inputStream = resolver.loadResourceAsStream(path);
LOG.debug("Loading dataformat JSON Schema for: {} using class resolver: {} -> {}", dataFormatName, resolver,
inputStream);
if (inputStream != null) {
try {
return IOHelper.loadText(inputStream);
} finally {
IOHelper.close(inputStream);
}
}
return null;
}
public String getLanguageParameterJsonSchema(String languageName) throws IOException {
// use the language factory finder to find the package name of the
// language class, which is the location
// where the documentation exists as well
FactoryFinder finder = getFactoryFinder(DefaultLanguageResolver.LANGUAGE_RESOURCE_PATH);
Class> clazz = finder.findClass(languageName).orElse(null);
if (clazz == null) {
return null;
}
String packageName = clazz.getPackage().getName();
packageName = packageName.replace('.', '/');
String path = packageName + "/" + languageName + ".json";
ClassResolver resolver = getClassResolver();
InputStream inputStream = resolver.loadResourceAsStream(path);
LOG.debug("Loading language JSON Schema for: {} using class resolver: {} -> {}", languageName, resolver, inputStream);
if (inputStream != null) {
try {
return IOHelper.loadText(inputStream);
} finally {
IOHelper.close(inputStream);
}
}
return null;
}
// Helper methods
// -----------------------------------------------------------------------
public String getEipParameterJsonSchema(String eipName) throws IOException {
// the eip json schema may be in some of the sub-packages so look until
// we find it
String[] subPackages = new String[] { "", "/config", "/dataformat", "/language", "/loadbalancer", "/rest" };
for (String sub : subPackages) {
String path = CamelContextHelper.MODEL_DOCUMENTATION_PREFIX + sub + "/" + eipName + ".json";
ClassResolver resolver = getClassResolver();
InputStream inputStream = resolver.loadResourceAsStream(path);
if (inputStream != null) {
LOG.debug("Loading eip JSON Schema for: {} using class resolver: {} -> {}", eipName, resolver, inputStream);
try {
return IOHelper.loadText(inputStream);
} finally {
IOHelper.close(inputStream);
}
}
}
return null;
}
@Override
public Language resolveLanguage(String name) {
LOG.debug("Resolving language: {}", name);
return languages.computeIfAbsent(name, new Function() {
@Override
public Language apply(String s) {
StartupStep step = null;
// only record startup step during startup (not started)
if (!isStarted() && startupStepRecorder.isEnabled()) {
step = startupStepRecorder.beginStep(Language.class, name, "Resolve Language");
}
final CamelContext camelContext = getCamelContextReference();
// as first iteration, check if there is a language instance for the given name
// bound to the registry
Language language = ResolverHelper.lookupLanguageInRegistryWithFallback(camelContext, name);
if (language == null) {
// language not known, then use resolver
language = getLanguageResolver().resolveLanguage(name, camelContext);
}
if (language != null) {
if (language instanceof Service) {
try {
Service service = (Service) language;
// init service first
CamelContextAware.trySetCamelContext(service, camelContext);
ServiceHelper.initService(service);
startService(service);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
}
// inject CamelContext if aware
CamelContextAware.trySetCamelContext(language, camelContext);
for (LifecycleStrategy strategy : lifecycleStrategies) {
strategy.onLanguageCreated(name, language);
}
}
if (step != null) {
startupStepRecorder.endStep(step);
}
return language;
}
});
}
// Properties
// -----------------------------------------------------------------------
@Override
public String resolvePropertyPlaceholders(String text) {
return resolvePropertyPlaceholders(text, false);
}
@Override
public String resolvePropertyPlaceholders(String text, boolean keepUnresolvedOptional) {
if (text != null && text.contains(PropertiesComponent.PREFIX_TOKEN)) {
// the parser will throw exception if property key was not found
String answer = getPropertiesComponent().parseUri(text, keepUnresolvedOptional);
LOG.debug("Resolved text: {} -> {}", text, answer);
return answer;
}
// is the value a known field (currently we only support
// constants from Exchange.class)
if (text != null && text.startsWith("Exchange.")) {
String field = StringHelper.after(text, "Exchange.");
String constant = ExchangeConstantProvider.lookup(field);
if (constant != null) {
LOG.debug("Resolved constant: {} -> {}", text, constant);
return constant;
} else {
throw new IllegalArgumentException("Constant field with name: " + field + " not found on Exchange.class");
}
}
// return original text as is
return text;
}
@Override
public TypeConverter getTypeConverter() {
return typeConverter;
}
public void setTypeConverter(TypeConverter typeConverter) {
this.typeConverter = doAddService(typeConverter);
}
protected TypeConverter getOrCreateTypeConverter() {
if (typeConverter == null) {
synchronized (lock) {
if (typeConverter == null) {
setTypeConverter(createTypeConverter());
}
}
}
return typeConverter;
}
@Override
public TypeConverterRegistry getTypeConverterRegistry() {
if (typeConverterRegistry == null) {
synchronized (lock) {
if (typeConverterRegistry == null) {
setTypeConverterRegistry(createTypeConverterRegistry());
}
}
}
return typeConverterRegistry;
}
@Override
public void setTypeConverterRegistry(TypeConverterRegistry typeConverterRegistry) {
this.typeConverterRegistry = doAddService(typeConverterRegistry);
// some registries are also a type converter implementation
if (typeConverterRegistry instanceof TypeConverter) {
this.typeConverter = (TypeConverter) typeConverterRegistry;
}
}
@Override
public Injector getInjector() {
if (injector == null) {
synchronized (lock) {
if (injector == null) {
setInjector(createInjector());
}
}
}
return injector;
}
@Override
public void setInjector(Injector injector) {
this.injector = doAddService(injector);
}
@Override
public PropertiesComponent getPropertiesComponent() {
if (propertiesComponent == null) {
synchronized (lock) {
if (propertiesComponent == null) {
setPropertiesComponent(createPropertiesComponent());
}
}
}
return propertiesComponent;
}
@Override
public void setPropertiesComponent(PropertiesComponent propertiesComponent) {
this.propertiesComponent = doAddService(propertiesComponent);
}
@Override
public CamelBeanPostProcessor getBeanPostProcessor() {
if (beanPostProcessor == null) {
synchronized (lock) {
if (beanPostProcessor == null) {
setBeanPostProcessor(createBeanPostProcessor());
}
}
}
return beanPostProcessor;
}
@Override
public void setBeanPostProcessor(CamelBeanPostProcessor beanPostProcessor) {
this.beanPostProcessor = doAddService(beanPostProcessor);
}
@Override
public CamelDependencyInjectionAnnotationFactory getDependencyInjectionAnnotationFactory() {
if (dependencyInjectionAnnotationFactory == null) {
synchronized (lock) {
if (dependencyInjectionAnnotationFactory == null) {
setDependencyInjectionAnnotationFactory(createDependencyInjectionAnnotationFactory());
}
}
}
return dependencyInjectionAnnotationFactory;
}
@Override
public void setDependencyInjectionAnnotationFactory(
CamelDependencyInjectionAnnotationFactory dependencyInjectionAnnotationFactory) {
this.dependencyInjectionAnnotationFactory = dependencyInjectionAnnotationFactory;
}
@Override
public ManagementMBeanAssembler getManagementMBeanAssembler() {
return managementMBeanAssembler;
}
public void setManagementMBeanAssembler(ManagementMBeanAssembler managementMBeanAssembler) {
this.managementMBeanAssembler = doAddService(managementMBeanAssembler, false);
}
public ComponentResolver getComponentResolver() {
if (componentResolver == null) {
synchronized (lock) {
if (componentResolver == null) {
setComponentResolver(createComponentResolver());
}
}
}
return componentResolver;
}
public void setComponentResolver(ComponentResolver componentResolver) {
this.componentResolver = doAddService(componentResolver);
}
public ComponentNameResolver getComponentNameResolver() {
if (componentNameResolver == null) {
synchronized (lock) {
if (componentNameResolver == null) {
setComponentNameResolver(createComponentNameResolver());
}
}
}
return componentNameResolver;
}
public void setComponentNameResolver(ComponentNameResolver componentNameResolver) {
this.componentNameResolver = doAddService(componentNameResolver);
}
public LanguageResolver getLanguageResolver() {
if (languageResolver == null) {
synchronized (lock) {
if (languageResolver == null) {
setLanguageResolver(createLanguageResolver());
}
}
}
return languageResolver;
}
public void setLanguageResolver(LanguageResolver languageResolver) {
this.languageResolver = doAddService(languageResolver);
}
public ConfigurerResolver getConfigurerResolver() {
if (configurerResolver == null) {
synchronized (lock) {
if (configurerResolver == null) {
setConfigurerResolver(createConfigurerResolver());
}
}
}
return configurerResolver;
}
public void setConfigurerResolver(ConfigurerResolver configurerResolver) {
this.configurerResolver = doAddService(configurerResolver);
}
public UriFactoryResolver getUriFactoryResolver() {
if (uriFactoryResolver == null) {
synchronized (lock) {
if (uriFactoryResolver == null) {
setUriFactoryResolver(createUriFactoryResolver());
}
}
}
return uriFactoryResolver;
}
public void setUriFactoryResolver(UriFactoryResolver uriFactoryResolver) {
this.uriFactoryResolver = doAddService(uriFactoryResolver);
}
public boolean isAutoCreateComponents() {
return autoCreateComponents;
}
public void setAutoCreateComponents(boolean autoCreateComponents) {
this.autoCreateComponents = autoCreateComponents;
}
@Override
public Registry getRegistry() {
if (registry == null) {
synchronized (lock) {
if (registry == null) {
setRegistry(createRegistry());
}
}
}
return registry;
}
@Override
public void setRegistry(Registry registry) {
CamelContextAware.trySetCamelContext(registry, getCamelContextReference());
this.registry = registry;
}
@Override
public T getRegistry(Class type) {
Registry reg = getRegistry();
if (type.isAssignableFrom(reg.getClass())) {
return type.cast(reg);
}
return null;
}
@Override
public List getLifecycleStrategies() {
return lifecycleStrategies;
}
@Override
public void addLifecycleStrategy(LifecycleStrategy lifecycleStrategy) {
// avoid adding double which can happen with spring xml on spring boot
if (!getLifecycleStrategies().contains(lifecycleStrategy)) {
getLifecycleStrategies().add(lifecycleStrategy);
}
}
@Override
public void setupRoutes(boolean done) {
if (done) {
isSetupRoutes.remove();
} else {
isSetupRoutes.set(true);
}
}
@Override
public RestConfiguration getRestConfiguration() {
if (restConfiguration == null) {
synchronized (lock) {
if (restConfiguration == null) {
setRestConfiguration(createRestConfiguration());
}
}
}
return restConfiguration;
}
@Override
public void setRestConfiguration(RestConfiguration restConfiguration) {
this.restConfiguration = restConfiguration;
}
@Override
public VaultConfiguration getVaultConfiguration() {
return vaultConfiguration;
}
@Override
public void setVaultConfiguration(VaultConfiguration vaultConfiguration) {
this.vaultConfiguration = vaultConfiguration;
}
@Override
public List getInterceptStrategies() {
return interceptStrategies;
}
public void setInterceptStrategies(List interceptStrategies) {
this.interceptStrategies = interceptStrategies;
}
@Override
public void addInterceptStrategy(InterceptStrategy interceptStrategy) {
// avoid adding double which can happen with spring xml on spring boot
if (!getInterceptStrategies().contains(interceptStrategy)) {
getInterceptStrategies().add(interceptStrategy);
}
}
@Override
public List getRoutePolicyFactories() {
return routePolicyFactories;
}
public void setRoutePolicyFactories(List routePolicyFactories) {
this.routePolicyFactories = routePolicyFactories;
}
@Override
public void addRoutePolicyFactory(RoutePolicyFactory routePolicyFactory) {
// avoid adding double which can happen with spring xml on spring boot
if (!getRoutePolicyFactories().contains(routePolicyFactory)) {
getRoutePolicyFactories().add(routePolicyFactory);
}
}
@Override
public Set getLogListeners() {
return logListeners;
}
@Override
public void addLogListener(LogListener listener) {
if (logListeners == null) {
logListeners = new LinkedHashSet<>();
}
// avoid adding double which can happen with spring xml on spring boot
logListeners.add(listener);
}
@Override
public void setStreamCaching(Boolean cache) {
this.streamCache = cache;
}
@Override
public Boolean isStreamCaching() {
return streamCache;
}
@Override
public void setTracing(Boolean tracing) {
this.trace = tracing;
}
@Override
public Boolean isTracing() {
return trace;
}
@Override
public String getTracingPattern() {
return tracePattern;
}
@Override
public void setTracingPattern(String tracePattern) {
this.tracePattern = tracePattern;
}
@Override
public String getTracingLoggingFormat() {
return tracingLoggingFormat;
}
@Override
public void setTracingLoggingFormat(String format) {
this.tracingLoggingFormat = format;
}
@Override
public Boolean isBacklogTracing() {
return backlogTrace;
}
@Override
public void setBacklogTracing(Boolean backlogTrace) {
this.backlogTrace = backlogTrace;
}
public Boolean getBacklogTraceStandby() {
return backlogTraceStandby;
}
public void setBacklogTraceStandby(Boolean backlogTraceStandby) {
this.backlogTraceStandby = backlogTraceStandby;
}
@Override
public void setDebugging(Boolean debug) {
this.debug = debug;
}
@Override
public Boolean isDebugging() {
return debug;
}
@Override
public void setMessageHistory(Boolean messageHistory) {
this.messageHistory = messageHistory;
}
@Override
public Boolean isMessageHistory() {
return messageHistory;
}
@Override
public void setLogMask(Boolean logMask) {
this.logMask = logMask;
}
@Override
public Boolean isLogMask() {
return logMask != null && logMask;
}
@Override
public Boolean isLogExhaustedMessageBody() {
return logExhaustedMessageBody;
}
@Override
public void setLogExhaustedMessageBody(Boolean logExhaustedMessageBody) {
this.logExhaustedMessageBody = logExhaustedMessageBody;
}
@Override
public Long getDelayer() {
return delay;
}
@Override
public void setDelayer(Long delay) {
this.delay = delay;
}
@Override
public ProducerTemplate createProducerTemplate() {
return createProducerTemplate(0);
}
@Override
public ProducerTemplate createProducerTemplate(int maximumCacheSize) {
DefaultProducerTemplate answer = new DefaultProducerTemplate(getCamelContextReference());
answer.setMaximumCacheSize(maximumCacheSize);
// start it so its ready to use
try {
startService(answer);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
return answer;
}
@Override
public FluentProducerTemplate createFluentProducerTemplate() {
return createFluentProducerTemplate(0);
}
@Override
public FluentProducerTemplate createFluentProducerTemplate(int maximumCacheSize) {
DefaultFluentProducerTemplate answer = new DefaultFluentProducerTemplate(getCamelContextReference());
answer.setMaximumCacheSize(maximumCacheSize);
// start it so its ready to use
try {
startService(answer);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
return answer;
}
@Override
public ConsumerTemplate createConsumerTemplate() {
return createConsumerTemplate(0);
}
@Override
public ConsumerTemplate createConsumerTemplate(int maximumCacheSize) {
DefaultConsumerTemplate answer = new DefaultConsumerTemplate(getCamelContextReference());
answer.setMaximumCacheSize(maximumCacheSize);
// start it so its ready to use
try {
startService(answer);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeCamelException(e);
}
return answer;
}
@Override
public ErrorHandlerFactory getErrorHandlerFactory() {
return errorHandlerFactory;
}
@Override
public void setErrorHandlerFactory(ErrorHandlerFactory errorHandlerFactory) {
this.errorHandlerFactory = errorHandlerFactory;
}
@Override
public ScheduledExecutorService getErrorHandlerExecutorService() {
if (errorHandlerExecutorService == null) {
synchronized (lock) {
if (errorHandlerExecutorService == null) {
// setup default thread pool for error handler
errorHandlerExecutorService = createErrorHandlerExecutorService();
}
}
}
return errorHandlerExecutorService;
}
public void setErrorHandlerExecutorService(ScheduledExecutorService errorHandlerExecutorService) {
this.errorHandlerExecutorService = errorHandlerExecutorService;
}
protected ScheduledExecutorService createErrorHandlerExecutorService() {
return getExecutorServiceManager().newDefaultScheduledThreadPool("ErrorHandlerRedeliveryThreadPool",
"ErrorHandlerRedeliveryTask");
}
@Override
public UnitOfWorkFactory getUnitOfWorkFactory() {
if (unitOfWorkFactory == null) {
synchronized (lock) {
if (unitOfWorkFactory == null) {
setUnitOfWorkFactory(createUnitOfWorkFactory());
}
}
}
return unitOfWorkFactory;
}
@Override
public void setUnitOfWorkFactory(UnitOfWorkFactory unitOfWorkFactory) {
this.unitOfWorkFactory = doAddService(unitOfWorkFactory);
}
@Override
public RuntimeEndpointRegistry getRuntimeEndpointRegistry() {
return runtimeEndpointRegistry;
}
@Override
public void setRuntimeEndpointRegistry(RuntimeEndpointRegistry runtimeEndpointRegistry) {
this.runtimeEndpointRegistry = doAddService(runtimeEndpointRegistry);
}
@Override
public String getUptime() {
long delta = getUptimeMillis();
if (delta == 0) {
return "";
}
return TimeUtils.printDuration(delta);
}
@Override
public long getUptimeMillis() {
if (startDate == 0) {
return 0;
}
return System.currentTimeMillis() - startDate;
}
@Override
public Date getStartDate() {
if (startDate == 0) {
return null;
}
return new Date(startDate);
}
@Override
public boolean isEventNotificationApplicable() {
return eventNotificationApplicable;
}
@Override
public void setEventNotificationApplicable(boolean eventNotificationApplicable) {
this.eventNotificationApplicable = eventNotificationApplicable;
}
@Override
public String getVersion() {
if (version == null) {
synchronized (lock) {
if (version == null) {
version = doGetVersion();
}
}
}
return version;
}
private String doGetVersion() {
String resolvedVersion = null;
InputStream is = null;
// try to load from maven properties first
try {
Properties p = new Properties();
is = AbstractCamelContext.class
.getResourceAsStream("/META-INF/maven/org.apache.camel/camel-base-engine/pom.properties");
if (is != null) {
p.load(is);
resolvedVersion = p.getProperty("version", "");
}
} catch (Exception e) {
// ignore
} finally {
if (is != null) {
IOHelper.close(is);
}
}
// fallback to using Java API
if (resolvedVersion == null) {
Package aPackage = getClass().getPackage();
if (aPackage != null) {
resolvedVersion = aPackage.getImplementationVersion();
if (resolvedVersion == null) {
resolvedVersion = aPackage.getSpecificationVersion();
}
}
}
if (resolvedVersion == null) {
// we could not compute the version so use a blank
resolvedVersion = "";
}
return resolvedVersion;
}
@Override
protected void doSuspend() throws Exception {
EventHelper.notifyCamelContextSuspending(this);
LOG.info("Apache Camel {} ({}) is suspending", getVersion(), getName());
StopWatch watch = new StopWatch();
// update list of started routes to be suspended
// because we only want to suspend started routes
// (so when we resume we only resume the routes which actually was
// suspended)
for (Map.Entry entry : getRouteServices().entrySet()) {
if (entry.getValue().getStatus().isStarted()) {
suspendedRouteServices.put(entry.getKey(), entry.getValue());
}
}
// assemble list of startup ordering so routes can be shutdown
// accordingly
List orders = new ArrayList<>();
for (Map.Entry entry : suspendedRouteServices.entrySet()) {
Route route = entry.getValue().getRoute();
Integer order = route.getStartupOrder();
if (order == null) {
order = defaultRouteStartupOrder++;
}
orders.add(new DefaultRouteStartupOrder(order, route, entry.getValue()));
}
// suspend routes using the shutdown strategy so it can shutdown in
// correct order
// routes which doesn't support suspension will be stopped instead
getShutdownStrategy().suspend(this, orders);
// mark the route services as suspended or stopped
for (RouteService service : suspendedRouteServices.values()) {
if (routeSupportsSuspension(service.getId())) {
service.suspend();
} else {
service.stop();
}
}
watch.taken();
if (LOG.isInfoEnabled()) {
LOG.info("Apache Camel {} ({}) is suspended in {}", getVersion(), getName(),
TimeUtils.printDuration(watch.taken(), true));
}
EventHelper.notifyCamelContextSuspended(this);
}
// Implementation methods
// -----------------------------------------------------------------------
@Override
protected void doResume() throws Exception {
try {
EventHelper.notifyCamelContextResuming(this);
LOG.info("Apache Camel {} ({}) is resuming", getVersion(), getName());
StopWatch watch = new StopWatch();
// start the suspended routes (do not check for route clashes, and
// indicate)
internalRouteStartupManager.doStartOrResumeRoutes(suspendedRouteServices, false, true, true, false);
// mark the route services as resumed (will be marked as started) as
// well
for (RouteService service : suspendedRouteServices.values()) {
if (routeSupportsSuspension(service.getId())) {
service.resume();
} else {
service.start();
}
}
if (LOG.isInfoEnabled()) {
LOG.info("Resumed {} routes", suspendedRouteServices.size());
LOG.info("Apache Camel {} ({}) resumed in {}", getVersion(), getName(),
TimeUtils.printDuration(watch.taken(), true));
}
// and clear the list as they have been resumed
suspendedRouteServices.clear();
EventHelper.notifyCamelContextResumed(this);
} catch (Exception e) {
EventHelper.notifyCamelContextResumeFailed(this, e);
throw e;
}
}
@Override
protected AutoCloseable doLifecycleChange() {
return new LifecycleHelper();
}
@Override
public void init() {
try {
super.init();
} catch (RuntimeCamelException e) {
if (e.getCause() != null && e.getCause() instanceof VetoCamelContextStartException) {
vetoed = (VetoCamelContextStartException) e.getCause();
} else {
throw e;
}
}
// was the initialization vetoed?
if (vetoed != null) {
LOG.info("CamelContext ({}) vetoed to not initialize due to: {}", getName(), vetoed.getMessage());
failOnStartup(vetoed);
return;
}
}
@Override
public void start() {
super.start();
//
// We need to perform the following actions after the {@link #start()} method
// is called, so that the state of the {@link CamelContext} is Started.
//
// did the start veto?
if (vetoed != null) {
LOG.info("CamelContext ({}) vetoed to not start due to: {}", getName(), vetoed.getMessage());
failOnStartup(vetoed);
stop();
return;
}
for (LifecycleStrategy strategy : lifecycleStrategies) {
try {
strategy.onContextStarted(this);
} catch (Throwable e) {
LOG.warn("Lifecycle strategy {} failed on CamelContext ({}) due to: {}. This exception will be ignored",
strategy,
getName(),
e.getMessage());
}
}
// okay the routes has been started so emit event that CamelContext
// has started (here at the end)
EventHelper.notifyCamelContextStarted(this);
// now call the startup listeners where the routes has been started
for (StartupListener startup : startupListeners) {
try {
startup.onCamelContextFullyStarted(this, isStarted());
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeException(e);
}
}
}
@Override
public void stop() {
for (LifecycleStrategy strategy : lifecycleStrategies) {
try {
strategy.onContextStopping(this);
strategy.onContextStop(this);
} catch (Throwable e) {
LOG.warn("Lifecycle strategy {} failed on CamelContext ({}) due to: {}. This exception will be ignored",
strategy,
getName(),
e.getMessage());
}
}
super.stop();
}
@Override
public void doBuild() throws Exception {
StopWatch watch = new StopWatch();
// auto-detect step recorder from classpath if none has been explicit configured
if (startupStepRecorder.getClass().getSimpleName().equals("DefaultStartupStepRecorder")) {
StartupStepRecorder fr = getBootstrapFactoryFinder()
.newInstance(StartupStepRecorder.FACTORY, StartupStepRecorder.class).orElse(null);
if (fr != null) {
LOG.debug("Discovered startup recorder: {} from classpath", fr);
startupStepRecorder = fr;
}
}
startupStepRecorder.start();
StartupStep step = startupStepRecorder.beginStep(CamelContext.class, null, "Build CamelContext");
// Initialize LRUCacheFactory as eager as possible,
// to let it warm up concurrently while Camel is startup up
if (initialization != Initialization.Lazy) {
StartupStep subStep = startupStepRecorder.beginStep(CamelContext.class, null, "Setup LRUCacheFactory");
LRUCacheFactory.init();
startupStepRecorder.endStep(subStep);
}
// Setup management first since end users may use it to add event
// notifiers using the management strategy before the CamelContext has been started
StartupStep step3 = startupStepRecorder.beginStep(CamelContext.class, null, "Setup Management");
setupManagement(null);
startupStepRecorder.endStep(step3);
// setup health-check registry as its needed this early phase for 3rd party to register custom repositories
HealthCheckRegistry hcr = getExtension(HealthCheckRegistry.class);
if (hcr == null) {
StartupStep step4 = startupStepRecorder.beginStep(CamelContext.class, null, "Setup HealthCheckRegistry");
hcr = createHealthCheckRegistry();
if (hcr != null) {
// install health-check registry if it was discovered from classpath (camel-health)
hcr.setCamelContext(this);
setExtension(HealthCheckRegistry.class, hcr);
}
startupStepRecorder.endStep(step4);
}
// setup dev-console registry as its needed this early phase for 3rd party to register custom consoles
DevConsoleRegistry dcr = getExtension(DevConsoleRegistry.class);
if (dcr == null) {
StartupStep step5 = startupStepRecorder.beginStep(CamelContext.class, null, "Setup DevConsoleRegistry");
dcr = createDevConsoleRegistry();
if (dcr != null) {
// install dev-console registry if it was discovered from classpath (camel-console)
dcr.setCamelContext(this);
setExtension(DevConsoleRegistry.class, dcr);
}
startupStepRecorder.endStep(step5);
}
// Call all registered trackers with this context
// Note, this may use a partially constructed object
CamelContextTracker.notifyContextCreated(this);
// Setup type converter eager as its highly in use and should not be lazy initialized
if (eagerCreateTypeConverter()) {
StartupStep step5 = startupStepRecorder.beginStep(CamelContext.class, null, "Setting up TypeConverter");
getOrCreateTypeConverter();
startupStepRecorder.endStep(step5);
}
startupStepRecorder.endStep(step);
buildTaken = watch.taken();
LOG.debug("Apache Camel {} ({}) built in {}", getVersion(), getName(), TimeUtils.printDuration(buildTaken, true));
}
protected void resetBuildTime() {
// needed by camel-quarkus
buildTaken = 0;
}
@Override
public void doInit() throws Exception {
StopWatch watch = new StopWatch();
vetoed = null;
StartupStep step = startupStepRecorder.beginStep(CamelContext.class, null, "Init CamelContext");
// init the route controller
this.routeController = getRouteController();
if (startupSummaryLevel == StartupSummaryLevel.Verbose) {
// verbose startup should let route controller do the route startup logging
if (routeController.getLoggingLevel().ordinal() < LoggingLevel.INFO.ordinal()) {
routeController.setLoggingLevel(LoggingLevel.INFO);
}
}
// init the shutdown strategy
this.shutdownStrategy = getShutdownStrategy();
if (startupSummaryLevel == StartupSummaryLevel.Verbose) {
// verbose startup should let route controller do the route shutdown logging
if (shutdownStrategy != null && shutdownStrategy.getLoggingLevel().ordinal() < LoggingLevel.INFO.ordinal()) {
shutdownStrategy.setLoggingLevel(LoggingLevel.INFO);
}
}
// optimize - before starting routes lets check if event notifications is possible
eventNotificationApplicable = EventHelper.eventsApplicable(this);
// ensure additional type converters is loaded (either if enabled or we should use package scanning from the base)
boolean load = loadTypeConverters || getBasePackageScan() != null;
if (load && typeConverter instanceof AnnotationScanTypeConverters) {
StartupStep step2 = startupStepRecorder.beginStep(CamelContext.class, null, "Scan TypeConverters");
((AnnotationScanTypeConverters) typeConverter).scanTypeConverters();
startupStepRecorder.endStep(step2);
}
// ensure additional health checks is loaded
if (loadHealthChecks) {
StartupStep step3 = startupStepRecorder.beginStep(CamelContext.class, null, "Scan HealthChecks");
HealthCheckRegistry hcr = getExtension(HealthCheckRegistry.class);
if (hcr != null) {
hcr.loadHealthChecks();
}
startupStepRecorder.endStep(step3);
}
// ensure additional dev consoles is loaded
if (devConsole) {
StartupStep step4 = startupStepRecorder.beginStep(CamelContext.class, null, "Scan DevConsoles (phase 1)");
DevConsoleRegistry dcr = getExtension(DevConsoleRegistry.class);
if (dcr != null) {
dcr.loadDevConsoles();
}
startupStepRecorder.endStep(step4);
}
// custom properties may use property placeholders so resolve those
// early on
if (globalOptions != null && !globalOptions.isEmpty()) {
for (Map.Entry entry : globalOptions.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (value != null) {
String replaced = resolvePropertyPlaceholders(value);
if (!value.equals(replaced)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Camel property with key {} replaced value from {} -> {}", key, value, replaced);
}
entry.setValue(replaced);
}
}
}
}
forceLazyInitialization();
// setup cli-connector if not already done
if (hasService(CliConnector.class) == null) {
CliConnectorFactory ccf = getCliConnectorFactory();
if (ccf != null && ccf.isEnabled()) {
CliConnector connector = ccf.createConnector();
addService(connector, true);
// force start cli connector early as otherwise it will be deferred until context is started
// but, we want status available during startup phase
ServiceHelper.startService(connector);
}
}
addService(getManagementStrategy(), false);
lifecycleStrategies.sort(OrderedComparator.get());
ServiceHelper.initService(lifecycleStrategies);
for (LifecycleStrategy strategy : lifecycleStrategies) {
try {
strategy.onContextInitializing(this);
} catch (VetoCamelContextStartException e) {
// okay we should not start Camel since it was vetoed
LOG.warn("Lifecycle strategy {} vetoed initializing CamelContext ({}) due to: {}", strategy, getName(),
e.getMessage());
throw e;
} catch (Exception e) {
LOG.warn("Lifecycle strategy {} failed initializing CamelContext ({}) due to: {}", strategy, getName(),
e.getMessage());
throw e;
}
}
// optimize - before starting routes lets check if event notifications is possible
eventNotificationApplicable = EventHelper.eventsApplicable(this);
// start notifiers as services
for (EventNotifier notifier : getManagementStrategy().getEventNotifiers()) {
if (notifier instanceof Service) {
Service service = (Service) notifier;
for (LifecycleStrategy strategy : lifecycleStrategies) {
strategy.onServiceAdd(getCamelContextReference(), service, null);
}
}
ServiceHelper.initService(notifier);
}
// the event notifiers must be initialized before we can emit this event
EventHelper.notifyCamelContextInitializing(this);
// re-create endpoint registry as the cache size limit may be set after the constructor of this instance was called.
// and we needed to create endpoints up-front as it may be accessed before this context is started
endpoints = doAddService(createEndpointRegistry(endpoints));
// optimised to not include runtimeEndpointRegistry unless startServices
// is enabled or JMX statistics is in extended mode
if (runtimeEndpointRegistry == null && getManagementStrategy() != null
&& getManagementStrategy().getManagementAgent() != null) {
Boolean isEnabled = getManagementStrategy().getManagementAgent().getEndpointRuntimeStatisticsEnabled();
boolean isExtended = getManagementStrategy().getManagementAgent().getStatisticsLevel().isExtended();
// extended mode is either if we use Extended statistics level or
// the option is explicit enabled
boolean extended = isExtended || isEnabled != null && isEnabled;
if (extended) {
runtimeEndpointRegistry = new DefaultRuntimeEndpointRegistry();
}
}
if (runtimeEndpointRegistry != null) {
if (runtimeEndpointRegistry instanceof EventNotifier && getManagementStrategy() != null) {
getManagementStrategy().addEventNotifier((EventNotifier) runtimeEndpointRegistry);
}
addService(runtimeEndpointRegistry, true, true);
}
bindDataFormats();
// init components
ServiceHelper.initService(components.values());
// create route definitions from route templates if we have any sources
for (RouteTemplateParameterSource source : getRegistry().findByType(RouteTemplateParameterSource.class)) {
for (String routeId : source.routeIds()) {
// do a defensive copy of the parameters
Map map = new HashMap<>(source.parameters(routeId));
Object templateId = map.remove(RouteTemplateParameterSource.TEMPLATE_ID);
if (templateId == null) {
// use alternative style as well
templateId = map.remove("template-id");
}
final String id = templateId != null ? templateId.toString() : null;
if (id == null) {
throw new IllegalArgumentException(
"RouteTemplateParameterSource with routeId: " + routeId + " has no templateId defined");
}
addRouteFromTemplate(routeId, id, map);
}
}
// init the route definitions before the routes is started
StartupStep subStep = startupStepRecorder.beginStep(CamelContext.class, getName(), "Init Routes");
// the method is called start but at this point it will only initialize (as context is starting up)
startRouteDefinitions();
// this will init route definitions and populate as route services which we can then initialize now
internalRouteStartupManager.doInitRoutes(routeServices);
startupStepRecorder.endStep(subStep);
if (!lifecycleStrategies.isEmpty()) {
subStep = startupStepRecorder.beginStep(CamelContext.class, getName(), "LifecycleStrategy onContextInitialized");
for (LifecycleStrategy strategy : lifecycleStrategies) {
try {
strategy.onContextInitialized(this);
} catch (VetoCamelContextStartException e) {
// okay we should not start Camel since it was vetoed
LOG.warn("Lifecycle strategy {} vetoed initializing CamelContext ({}) due to: {}", strategy, getName(),
e.getMessage());
throw e;
} catch (Exception e) {
LOG.warn("Lifecycle strategy {} failed initializing CamelContext ({}) due to: {}", strategy, getName(),
e.getMessage());
throw e;
}
}
startupStepRecorder.endStep(subStep);
}
EventHelper.notifyCamelContextInitialized(this);
startupStepRecorder.endStep(step);
initTaken = watch.taken();
LOG.debug("Apache Camel {} ({}) initialized in {}", getVersion(), getName(), TimeUtils.printDuration(initTaken, true));
}
@Override
protected void doStart() throws Exception {
if (firstStartDone) {
// its not good practice resetting a camel context
LOG.warn("Starting CamelContext: {} after the context has been stopped is not recommended", getName());
}
StartupStep step = startupStepRecorder.beginStep(CamelContext.class, getName(), "Start CamelContext");
try {
doStartContext();
} catch (Exception e) {
// fire event that we failed to start
EventHelper.notifyCamelContextStartupFailed(AbstractCamelContext.this, e);
// rethrow cause
throw e;
}
startupStepRecorder.endStep(step);
// if we should only record the startup process then stop it right after started
if (startupStepRecorder.getStartupRecorderDuration() < 0) {
startupStepRecorder.stop();
}
}
protected void doStartContext() throws Exception {
LOG.info("Apache Camel {} ({}) is starting", getVersion(), getName());
vetoed = null;
startDate = System.currentTimeMillis();
stopWatch.restart();
// Start the route controller
startService(this.routeController);
doNotStartRoutesOnFirstStart = !firstStartDone && !isAutoStartup();
// if the context was configured with auto startup = false, and we
// are already started,
// then we may need to start the routes on the 2nd start call
if (firstStartDone && !isAutoStartup() && isStarted()) {
// invoke this logic to warm up the routes and if possible also
// start the routes
try {
internalRouteStartupManager.doStartOrResumeRoutes(routeServices, true, true, false, true);
} catch (Exception e) {
throw RuntimeCamelException.wrapRuntimeException(e);
}
}
// super will invoke doStart which will prepare internal services
// and start routes etc.
try {
firstStartDone = true;
doStartCamel();
} catch (Exception e) {
VetoCamelContextStartException veto = ObjectHelper.getException(VetoCamelContextStartException.class, e);
if (veto != null) {
// mark we veto against starting Camel
vetoed = veto;
return;
} else {
LOG.error("Error starting CamelContext (" + getName() + ") due to exception thrown: " + e.getMessage(), e);
throw RuntimeCamelException.wrapRuntimeException(e);
}
}
// duplicate components in use?
logDuplicateComponents();
// log startup summary
logStartSummary();
// now Camel has been started/bootstrap is complete, then run cleanup to help free up memory etc
for (BootstrapCloseable bootstrap : bootstraps) {
try {
bootstrap.close();
} catch (Exception e) {
LOG.warn("Error during closing bootstrap. This exception is ignored.", e);
}
}
bootstraps.clear();
if (adapt(ExtendedCamelContext.class).getExchangeFactory().isPooled()) {
LOG.info(
"Pooled mode enabled. Camel pools and reuses objects to reduce JVM object allocations. The pool capacity is: {} elements.",
adapt(ExtendedCamelContext.class).getExchangeFactory().getCapacity());
}
if (isLightweight()) {
LOG.info("Lightweight mode enabled. Performing optimizations and memory reduction.");
ReifierStrategy.clearReifiers();
adapt(ExtendedCamelContext.class).disposeModel();
}
}
protected void logDuplicateComponents() {
// output how many instances of the same component class are in use, as multiple instances is potential a mistake
if (LOG.isInfoEnabled()) {
Map, Set> counters = new LinkedHashMap<>();
// use TreeSet to sort the names
Set cnames = new TreeSet<>(getComponentNames());
for (String sourceName : cnames) {
Class> source = getComponent(sourceName).getClass();
if (!counters.containsKey(source)) {
for (String targetName : cnames) {
Class> target = getComponent(targetName).getClass();
if (source == target) {
Set names = counters.computeIfAbsent(source, k -> new TreeSet<>());
names.add(targetName);
}
}
}
}
for (Map.Entry, Set> entry : counters.entrySet()) {
int count = entry.getValue().size();
if (count > 1) {
String fqn = entry.getKey().getName();
String names = String.join(", ", entry.getValue());
LOG.info("Using {} instances of same component class: {} with names: {}", count,
fqn, names);
}
}
}
}
protected void logStartSummary() {
// supervising route controller should do their own startup log summary
boolean supervised = getRouteController().isSupervising();
if (!supervised && startupSummaryLevel != StartupSummaryLevel.Oneline && startupSummaryLevel != StartupSummaryLevel.Off
&& LOG.isInfoEnabled()) {
int started = 0;
int total = 0;
int disabled = 0;
List lines = new ArrayList<>();
List configs = new ArrayList<>();
routeStartupOrder.sort(Comparator.comparingInt(RouteStartupOrder::getStartupOrder));
for (RouteStartupOrder order : routeStartupOrder) {
total++;
String id = order.getRoute().getRouteId();
String status = getRouteStatus(id).name();
if (ServiceStatus.Started.name().equals(status)) {
started++;
}
// use basic endpoint uri to not log verbose details or potential sensitive data
String uri = order.getRoute().getEndpoint().getEndpointBaseUri();
uri = URISupport.sanitizeUri(uri);
String loc = order.getRoute().getSourceLocationShort();
if (startupSummaryLevel == StartupSummaryLevel.Verbose && loc != null) {
lines.add(String.format(" %s %s (%s) (source: %s)", status, id, uri, loc));
} else {
lines.add(String.format(" %s %s (%s)", status, id, uri));
}
String cid = order.getRoute().getConfigurationId();
if (cid != null) {
configs.add(String.format(" %s (%s)", id, cid));
}
}
for (Route route : routes) {
if (!route.isAutoStartup()) {
total++;
disabled++;
String id = route.getRouteId();
String status = getRouteStatus(id).name();
if (ServiceStatus.Stopped.name().equals(status)) {
status = "Disabled";
}
// use basic endpoint uri to not log verbose details or potential sensitive data
String uri = route.getEndpoint().getEndpointBaseUri();
uri = URISupport.sanitizeUri(uri);
String loc = route.getSourceLocationShort();
if (startupSummaryLevel == StartupSummaryLevel.Verbose && loc != null) {
lines.add(String.format(" %s %s (%s) (source: %s)", status, id, uri, loc));
} else {
lines.add(String.format(" %s %s (%s)", status, id, uri));
}
String cid = route.getConfigurationId();
if (cid != null) {
configs.add(String.format(" %s (%s)", id, cid));
}
}
}
if (disabled > 0) {
LOG.info("Routes startup (total:{} started:{} disabled:{})", total, started, disabled);
} else if (total != started) {
LOG.info("Routes startup (total:{} started:{})", total, started);
} else {
LOG.info("Routes startup (started:{})", started);
}
// if we are default/verbose then log each route line
if (startupSummaryLevel == StartupSummaryLevel.Default || startupSummaryLevel == StartupSummaryLevel.Verbose) {
for (String line : lines) {
LOG.info(line);
}
if (startupSummaryLevel == StartupSummaryLevel.Verbose) {
LOG.info("Routes configuration:");
for (String line : configs) {
LOG.info(line);
}
}
}
}
if (startupSummaryLevel != StartupSummaryLevel.Off && LOG.isInfoEnabled()) {
long taken = stopWatch.taken();
long max = buildTaken + initTaken + taken;
String total = TimeUtils.printDuration(max, true);
String start = TimeUtils.printDuration(taken, true);
String init = TimeUtils.printDuration(initTaken, true);
String built = TimeUtils.printDuration(buildTaken, true);
String jvm = logJvmUptime ? getJvmUptime() : null;
if (jvm != null) {
LOG.info("Apache Camel {} ({}) started in {} (build:{} init:{} start:{} JVM-uptime:{})", getVersion(),
getName(), total, built,
init, start, jvm);
} else {
LOG.info("Apache Camel {} ({}) started in {} (build:{} init:{} start:{})", getVersion(), getName(), total,
built,
init,
start);
}
}
}
protected void doStartCamel() throws Exception {
if (!adapt(ExtendedCamelContext.class).getBeanPostProcessor().isEnabled()) {
LOG.info("BeanPostProcessor is disabled. Dependency injection of Camel annotations in beans is not supported.");
}
if (LOG.isDebugEnabled()) {
LOG.debug(
"Using ClassResolver={}, PackageScanClassResolver={}, ApplicationContextClassLoader={}, RouteController={}",
getClassResolver(),
getPackageScanClassResolver(), getApplicationContextClassLoader(), getRouteController());
}
if (isStreamCaching()) {
// stream caching is default enabled so lets report if it has been disabled
LOG.debug("StreamCaching is disabled on CamelContext: {}", getName());
}
if (isBacklogTracing()) {
// tracing is added in the DefaultChannel so we can enable it on the fly
LOG.debug("Backlog Tracing is enabled on CamelContext: {}", getName());
}
if (isTracing()) {
// tracing is added in the DefaultChannel so we can enable it on the fly
LOG.info("Tracing is enabled on CamelContext: {}", getName());
}
if (isUseMDCLogging()) {
// log if MDC has been enabled
String pattern = getMDCLoggingKeysPattern();
if (pattern != null) {
LOG.info("MDC logging (keys-pattern: {}) is enabled on CamelContext: {}", pattern, getName());
} else {
LOG.info("MDC logging is enabled on CamelContext: {}", getName());
}
}
if (getDelayer() != null && getDelayer() > 0) {
LOG.info("Delayer is enabled with: {} ms. on CamelContext: {}", getDelayer(), getName());
}
// start management strategy before lifecycles are started
startService(getManagementStrategy());
// start lifecycle strategies
if (!lifecycleStrategies.isEmpty()) {
StartupStep subStep
= startupStepRecorder.beginStep(CamelContext.class, getName(), "LifecycleStrategy onContextStarting");
startServices(lifecycleStrategies);
for (LifecycleStrategy strategy : lifecycleStrategies) {
try {
strategy.onContextStarting(this);
strategy.onContextStart(this);
} catch (VetoCamelContextStartException e) {
// okay we should not start Camel since it was vetoed
LOG.warn("Lifecycle strategy {} vetoed starting CamelContext ({}) due to: {}", strategy, getName(),
e.getMessage());
throw e;
} catch (Exception e) {
LOG.warn("Lifecycle strategy {} failed starting CamelContext ({}) due to: {}", strategy, getName(),
e.getMessage());
throw e;
}
}
startupStepRecorder.endStep(subStep);
}
// ensure components are started
for (Map.Entry entry : components.entrySet()) {
StartupStep step = startupStepRecorder.beginStep(Component.class, entry.getKey(), "Start Component");
try {
startService(entry.getValue());
} catch (Exception e) {
throw new FailedToStartComponentException(entry.getKey(), e.getMessage(), e);
} finally {
startupStepRecorder.endStep(step);
}
}
if (!startupListeners.isEmpty()) {
StartupStep subStep
= startupStepRecorder.beginStep(CamelContext.class, getName(), "StartupListener onCamelContextStarting");
// sort the startup listeners so they are started in the right order
startupListeners.sort(OrderedComparator.get());
// now call the startup listeners where the routes has been warmed up
// (only the actual route consumer has not yet been started)
for (StartupListener startup : startupListeners) {
startup.onCamelContextStarting(getCamelContextReference(), isStarted());
}
startupStepRecorder.endStep(subStep);
}
// start notifiers as services
for (EventNotifier notifier : getManagementStrategy().getEventNotifiers()) {
if (notifier instanceof Service) {
startService((Service) notifier);
}
}
// must let some bootstrap service be started before we can notify the starting event
EventHelper.notifyCamelContextStarting(this);
if (isUseDataType()) {
// log if DataType has been enabled
LOG.debug("Message DataType is enabled on CamelContext: {}", getName());
}
// 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
if (isStreamCachingInUse()) {
// stream caching is in use so enable the strategy
getStreamCachingStrategy().setEnabled(true);
} else {
// log if stream caching is not in use as this can help people to
// enable it if they use streams
LOG.debug("StreamCaching is not in use. If using streams then it's recommended to enable stream caching."
+ " See more details at http://camel.apache.org/stream-caching.html");
}
if (isAllowUseOriginalMessage()) {
LOG.debug("AllowUseOriginalMessage enabled because UseOriginalMessage is in use");
}
LOG.debug("Using HeadersMapFactory: {}", getHeadersMapFactory());
if (isCaseInsensitiveHeaders() && !getHeadersMapFactory().isCaseInsensitive()) {
LOG.info(
"HeadersMapFactory: {} is case-sensitive which can cause problems for protocols such as HTTP based, which rely on case-insensitive headers.",
getHeadersMapFactory());
} else if (!isCaseInsensitiveHeaders()) {
// notify user that the headers are sensitive which can be a problem
LOG.info(
"Case-insensitive headers is not in use. This can cause problems for protocols such as HTTP based, which rely on case-insensitive headers.");
}
// lets log at INFO level if we are not using the default reactive executor
if (!getReactiveExecutor().getClass().getSimpleName().equals("DefaultReactiveExecutor")) {
LOG.info("Using ReactiveExecutor: {}", getReactiveExecutor());
} else {
LOG.debug("Using ReactiveExecutor: {}", getReactiveExecutor());
}
// lets log at INFO level if we are not using the default thread pool factory
if (!getExecutorServiceManager().getThreadPoolFactory().getClass().getSimpleName().equals("DefaultThreadPoolFactory")) {
LOG.info("Using ThreadPoolFactory: {}", getExecutorServiceManager().getThreadPoolFactory());
} else {
LOG.debug("Using ThreadPoolFactory: {}", getExecutorServiceManager().getThreadPoolFactory());
}
HealthCheckRegistry hcr = getExtension(HealthCheckRegistry.class);
if (hcr != null && hcr.isEnabled()) {
LOG.debug("Using HealthCheck: {}", hcr.getId());
}
// start routes
if (doNotStartRoutesOnFirstStart) {
LOG.debug("Skip starting routes as CamelContext has been configured with autoStartup=false");
}
if (isDumpRoutes() != null && isDumpRoutes()) {
doDumpRoutes();
}
if (!getRouteController().isSupervising()) {
// invoke this logic to warmup the routes and if possible also start the routes (using default route controller)
StartupStep subStep = startupStepRecorder.beginStep(CamelContext.class, getName(), "Start Routes");
EventHelper.notifyCamelContextRoutesStarting(this);
internalRouteStartupManager.doStartOrResumeRoutes(routeServices, true, !doNotStartRoutesOnFirstStart, false, true);
EventHelper.notifyCamelContextRoutesStarted(this);
startupStepRecorder.endStep(subStep);
}
// ensure extra dev consoles is loaded in case additional JARs has been dynamically added to the classpath
if (devConsole) {
StartupStep step = startupStepRecorder.beginStep(CamelContext.class, null, "Scan DevConsoles (phase 2)");
DevConsoleRegistry dcr = getExtension(DevConsoleRegistry.class);
if (dcr != null) {
dcr.loadDevConsoles(true);
}
startupStepRecorder.endStep(step);
}
long cacheCounter = beanIntrospection != null ? beanIntrospection.getCachedClassesCounter() : 0;
if (cacheCounter > 0) {
LOG.debug("Clearing BeanIntrospection cache with {} objects using during starting Camel", cacheCounter);
beanIntrospection.clearCache();
}
long invokedCounter = beanIntrospection != null ? beanIntrospection.getInvokedCounter() : 0;
if (invokedCounter > 0) {
LOG.debug("BeanIntrospection invoked {} times during starting Camel", invokedCounter);
}
// starting will continue in the start method
}
@Override
protected void doStop() throws Exception {
stopWatch.restart();
if (startupSummaryLevel != StartupSummaryLevel.Oneline && startupSummaryLevel != StartupSummaryLevel.Off) {
if (shutdownStrategy != null && shutdownStrategy.getTimeUnit() != null) {
long timeout = shutdownStrategy.getTimeUnit().toMillis(shutdownStrategy.getTimeout());
// only use precise print duration if timeout is shorter than 10 seconds
String to = TimeUtils.printDuration(timeout, timeout < 10000);
LOG.info("Apache Camel {} ({}) is shutting down (timeout:{})", getVersion(), getName(), to);
} else {
LOG.info("Apache Camel {} ({}) is shutting down", getVersion(), getName());
}
}
EventHelper.notifyCamelContextStopping(this);
EventHelper.notifyCamelContextRoutesStopping(this);
// Stop the route controller
ServiceHelper.stopAndShutdownService(this.routeController);
// stop route inputs in the same order as they were started, so we stop
// the very first inputs at first
try {
// force shutting down routes as they may otherwise cause shutdown to hang
if (shutdownStrategy != null) {
shutdownStrategy.shutdownForced(this, getRouteStartupOrder());
}
} catch (Throwable e) {
LOG.warn("Error occurred while shutting down routes. This exception will be ignored.", e);
}
// shutdown await manager to trigger interrupt of blocked threads to
// attempt to free these threads graceful
shutdownServices(asyncProcessorAwaitManager);
// we need also to include routes which failed to start to ensure all resources get stopped when stopping Camel
for (RouteService routeService : routeServices.values()) {
boolean found = routeStartupOrder.stream().anyMatch(o -> o.getRoute().getId().equals(routeService.getId()));
if (!found) {
LOG.debug("Route: {} which failed to startup will be stopped", routeService.getId());
routeStartupOrder.add(internalRouteStartupManager.doPrepareRouteToBeStarted(routeService));
}
}
routeStartupOrder.sort(Comparator.comparingInt(RouteStartupOrder::getStartupOrder).reversed());
List list = new ArrayList<>();
for (RouteStartupOrder startupOrder : routeStartupOrder) {
DefaultRouteStartupOrder order = (DefaultRouteStartupOrder) startupOrder;
RouteService routeService = order.getRouteService();
list.add(routeService);
}
shutdownServices(list, false);
if (startupSummaryLevel != StartupSummaryLevel.Oneline
&& startupSummaryLevel != StartupSummaryLevel.Off) {
logRouteStopSummary(LoggingLevel.INFO);
}
// do not clear route services or startup listeners as we can start
// Camel again and get the route back as before
routeStartupOrder.clear();
EventHelper.notifyCamelContextRoutesStopped(this);
// but clear any suspend routes
suspendedRouteServices.clear();
// stop consumers from the services to close first, such as POJO
// consumer (eg @Consumer)
// which we need to stop after the routes, as a POJO consumer is
// essentially a route also
for (Service service : servicesToStop) {
if (service instanceof Consumer) {
shutdownServices(service);
}
}
// the stop order is important
// shutdown default error handler thread pool
if (errorHandlerExecutorService != null) {
// force shutting down the thread pool
getExecutorServiceManager().shutdownNow(errorHandlerExecutorService);
errorHandlerExecutorService = null;
}
// shutdown debugger
ServiceHelper.stopAndShutdownService(getDebugger());
shutdownServices(endpoints.values());
endpoints.clear();
shutdownServices(components.values());
components.clear();
shutdownServices(languages.values());
languages.clear();
// shutdown services as late as possible (except type converters as they may be needed during the remainder of the stopping)
shutdownServices(servicesToStop);
servicesToStop.clear();
try {
for (LifecycleStrategy strategy : lifecycleStrategies) {
strategy.onContextStopped(this);
}
} catch (Throwable e) {
LOG.warn("Error occurred while stopping lifecycle strategies. This exception will be ignored.", e);
}
// must notify that we are stopped before stopping the management strategy
EventHelper.notifyCamelContextStopped(this);
// stop the notifier service
if (getManagementStrategy() != null) {
for (EventNotifier notifier : getManagementStrategy().getEventNotifiers()) {
shutdownServices(notifier);
}
}
// shutdown management and lifecycle after all other services
shutdownServices(managementStrategy);
shutdownServices(managementMBeanAssembler);
shutdownServices(lifecycleStrategies);
// do not clear lifecycleStrategies as we can start Camel again and get
// the route back as before
// shutdown executor service, reactive executor last
shutdownServices(executorServiceManager);
shutdownServices(reactiveExecutor);
// shutdown type converter and registry as late as possible
ServiceHelper.stopService(typeConverter);
ServiceHelper.stopService(typeConverterRegistry);
ServiceHelper.stopService(registry);
// stop the lazy created so they can be re-created on restart
forceStopLazyInitialization();
if (startupSummaryLevel != StartupSummaryLevel.Off) {
if (LOG.isInfoEnabled()) {
String taken = TimeUtils.printDuration(stopWatch.taken(), true);
String jvm = logJvmUptime ? getJvmUptime() : null;
if (jvm != null) {
LOG.info("Apache Camel {} ({}) shutdown in {} (uptime:{} JVM-uptime:{})", getVersion(), getName(), taken,
getUptime(), jvm);
} else {
LOG.info("Apache Camel {} ({}) shutdown in {} (uptime:{})", getVersion(), getName(), taken, getUptime());
}
}
}
// ensure any recorder is stopped in case it was kept running
startupStepRecorder.stop();
// and clear start date
startDate = 0;
// Call all registered trackers with this context
// Note, this may use a partially constructed object
CamelContextTracker.notifyContextDestroyed(this);
firstStartDone = true;
}
@Override
protected void doFail(Exception e) {
super.doFail(e);
// reset flag in case of startup fail as we want to be able to allow to start again
firstStartDone = false;
}
protected void doDumpRoutes() {
// noop
}
protected void logRouteStopSummary(LoggingLevel loggingLevel) {
CamelLogger logger = new CamelLogger(LOG, loggingLevel);
if (logger.shouldLog()) {
int total = 0;
int stopped = 0;
int forced = 0;
List lines = new ArrayList<>();
if (shutdownStrategy != null && shutdownStrategy.isShutdownRoutesInReverseOrder()) {
routeStartupOrder.sort(Comparator.comparingInt(RouteStartupOrder::getStartupOrder).reversed());
} else {
routeStartupOrder.sort(Comparator.comparingInt(RouteStartupOrder::getStartupOrder));
}
for (RouteStartupOrder order : routeStartupOrder) {
total++;
String id = order.getRoute().getRouteId();
String status = getRouteStatus(id).name();
if (ServiceStatus.Stopped.name().equals(status)) {
stopped++;
}
if (order.getRoute().getProperties().containsKey("forcedShutdown")) {
forced++;
status = "Forced stopped";
}
// use basic endpoint uri to not log verbose details or potential sensitive data
String uri = order.getRoute().getEndpoint().getEndpointBaseUri();
uri = URISupport.sanitizeUri(uri);
lines.add(String.format(" %s %s (%s)", status, id, uri));
}
if (forced > 0) {
logger.log(String.format("Routes stopped (total:%s stopped:%s forced:%s)", total, stopped, forced));
} else if (total != stopped) {
logger.log(String.format("Routes stopped (total:%s stopped:%s)", total, stopped));
} else {
logger.log(String.format("Routes stopped (stopped:%s)", stopped));
}
// if we are default/verbose then log each route line
if (startupSummaryLevel == StartupSummaryLevel.Default || startupSummaryLevel == StartupSummaryLevel.Verbose) {
for (String line : lines) {
logger.log(line);
}
}
}
}
public void startRouteDefinitions() throws Exception {
}
public void removeRouteDefinitionsFromTemplate() throws Exception {
}
protected boolean isStreamCachingInUse() throws Exception {
return isStreamCaching();
}
protected void bindDataFormats() throws Exception {
}
protected boolean routeSupportsSuspension(String routeId) {
RouteService routeService = routeServices.get(routeId);
if (routeService != null) {
return routeService.getRoute().supportsSuspension();
}
return false;
}
private void shutdownServices(Object service) {
// do not rethrow exception as we want to keep shutting down in case of
// problems
// allow us to do custom work before delegating to service helper
try {
if (service instanceof Service) {
ServiceHelper.stopAndShutdownService(service);
} else if (service instanceof Collection) {
ServiceHelper.stopAndShutdownServices((Collection>) service);
}
} catch (Throwable e) {
LOG.warn("Error occurred while shutting down service: " + service + ". This exception will be ignored.", e);
// fire event
EventHelper.notifyServiceStopFailure(this, service, e);
}
}
private void shutdownServices(Collection> services) {
// reverse stopping by default
shutdownServices(services, true);
}
private void shutdownServices(Collection> services, boolean reverse) {
Collection> list = services;
if (reverse) {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy