All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.camel.impl.RouteService Maven / Gradle / Ivy

There is a newer version: 4.6.0
Show newest version
/**
 * 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;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.camel.CamelContext;
import org.apache.camel.Channel;
import org.apache.camel.Consumer;
import org.apache.camel.Endpoint;
import org.apache.camel.EndpointAware;
import org.apache.camel.FailedToCreateRouteException;
import org.apache.camel.Processor;
import org.apache.camel.Route;
import org.apache.camel.RouteAware;
import org.apache.camel.Service;
import org.apache.camel.model.OnCompletionDefinition;
import org.apache.camel.model.OnExceptionDefinition;
import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.processor.ErrorHandler;
import org.apache.camel.spi.LifecycleStrategy;
import org.apache.camel.spi.RouteContext;
import org.apache.camel.spi.RoutePolicy;
import org.apache.camel.support.ChildServiceSupport;
import org.apache.camel.util.EventHelper;
import org.apache.camel.util.ServiceHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import static org.apache.camel.impl.MDCUnitOfWork.MDC_CAMEL_CONTEXT_ID;
import static org.apache.camel.impl.MDCUnitOfWork.MDC_ROUTE_ID;

/**
 * Represents the runtime objects for a given {@link RouteDefinition} so that it can be stopped independently
 * of other routes
 *
 * @version 
 */
public class RouteService extends ChildServiceSupport {

    private static final Logger LOG = LoggerFactory.getLogger(RouteService.class);

    private final DefaultCamelContext camelContext;
    private final RouteDefinition routeDefinition;
    private final List routeContexts;
    private final List routes;
    private final String id;
    private boolean removingRoutes;
    private final Map inputs = new HashMap();
    private final AtomicBoolean warmUpDone = new AtomicBoolean(false);
    private final AtomicBoolean endpointDone = new AtomicBoolean(false);

    public RouteService(DefaultCamelContext camelContext, RouteDefinition routeDefinition, List routeContexts, List routes) {
        this.camelContext = camelContext;
        this.routeDefinition = routeDefinition;
        this.routeContexts = routeContexts;
        this.routes = routes;
        this.id = routeDefinition.idOrCreate(camelContext.getNodeIdFactory());
    }

    public String getId() {
        return id;
    }

    public CamelContext getCamelContext() {
        return camelContext;
    }

    public List getRouteContexts() {
        return routeContexts;
    }

    public RouteDefinition getRouteDefinition() {
        return routeDefinition;
    }

    public Collection getRoutes() {
        return routes;
    }

