001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.impl;
018
019 import java.util.ArrayList;
020 import java.util.Arrays;
021 import java.util.Collection;
022 import java.util.HashMap;
023 import java.util.List;
024 import java.util.Map;
025
026 import org.apache.camel.CamelContext;
027 import org.apache.camel.Consumer;
028 import org.apache.camel.Navigate;
029 import org.apache.camel.Route;
030 import org.apache.camel.Service;
031 import org.apache.camel.model.RouteDefinition;
032 import org.apache.camel.spi.LifecycleStrategy;
033 import org.apache.camel.spi.RouteContext;
034 import org.apache.camel.util.EventHelper;
035 import org.apache.camel.util.ServiceHelper;
036 import org.apache.commons.logging.Log;
037 import org.apache.commons.logging.LogFactory;
038
039 /**
040 * Represents the runtime objects for a given {@link RouteDefinition} so that it can be stopped independently
041 * of other routes
042 *
043 * @version $Revision: 830861 $
044 */
045 public class RouteService extends ServiceSupport {
046
047 private static final Log LOG = LogFactory.getLog(RouteService.class);
048
049 private final DefaultCamelContext camelContext;
050 private final RouteDefinition routeDefinition;
051 private final List<RouteContext> routeContexts;
052 private final List<Route> routes;
053 private final String id;
054 private boolean startInputs = true;
055 private final Map<Route, Consumer> inputs = new HashMap<Route, Consumer>();
056
057 public RouteService(DefaultCamelContext camelContext, RouteDefinition routeDefinition, List<RouteContext> routeContexts, List<Route> routes) {
058 this.camelContext = camelContext;
059 this.routeDefinition = routeDefinition;
060 this.routeContexts = routeContexts;
061 this.routes = routes;
062 this.id = routeDefinition.idOrCreate(camelContext.getNodeIdFactory());
063 }
064
065 public String getId() {
066 return id;
067 }
068
069 public CamelContext getCamelContext() {
070 return camelContext;
071 }
072
073 public List<RouteContext> getRouteContexts() {
074 return routeContexts;
075 }
076
077 public RouteDefinition getRouteDefinition() {
078 return routeDefinition;
079 }
080
081 public Collection<Route> getRoutes() {
082 return routes;
083 }
084
085 /**
086 * Sets whether inputs (consumers) should be started when starting the routes
087 * <p/>
088 * By default inputs are started.
089 *
090 * @param flag flag to either start inputs or not
091 */
092 public void startInputs(boolean flag) {
093 this.startInputs = flag;
094 }
095
096 /**
097 * Gets the inputs to the routes.
098 *
099 * @return list of {@link Consumer} as inputs for the routes
100 */
101 public Map<Route, Consumer> getInputs() {
102 return inputs;
103 }
104
105 protected void doStart() throws Exception {
106 camelContext.addRouteCollection(routes);
107
108 for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) {
109 strategy.onRoutesAdd(routes);
110 }
111
112 for (Route route : routes) {
113 if (LOG.isTraceEnabled()) {
114 LOG.trace("Starting route services: " + route);
115 }
116
117 // TODO: We should also consider processors which are not services then we can manage all processors as well
118 // otherwise its only the processors which is a Service
119
120 List<Service> services = route.getServices();
121
122 // callback that we are staring these services
123 route.onStartingServices(services);
124
125 // gather list of services to start as we need to start child services as well
126 List<Service> list = new ArrayList<Service>();
127 for (Service service : services) {
128 doGetChildServices(list, service);
129 }
130
131 // split into consumers and child services as we need to start the consumers
132 // afterwards to avoid them being active while the others start
133 List<Service> childServices = new ArrayList<Service>();
134 for (Service service : list) {
135 if (service instanceof Consumer) {
136 inputs.put(route, (Consumer) service);
137 } else {
138 childServices.add(service);
139 }
140 }
141 startChildService(route, childServices);
142
143 // start the route itself
144 ServiceHelper.startService(route);
145
146 // fire event
147 EventHelper.notifyRouteStarted(camelContext, route);
148 }
149
150 if (startInputs) {
151 // start the input consumers
152 for (Map.Entry<Route, Consumer> entry : inputs.entrySet()) {
153 Route route = entry.getKey();
154 Consumer consumer = entry.getValue();
155 startChildService(route, consumer);
156 }
157 }
158 }
159
160 protected void doStop() throws Exception {
161 // clear inputs
162 inputs.clear();
163
164 for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) {
165 strategy.onRoutesRemove(routes);
166 }
167
168 for (Route route : routes) {
169 if (LOG.isTraceEnabled()) {
170 LOG.trace("Stopping route: " + route);
171 }
172 // getServices will not add services again
173 List<Service> services = route.getServices();
174
175 // gather list of services to stop as we need to start child services as well
176 List<Service> list = new ArrayList<Service>();
177 for (Service service : services) {
178 doGetChildServices(list, service);
179 }
180 stopChildService(route, list);
181
182 // stop the route itself
183 ServiceHelper.stopService(route);
184
185 // fire event
186 EventHelper.notifyRouteStopped(camelContext, route);
187 }
188
189 camelContext.removeRouteCollection(routes);
190 }
191
192 protected void startChildService(Route route, Service... services) throws Exception {
193 List<Service> list = new ArrayList<Service>(Arrays.asList(services));
194 startChildService(route, list);
195 }
196
197 protected void startChildService(Route route, List<Service> services) throws Exception {
198 for (Service service : services) {
199 for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) {
200 strategy.onServiceAdd(camelContext, service, route);
201 }
202 ServiceHelper.startService(service);
203 addChildService(service);
204 }
205 }
206
207 protected void stopChildService(Route route, List<Service> services) throws Exception {
208 for (Service service : services) {
209 for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) {
210 strategy.onServiceRemove(camelContext, service, route);
211 }
212 ServiceHelper.stopService(service);
213 removeChildService(service);
214 }
215 }
216
217 /**
218 * Need to recursive start child services for routes
219 */
220 private static void doGetChildServices(List<Service> services, Service service) throws Exception {
221 services.add(service);
222
223 if (service instanceof Navigate) {
224 Navigate<?> nav = (Navigate<?>) service;
225 if (nav.hasNext()) {
226 List<?> children = nav.next();
227 for (Object child : children) {
228 if (child instanceof Service) {
229 doGetChildServices(services, (Service) child);
230 }
231 }
232 }
233 }
234 }
235
236 }