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.util; 018 019 import java.util.Arrays; 020 import java.util.Collection; 021 import java.util.LinkedHashSet; 022 import java.util.List; 023 import java.util.Set; 024 025 import org.apache.camel.Channel; 026 import org.apache.camel.Navigate; 027 import org.apache.camel.Processor; 028 import org.apache.camel.Service; 029 import org.apache.camel.ShutdownableService; 030 import org.apache.camel.StatefulService; 031 import org.apache.camel.SuspendableService; 032 import org.slf4j.Logger; 033 import org.slf4j.LoggerFactory; 034 035 /** 036 * A collection of helper methods for working with {@link Service} objects. 037 * 038 * @version 039 */ 040 public final class ServiceHelper { 041 private static final Logger LOG = LoggerFactory.getLogger(ServiceHelper.class); 042 043 /** 044 * Utility classes should not have a public constructor. 045 */ 046 private ServiceHelper() { 047 } 048 049 /** 050 * Starts the given {@code value} if it's a {@link Service} or a collection of it. 051 * <p/> 052 * Calling this method has no effect if {@code value} is {@code null}. 053 * 054 * @see #startService(Service) 055 * @see #startServices(Collection) 056 */ 057 public static void startService(Object value) throws Exception { 058 if (value instanceof Service) { 059 startService((Service)value); 060 } else if (value instanceof Collection) { 061 startServices((Collection<?>)value); 062 } 063 } 064 065 /** 066 * Starts the given {@code service}. 067 * <p/> 068 * Calling this method has no effect if {@code service} is {@code null}. 069 * 070 * @see Service#start() 071 */ 072 public static void startService(Service service) throws Exception { 073 if (service != null) { 074 service.start(); 075 } 076 } 077 078 /** 079 * Starts each element of the given {@code services} if {@code services} itself is 080 * not {@code null}, otherwise this method would return immediately. 081 * 082 * @see #startServices(Collection) 083 */ 084 public static void startServices(Object... services) throws Exception { 085 if (services == null) { 086 return; 087 } 088 List<Object> list = Arrays.asList(services); 089 startServices(list); 090 } 091 092 /** 093 * Starts each element of the given {@code services} if {@code services} itself is 094 * not {@code null}, otherwise this method would return immediately. 095 * 096 * @see #startService(Object) 097 */ 098 public static void startServices(Collection<?> services) throws Exception { 099 if (services == null) { 100 return; 101 } 102 for (Object value : services) { 103 startService(value); 104 } 105 } 106 107 /** 108 * Stops each element of the given {@code services} if {@code services} itself is 109 * not {@code null}, otherwise this method would return immediately. 110 * <p/> 111 * If there's any exception being thrown while stopping the elements one after the 112 * other this method would rethrow the <b>first</b> such exception being thrown. 113 * 114 * @see #stopServices(Collection) 115 */ 116 public static void stopServices(Object... services) throws Exception { 117 if (services == null) { 118 return; 119 } 120 List<Object> list = Arrays.asList(services); 121 stopServices(list); 122 } 123 124 /** 125 * Stops the given {@code value}, rethrowing the first exception caught. 126 * <p/> 127 * Calling this method has no effect if {@code value} is {@code null}. 128 * 129 * @see Service#stop() 130 * @see #stopServices(Collection) 131 */ 132 public static void stopService(Object value) throws Exception { 133 if (isStopped(value)) { 134 // only stop service if not already stopped 135 LOG.trace("Service already stopped: {}", value); 136 return; 137 } 138 if (value instanceof Service) { 139 Service service = (Service)value; 140 LOG.trace("Stopping service {}", value); 141 service.stop(); 142 } else if (value instanceof Collection) { 143 stopServices((Collection<?>)value); 144 } 145 } 146 147 /** 148 * Stops each element of the given {@code services} if {@code services} itself is 149 * not {@code null}, otherwise this method would return immediately. 150 * <p/> 151 * If there's any exception being thrown while stopping the elements one after the 152 * other this method would rethrow the <b>first</b> such exception being thrown. 153 * 154 * @see #stopService(Object) 155 */ 156 public static void stopServices(Collection<?> services) throws Exception { 157 if (services == null) { 158 return; 159 } 160 Exception firstException = null; 161 for (Object value : services) { 162 try { 163 stopService(value); 164 } catch (Exception e) { 165 if (LOG.isDebugEnabled()) { 166 LOG.debug("Caught exception stopping service: " + value, e); 167 } 168 if (firstException == null) { 169 firstException = e; 170 } 171 } 172 } 173 if (firstException != null) { 174 throw firstException; 175 } 176 } 177 178 /** 179 * Stops and shutdowns each element of the given {@code services} if {@code services} itself is 180 * not {@code null}, otherwise this method would return immediately. 181 * <p/> 182 * If there's any exception being thrown while stopping/shutting down the elements one after 183 * the other this method would rethrow the <b>first</b> such exception being thrown. 184 * 185 * @see #stopAndShutdownServices(Collection) 186 */ 187 public static void stopAndShutdownServices(Object... services) throws Exception { 188 if (services == null) { 189 return; 190 } 191 List<Object> list = Arrays.asList(services); 192 stopAndShutdownServices(list); 193 } 194 195 /** 196 * Stops and shutdowns the given {@code service}, rethrowing the first exception caught. 197 * <p/> 198 * Calling this method has no effect if {@code value} is {@code null}. 199 * 200 * @see #stopService(Object) 201 * @see ShutdownableService#shutdown() 202 */ 203 public static void stopAndShutdownService(Object value) throws Exception { 204 stopService(value); 205 206 // then try to shutdown 207 if (value instanceof ShutdownableService) { 208 ShutdownableService service = (ShutdownableService)value; 209 LOG.trace("Shutting down service {}", value); 210 service.shutdown(); 211 } 212 } 213 214 /** 215 * Stops and shutdowns each element of the given {@code services} if {@code services} 216 * itself is not {@code null}, otherwise this method would return immediately. 217 * <p/> 218 * If there's any exception being thrown while stopping/shutting down the elements one after 219 * the other this method would rethrow the <b>first</b> such exception being thrown. 220 * 221 * @see #stopService(Object) 222 * @see ShutdownableService#shutdown() 223 */ 224 public static void stopAndShutdownServices(Collection<?> services) throws Exception { 225 if (services == null) { 226 return; 227 } 228 Exception firstException = null; 229 230 for (Object value : services) { 231 232 try { 233 // must stop it first 234 stopService(value); 235 236 // then try to shutdown 237 if (value instanceof ShutdownableService) { 238 ShutdownableService service = (ShutdownableService)value; 239 LOG.trace("Shutting down service: {}", service); 240 service.shutdown(); 241 } 242 } catch (Exception e) { 243 if (LOG.isDebugEnabled()) { 244 LOG.debug("Caught exception shutting down service: " + value, e); 245 } 246 if (firstException == null) { 247 firstException = e; 248 } 249 } 250 } 251 if (firstException != null) { 252 throw firstException; 253 } 254 } 255 256 /** 257 * Resumes each element of the given {@code services} if {@code services} itself is 258 * not {@code null}, otherwise this method would return immediately. 259 * <p/> 260 * If there's any exception being thrown while resuming the elements one after the 261 * other this method would rethrow the <b>first</b> such exception being thrown. 262 * 263 * @see #resumeService(Service) 264 */ 265 public static void resumeServices(Collection<?> services) throws Exception { 266 if (services == null) { 267 return; 268 } 269 Exception firstException = null; 270 for (Object value : services) { 271 if (value instanceof Service) { 272 Service service = (Service)value; 273 try { 274 resumeService(service); 275 } catch (Exception e) { 276 if (LOG.isDebugEnabled()) { 277 LOG.debug("Caught exception resuming service: " + service, e); 278 } 279 if (firstException == null) { 280 firstException = e; 281 } 282 } 283 } 284 } 285 if (firstException != null) { 286 throw firstException; 287 } 288 } 289 290 /** 291 * Resumes the given {@code service}. 292 * <p/> 293 * If {@code service} is a {@link org.apache.camel.SuspendableService} then 294 * it's {@link org.apache.camel.SuspendableService#resume()} is called but 295 * <b>only</b> if {@code service} is already {@link #isSuspended(Object) 296 * suspended}. 297 * <p/> 298 * If {@code service} is <b>not</b> a 299 * {@link org.apache.camel.SuspendableService} then it's 300 * {@link org.apache.camel.Service#start()} is called. 301 * <p/> 302 * Calling this method has no effect if {@code service} is {@code null}. 303 * 304 * @param service the service 305 * @return <tt>true</tt> if either <tt>resume</tt> method or 306 * {@link #startService(Service)} was called, <tt>false</tt> 307 * otherwise. 308 * @throws Exception is thrown if error occurred 309 * @see #startService(Service) 310 */ 311 public static boolean resumeService(Service service) throws Exception { 312 if (service instanceof SuspendableService) { 313 SuspendableService ss = (SuspendableService) service; 314 if (ss.isSuspended()) { 315 LOG.debug("Resuming service {}", service); 316 ss.resume(); 317 return true; 318 } else { 319 return false; 320 } 321 } else { 322 startService(service); 323 return true; 324 } 325 } 326 327 /** 328 * Suspends each element of the given {@code services} if {@code services} itself is 329 * not {@code null}, otherwise this method would return immediately. 330 * <p/> 331 * If there's any exception being thrown while suspending the elements one after the 332 * other this method would rethrow the <b>first</b> such exception being thrown. 333 * 334 * @see #suspendService(Service) 335 */ 336 public static void suspendServices(Collection<?> services) throws Exception { 337 if (services == null) { 338 return; 339 } 340 Exception firstException = null; 341 for (Object value : services) { 342 if (value instanceof Service) { 343 Service service = (Service)value; 344 try { 345 suspendService(service); 346 } catch (Exception e) { 347 if (LOG.isDebugEnabled()) { 348 LOG.debug("Caught exception suspending service: " + service, e); 349 } 350 if (firstException == null) { 351 firstException = e; 352 } 353 } 354 } 355 } 356 if (firstException != null) { 357 throw firstException; 358 } 359 } 360 361 /** 362 * Suspends the given {@code service}. 363 * <p/> 364 * If {@code service} is a {@link org.apache.camel.SuspendableService} then 365 * it's {@link org.apache.camel.SuspendableService#suspend()} is called but 366 * <b>only</b> if {@code service} is <b>not</b> already 367 * {@link #isSuspended(Object) suspended}. 368 * <p/> 369 * If {@code service} is <b>not</b> a 370 * {@link org.apache.camel.SuspendableService} then it's 371 * {@link org.apache.camel.Service#stop()} is called. 372 * <p/> 373 * Calling this method has no effect if {@code service} is {@code null}. 374 * 375 * @param service the service 376 * @return <tt>true</tt> if either the <tt>suspend</tt> method or 377 * {@link #stopService(Object)} was called, <tt>false</tt> 378 * otherwise. 379 * @throws Exception is thrown if error occurred 380 * @see #stopService(Object) 381 */ 382 public static boolean suspendService(Service service) throws Exception { 383 if (service instanceof SuspendableService) { 384 SuspendableService ss = (SuspendableService) service; 385 if (!ss.isSuspended()) { 386 LOG.trace("Suspending service {}", service); 387 ss.suspend(); 388 return true; 389 } else { 390 return false; 391 } 392 } else { 393 stopService(service); 394 return true; 395 } 396 } 397 398 /** 399 * Is the given service stopping or already stopped? 400 * 401 * @return <tt>true</tt> if stopping or already stopped, <tt>false</tt> otherwise 402 * @see StatefulService#isStopping() 403 * @see StatefulService#isStopped() 404 */ 405 public static boolean isStopped(Object value) { 406 if (value instanceof StatefulService) { 407 StatefulService service = (StatefulService) value; 408 if (service.isStopping() || service.isStopped()) { 409 return true; 410 } 411 } 412 return false; 413 } 414 415 /** 416 * Is the given service starting or already started? 417 * 418 * @return <tt>true</tt> if starting or already started, <tt>false</tt> otherwise 419 * @see StatefulService#isStarting() 420 * @see StatefulService#isStarted() 421 */ 422 public static boolean isStarted(Object value) { 423 if (value instanceof StatefulService) { 424 StatefulService service = (StatefulService) value; 425 if (service.isStarting() || service.isStarted()) { 426 return true; 427 } 428 } 429 return false; 430 } 431 432 /** 433 * Is the given service suspending or already suspended? 434 * 435 * @return <tt>true</tt> if suspending or already suspended, <tt>false</tt> otherwise 436 * @see StatefulService#isSuspending() 437 * @see StatefulService#isSuspended() 438 */ 439 public static boolean isSuspended(Object value) { 440 if (value instanceof StatefulService) { 441 StatefulService service = (StatefulService) value; 442 if (service.isSuspending() || service.isSuspended()) { 443 return true; 444 } 445 } 446 return false; 447 } 448 449 /** 450 * Gathers all child services by navigating the service to recursively gather all child services. 451 * <p/> 452 * The returned set does <b>not</b> include the childern being error handler. 453 * 454 * @param service the service 455 * @return the services, including the parent service, and all its children 456 */ 457 public static Set<Service> getChildServices(Service service) { 458 return getChildServices(service, false); 459 } 460 461 /** 462 * Gathers all child services by navigating the service to recursively gather all child services. 463 * 464 * @param service the service 465 * @param includeErrorHandler whether to include error handlers 466 * @return the services, including the parent service, and all its children 467 */ 468 public static Set<Service> getChildServices(Service service, boolean includeErrorHandler) { 469 Set<Service> answer = new LinkedHashSet<Service>(); 470 doGetChildServices(answer, service, includeErrorHandler); 471 return answer; 472 } 473 474 private static void doGetChildServices(Set<Service> services, Service service, boolean includeErrorHandler) { 475 services.add(service); 476 if (service instanceof Navigate) { 477 Navigate<?> nav = (Navigate<?>) service; 478 if (nav.hasNext()) { 479 List<?> children = nav.next(); 480 for (Object child : children) { 481 if (child instanceof Channel) { 482 if (includeErrorHandler) { 483 // special for error handler as they are tied to the Channel 484 Processor errorHandler = ((Channel) child).getErrorHandler(); 485 if (errorHandler != null && errorHandler instanceof Service) { 486 services.add((Service) errorHandler); 487 } 488 } 489 Processor next = ((Channel) child).getNextProcessor(); 490 if (next != null && next instanceof Service) { 491 services.add((Service) next); 492 } 493 } 494 if (child instanceof Service) { 495 doGetChildServices(services, (Service) child, includeErrorHandler); 496 } 497 } 498 } 499 } 500 } 501 502 }