    /**
     * Gather all the endpoints this route service uses
     * 

* This implementation finds the endpoints by searching all the child services * for {@link org.apache.camel.EndpointAware} processors which uses an endpoint. */ public Set gatherEndpoints() { Set answer = new LinkedHashSet(); for (Route route : routes) { Set services = gatherChildServices(route, true); for (Service service : services) { if (service instanceof EndpointAware) { Endpoint endpoint = ((EndpointAware) service).getEndpoint(); if (endpoint != null) { answer.add(endpoint); } } } } return answer; } /** * Gets the inputs to the routes. * * @return list of {@link Consumer} as inputs for the routes */ public Map getInputs() { return inputs; } public boolean isRemovingRoutes() { return removingRoutes; } public void setRemovingRoutes(boolean removingRoutes) { this.removingRoutes = removingRoutes; } public void warmUp() throws Exception { try { doWarmUp(); } catch (Exception e) { throw new FailedToCreateRouteException(routeDefinition.getId(), routeDefinition.toString(), e); } } protected synchronized void doWarmUp() throws Exception { if (endpointDone.compareAndSet(false, true)) { // endpoints should only be started once as they can be reused on other routes // and whatnot, thus their lifecycle is to start once, and only to stop when Camel shutdown for (Route route : routes) { // ensure endpoint is started first (before the route services, such as the consumer) ServiceHelper.startService(route.getEndpoint()); } } if (warmUpDone.compareAndSet(false, true)) { for (Route route : routes) { try (MDCHelper mdcHelper = new MDCHelper(route.getId())) { // warm up the route first route.warmUp(); LOG.debug("Starting services on route: {}", route.getId()); List services = route.getServices(); // callback that we are staring these services route.onStartingServices(services); // gather list of services to start as we need to start child services as well Set list = new LinkedHashSet(); for (Service service : services) { list.addAll(ServiceHelper.getChildServices(service)); } // split into consumers and child services as we need to start the consumers // afterwards to avoid them being active while the others start List childServices = new ArrayList(); for (Service service : list) { // inject the route if (service instanceof RouteAware) { ((RouteAware) service).setRoute(route); } if (service instanceof Consumer) { inputs.put(route, (Consumer) service); } else { childServices.add(service); } } startChildService(route, childServices); // fire event EventHelper.notifyRouteAdded(camelContext, route); } } // ensure lifecycle strategy is invoked which among others enlist the route in JMX for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) { strategy.onRoutesAdd(routes); } // add routes to camel context camelContext.addRouteCollection(routes); // add the routes to the inflight registry so they are pre-installed for (Route route : routes) { camelContext.getInflightRepository().addRoute(route.getId()); } } } protected void doStart() throws Exception { warmUp(); for (Route route : routes) { try (MDCHelper mdcHelper = new MDCHelper(route.getId())) { // start the route itself ServiceHelper.startService(route); // invoke callbacks on route policy if (route.getRouteContext().getRoutePolicyList() != null) { for (RoutePolicy routePolicy : route.getRouteContext().getRoutePolicyList()) { routePolicy.onStart(route); } } // fire event EventHelper.notifyRouteStarted(camelContext, route); } } } protected void doStop() throws Exception { // if we are stopping CamelContext then we are shutting down boolean isShutdownCamelContext = camelContext.isStopping(); if (isShutdownCamelContext || isRemovingRoutes()) { // need to call onRoutesRemove when the CamelContext is shutting down or Route is shutdown for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) { strategy.onRoutesRemove(routes); } } for (Route route : routes) { try (MDCHelper mdcHelper = new MDCHelper(route.getId())) { LOG.debug("Stopping services on route: {}", route.getId()); // gather list of services to stop as we need to start child services as well Set services = gatherChildServices(route, true); // stop services stopChildService(route, services, isShutdownCamelContext); // stop the route itself if (isShutdownCamelContext) { ServiceHelper.stopAndShutdownServices(route); } else { ServiceHelper.stopServices(route); } // invoke callbacks on route policy if (route.getRouteContext().getRoutePolicyList() != null) { for (RoutePolicy routePolicy : route.getRouteContext().getRoutePolicyList()) { routePolicy.onStop(route); } } // fire event EventHelper.notifyRouteStopped(camelContext, route); } } if (isRemovingRoutes()) { camelContext.removeRouteCollection(routes); } // need to warm up again warmUpDone.set(false); } @Override protected void doShutdown() throws Exception { for (Route route : routes) { try (MDCHelper mdcHelper = new MDCHelper(route.getId())) { LOG.debug("Shutting down services on route: {}", route.getId()); // gather list of services to stop as we need to start child services as well Set services = gatherChildServices(route, true); // shutdown services stopChildService(route, services, true); // shutdown the route itself ServiceHelper.stopAndShutdownServices(route); // endpoints should only be stopped when Camel is shutting down // see more details in the warmUp method ServiceHelper.stopAndShutdownServices(route.getEndpoint()); // invoke callbacks on route policy if (route.getRouteContext().getRoutePolicyList() != null) { for (RoutePolicy routePolicy : route.getRouteContext().getRoutePolicyList()) { routePolicy.onRemove(route); } } // fire event EventHelper.notifyRouteRemoved(camelContext, route); } } // need to call onRoutesRemove when the CamelContext is shutting down or Route is shutdown for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) { strategy.onRoutesRemove(routes); } // remove the routes from the inflight registry for (Route route : routes) { camelContext.getInflightRepository().removeRoute(route.getId()); } // remove the routes from the collections camelContext.removeRouteCollection(routes); // clear inputs on shutdown inputs.clear(); warmUpDone.set(false); endpointDone.set(false); } @Override protected void doSuspend() throws Exception { // suspend and resume logic is provided by DefaultCamelContext which leverages ShutdownStrategy // to safely suspend and resume for (Route route : routes) { try (MDCHelper mdcHelper = new MDCHelper(route.getId())) { if (route.getRouteContext().getRoutePolicyList() != null) { for (RoutePolicy routePolicy : route.getRouteContext().getRoutePolicyList()) { routePolicy.onSuspend(route); } } } } } @Override protected void doResume() throws Exception { // suspend and resume logic is provided by DefaultCamelContext which leverages ShutdownStrategy // to safely suspend and resume for (Route route : routes) { try (MDCHelper mdcHelper = new MDCHelper(route.getId())) { if (route.getRouteContext().getRoutePolicyList() != null) { for (RoutePolicy routePolicy : route.getRouteContext().getRoutePolicyList()) { routePolicy.onResume(route); } } } } } protected void startChildService(Route route, List services) throws Exception { for (Service service : services) { LOG.debug("Starting child service on route: {} -> {}", route.getId(), service); for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) { strategy.onServiceAdd(camelContext, service, route); } ServiceHelper.startService(service); addChildService(service); } } protected void stopChildService(Route route, Set services, boolean shutdown) throws Exception { for (Service service : services) { LOG.debug("{} child service on route: {} -> {}", new Object[]{shutdown ? "Shutting down" : "Stopping", route.getId(), service}); if (service instanceof ErrorHandler) { // special for error handlers for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) { strategy.onErrorHandlerRemove(route.getRouteContext(), (Processor) service, route.getRouteContext().getRoute().getErrorHandlerBuilder()); } } else { for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) { strategy.onServiceRemove(camelContext, service, route); } } if (shutdown) { ServiceHelper.stopAndShutdownService(service); } else { ServiceHelper.stopService(service); } removeChildService(service); } } /** * Gather all child services */ private Set gatherChildServices(Route route, boolean includeErrorHandler) { // gather list of services to stop as we need to start child services as well List services = new ArrayList(); services.addAll(route.getServices()); // also get route scoped services doGetRouteScopedServices(services, route); Set list = new LinkedHashSet(); for (Service service : services) { list.addAll(ServiceHelper.getChildServices(service)); } if (includeErrorHandler) { // also get route scoped error handler (which must be done last) doGetRouteScopedErrorHandler(list, route); } Set answer = new LinkedHashSet(); answer.addAll(list); return answer; } /** * Gather the route scoped error handler from the given route */ private void doGetRouteScopedErrorHandler(Set services, Route route) { // only include error handlers if they are route scoped boolean includeErrorHandler = !routeDefinition.isContextScopedErrorHandler(route.getRouteContext().getCamelContext()); List extra = new ArrayList(); if (includeErrorHandler) { for (Service service : services) { if (service instanceof Channel) { Processor eh = ((Channel) service).getErrorHandler(); if (eh instanceof Service) { extra.add((Service) eh); } } } } if (!extra.isEmpty()) { services.addAll(extra); } } /** * Gather all other kind of route scoped services from the given route, except error handler */ private void doGetRouteScopedServices(List services, Route route) { for (ProcessorDefinition output : route.getRouteContext().getRoute().getOutputs()) { if (output instanceof OnExceptionDefinition) { OnExceptionDefinition onExceptionDefinition = (OnExceptionDefinition) output; if (onExceptionDefinition.isRouteScoped()) { Processor errorHandler = onExceptionDefinition.getErrorHandler(route.getId()); if (errorHandler instanceof Service) { services.add((Service) errorHandler); } } } else if (output instanceof OnCompletionDefinition) { OnCompletionDefinition onCompletionDefinition = (OnCompletionDefinition) output; if (onCompletionDefinition.isRouteScoped()) { Processor onCompletionProcessor = onCompletionDefinition.getOnCompletion(route.getId()); if (onCompletionProcessor instanceof Service) { services.add((Service) onCompletionProcessor); } } } } } class MDCHelper implements AutoCloseable { final Map originalContextMap; MDCHelper(String routeId) { if (getCamelContext().isUseMDCLogging()) { originalContextMap = MDC.getCopyOfContextMap(); MDC.put(MDC_CAMEL_CONTEXT_ID, getCamelContext().getName()); MDC.put(MDC_ROUTE_ID, routeId); } else { originalContextMap = null; } } @Override public void close() { if (getCamelContext().isUseMDCLogging()) { if (originalContextMap != null) { MDC.setContextMap(originalContextMap); } else { MDC.clear(); } } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy