001/* 002 * Copyright (C) 2009 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.google.common.util.concurrent; 018 019import com.google.common.annotations.Beta; 020import com.google.common.base.Supplier; 021import com.google.common.base.Throwables; 022 023import java.util.concurrent.Executor; 024import java.util.concurrent.TimeUnit; 025import java.util.concurrent.TimeoutException; 026import java.util.logging.Level; 027import java.util.logging.Logger; 028 029/** 030 * Base class for services that can implement {@link #startUp}, {@link #run} and 031 * {@link #shutDown} methods. This class uses a single thread to execute the 032 * service; consider {@link AbstractService} if you would like to manage any 033 * threading manually. 034 * 035 * @author Jesse Wilson 036 * @since 1.0 037 */ 038@Beta 039public abstract class AbstractExecutionThreadService implements Service { 040 private static final Logger logger = Logger.getLogger( 041 AbstractExecutionThreadService.class.getName()); 042 043 /* use AbstractService for state management */ 044 private final Service delegate = new AbstractService() { 045 @Override protected final void doStart() { 046 Executor executor = MoreExecutors.renamingDecorator(executor(), new Supplier<String>() { 047 @Override public String get() { 048 return serviceName(); 049 } 050 }); 051 executor.execute(new Runnable() { 052 @Override 053 public void run() { 054 try { 055 startUp(); 056 notifyStarted(); 057 058 if (isRunning()) { 059 try { 060 AbstractExecutionThreadService.this.run(); 061 } catch (Throwable t) { 062 try { 063 shutDown(); 064 } catch (Exception ignored) { 065 logger.log(Level.WARNING, 066 "Error while attempting to shut down the service" 067 + " after failure.", ignored); 068 } 069 throw t; 070 } 071 } 072 073 shutDown(); 074 notifyStopped(); 075 } catch (Throwable t) { 076 notifyFailed(t); 077 throw Throwables.propagate(t); 078 } 079 } 080 }); 081 } 082 083 @Override protected void doStop() { 084 triggerShutdown(); 085 } 086 }; 087 088 /** 089 * Constructor for use by subclasses. 090 */ 091 protected AbstractExecutionThreadService() {} 092 093 /** 094 * Start the service. This method is invoked on the execution thread. 095 * 096 * <p>By default this method does nothing. 097 */ 098 protected void startUp() throws Exception {} 099 100 /** 101 * Run the service. This method is invoked on the execution thread. 102 * Implementations must respond to stop requests. You could poll for lifecycle 103 * changes in a work loop: 104 * <pre> 105 * public void run() { 106 * while ({@link #isRunning()}) { 107 * // perform a unit of work 108 * } 109 * } 110 * </pre> 111 * ...or you could respond to stop requests by implementing {@link 112 * #triggerShutdown()}, which should cause {@link #run()} to return. 113 */ 114 protected abstract void run() throws Exception; 115 116 /** 117 * Stop the service. This method is invoked on the execution thread. 118 * 119 * <p>By default this method does nothing. 120 */ 121 // TODO: consider supporting a TearDownTestCase-like API 122 protected void shutDown() throws Exception {} 123 124 /** 125 * Invoked to request the service to stop. 126 * 127 * <p>By default this method does nothing. 128 */ 129 protected void triggerShutdown() {} 130 131 /** 132 * Returns the {@link Executor} that will be used to run this service. 133 * Subclasses may override this method to use a custom {@link Executor}, which 134 * may configure its worker thread with a specific name, thread group or 135 * priority. The returned executor's {@link Executor#execute(Runnable) 136 * execute()} method is called when this service is started, and should return 137 * promptly. 138 * 139 * <p>The default implementation returns a new {@link Executor} that sets the 140 * name of its threads to the string returned by {@link #serviceName} 141 */ 142 protected Executor executor() { 143 return new Executor() { 144 @Override 145 public void execute(Runnable command) { 146 MoreExecutors.newThread(serviceName(), command).start(); 147 } 148 }; 149 } 150 151 @Override public String toString() { 152 return serviceName() + " [" + state() + "]"; 153 } 154 155 // We override instead of using ForwardingService so that these can be final. 156 157 @Deprecated 158 @Override 159 public final ListenableFuture<State> start() { 160 return delegate.start(); 161 } 162 163 @Deprecated 164 @Override 165 public final State startAndWait() { 166 return delegate.startAndWait(); 167 } 168 169 @Override public final boolean isRunning() { 170 return delegate.isRunning(); 171 } 172 173 @Override public final State state() { 174 return delegate.state(); 175 } 176 177 @Deprecated 178 @Override 179 public final ListenableFuture<State> stop() { 180 return delegate.stop(); 181 } 182 183 @Deprecated 184 @Override 185 public final State stopAndWait() { 186 return delegate.stopAndWait(); 187 } 188 189 /** 190 * @since 13.0 191 */ 192 @Override public final void addListener(Listener listener, Executor executor) { 193 delegate.addListener(listener, executor); 194 } 195 196 /** 197 * @since 14.0 198 */ 199 @Override public final Throwable failureCause() { 200 return delegate.failureCause(); 201 } 202 203 /** 204 * @since 15.0 205 */ 206 @Override public final Service startAsync() { 207 delegate.startAsync(); 208 return this; 209 } 210 211 /** 212 * @since 15.0 213 */ 214 @Override public final Service stopAsync() { 215 delegate.stopAsync(); 216 return this; 217 } 218 219 /** 220 * @since 15.0 221 */ 222 @Override public final void awaitRunning() { 223 delegate.awaitRunning(); 224 } 225 226 /** 227 * @since 15.0 228 */ 229 @Override public final void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException { 230 delegate.awaitRunning(timeout, unit); 231 } 232 233 /** 234 * @since 15.0 235 */ 236 @Override public final void awaitTerminated() { 237 delegate.awaitTerminated(); 238 } 239 240 /** 241 * @since 15.0 242 */ 243 @Override public final void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException { 244 delegate.awaitTerminated(timeout, unit); 245 } 246 247 /** 248 * Returns the name of this service. {@link AbstractExecutionThreadService} 249 * may include the name in debugging output. 250 * 251 * <p>Subclasses may override this method. 252 * 253 * @since 14.0 (present in 10.0 as getServiceName) 254 */ 255 protected String serviceName() { 256 return getClass().getSimpleName(); 257 } 258}