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