001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package org.apache.hadoop.service; 020 021 import java.util.ArrayList; 022 import java.util.List; 023 024 import org.apache.commons.logging.Log; 025 import org.apache.commons.logging.LogFactory; 026 import org.apache.hadoop.classification.InterfaceAudience.Public; 027 import org.apache.hadoop.classification.InterfaceStability.Evolving; 028 import org.apache.hadoop.conf.Configuration; 029 030 /** 031 * Composition of services. 032 */ 033 @Public 034 @Evolving 035 public class CompositeService extends AbstractService { 036 037 private static final Log LOG = LogFactory.getLog(CompositeService.class); 038 039 /** 040 * Policy on shutdown: attempt to close everything (purest) or 041 * only try to close started services (which assumes 042 * that the service implementations may not handle the stop() operation 043 * except when started. 044 * Irrespective of this policy, if a child service fails during 045 * its init() or start() operations, it will have stop() called on it. 046 */ 047 protected static final boolean STOP_ONLY_STARTED_SERVICES = false; 048 049 private final List<Service> serviceList = new ArrayList<Service>(); 050 051 public CompositeService(String name) { 052 super(name); 053 } 054 055 /** 056 * Get a cloned list of services 057 * @return a list of child services at the time of invocation - 058 * added services will not be picked up. 059 */ 060 public List<Service> getServices() { 061 synchronized (serviceList) { 062 return new ArrayList<Service>(serviceList); 063 } 064 } 065 066 /** 067 * Add the passed {@link Service} to the list of services managed by this 068 * {@link CompositeService} 069 * @param service the {@link Service} to be added 070 */ 071 protected void addService(Service service) { 072 if (LOG.isDebugEnabled()) { 073 LOG.debug("Adding service " + service.getName()); 074 } 075 synchronized (serviceList) { 076 serviceList.add(service); 077 } 078 } 079 080 /** 081 * If the passed object is an instance of {@link Service}, 082 * add it to the list of services managed by this {@link CompositeService} 083 * @param object 084 * @return true if a service is added, false otherwise. 085 */ 086 protected boolean addIfService(Object object) { 087 if (object instanceof Service) { 088 addService((Service) object); 089 return true; 090 } else { 091 return false; 092 } 093 } 094 095 protected synchronized boolean removeService(Service service) { 096 synchronized (serviceList) { 097 return serviceList.remove(service); 098 } 099 } 100 101 protected void serviceInit(Configuration conf) throws Exception { 102 List<Service> services = getServices(); 103 if (LOG.isDebugEnabled()) { 104 LOG.debug(getName() + ": initing services, size=" + services.size()); 105 } 106 for (Service service : services) { 107 service.init(conf); 108 } 109 super.serviceInit(conf); 110 } 111 112 protected void serviceStart() throws Exception { 113 List<Service> services = getServices(); 114 if (LOG.isDebugEnabled()) { 115 LOG.debug(getName() + ": starting services, size=" + services.size()); 116 } 117 for (Service service : services) { 118 // start the service. If this fails that service 119 // will be stopped and an exception raised 120 service.start(); 121 } 122 super.serviceStart(); 123 } 124 125 protected void serviceStop() throws Exception { 126 //stop all services that were started 127 int numOfServicesToStop = serviceList.size(); 128 if (LOG.isDebugEnabled()) { 129 LOG.debug(getName() + ": stopping services, size=" + numOfServicesToStop); 130 } 131 stop(numOfServicesToStop, STOP_ONLY_STARTED_SERVICES); 132 super.serviceStop(); 133 } 134 135 /** 136 * Stop the services in reverse order 137 * 138 * @param numOfServicesStarted index from where the stop should work 139 * @param stopOnlyStartedServices flag to say "only start services that are 140 * started, not those that are NOTINITED or INITED. 141 * @throws RuntimeException the first exception raised during the 142 * stop process -<i>after all services are stopped</i> 143 */ 144 private void stop(int numOfServicesStarted, boolean stopOnlyStartedServices) { 145 // stop in reverse order of start 146 Exception firstException = null; 147 List<Service> services = getServices(); 148 for (int i = numOfServicesStarted - 1; i >= 0; i--) { 149 Service service = services.get(i); 150 if (LOG.isDebugEnabled()) { 151 LOG.debug("Stopping service #" + i + ": " + service); 152 } 153 STATE state = service.getServiceState(); 154 //depending on the stop police 155 if (state == STATE.STARTED 156 || (!stopOnlyStartedServices && state == STATE.INITED)) { 157 Exception ex = ServiceOperations.stopQuietly(LOG, service); 158 if (ex != null && firstException == null) { 159 firstException = ex; 160 } 161 } 162 } 163 //after stopping all services, rethrow the first exception raised 164 if (firstException != null) { 165 throw ServiceStateException.convert(firstException); 166 } 167 } 168 169 /** 170 * JVM Shutdown hook for CompositeService which will stop the give 171 * CompositeService gracefully in case of JVM shutdown. 172 */ 173 public static class CompositeServiceShutdownHook implements Runnable { 174 175 private CompositeService compositeService; 176 177 public CompositeServiceShutdownHook(CompositeService compositeService) { 178 this.compositeService = compositeService; 179 } 180 181 @Override 182 public void run() { 183 ServiceOperations.stopQuietly(compositeService); 184 } 185 } 186 187 }