1/* 2 * Copyright (C) 2009 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.google.common.util.concurrent; 18 19import com.google.common.annotations.Beta; 20 21import java.util.concurrent.Executor; 22import java.util.concurrent.TimeUnit; 23import java.util.concurrent.TimeoutException; 24 25/** 26 * An object with an operational state, plus asynchronous {@link #startAsync()} and 27 * {@link #stopAsync()} lifecycle methods to transition between states. Example services include 28 * webservers, RPC servers and timers. 29 * 30 * <p>The normal lifecycle of a service is: 31 * <ul> 32 * <li>{@linkplain State#NEW NEW} -> 33 * <li>{@linkplain State#STARTING STARTING} -> 34 * <li>{@linkplain State#RUNNING RUNNING} -> 35 * <li>{@linkplain State#STOPPING STOPPING} -> 36 * <li>{@linkplain State#TERMINATED TERMINATED} 37 * </ul> 38 * 39 * <p>There are deviations from this if there are failures or if {@link Service#stopAsync} is called 40 * before the {@link Service} reaches the {@linkplain State#RUNNING RUNNING} state. The set of legal 41 * transitions form a <a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph">DAG</a>, 42 * therefore every method of the listener will be called at most once. N.B. The {@link State#FAILED} 43 * and {@link State#TERMINATED} states are terminal states, once a service enters either of these 44 * states it cannot ever leave them. 45 * 46 * <p>Implementors of this interface are strongly encouraged to extend one of the abstract classes 47 * in this package which implement this interface and make the threading and state management 48 * easier. 49 * 50 * @author Jesse Wilson 51 * @author Luke Sandberg 52 * @since 9.0 (in 1.0 as {@code com.google.common.base.Service}) 53 */ 54@Beta 55public interface Service { 56 /** 57 * If the service state is {@link State#NEW}, this initiates service startup and returns 58 * immediately. If the service has already been started, this method returns immediately without 59 * taking action. A stopped service may not be restarted. 60 * 61 * @deprecated Use {@link #startAsync()} instead of this method to start the {@link Service} or 62 * use a {@link Listener} to asynchronously wait for service startup. 63 * 64 * @return a future for the startup result, regardless of whether this call initiated startup. 65 * Calling {@link ListenableFuture#get} will block until the service has finished 66 * starting, and returns one of {@link State#RUNNING}, {@link State#STOPPING} or 67 * {@link State#TERMINATED}. If the service fails to start, {@link ListenableFuture#get} 68 * will throw an {@link ExecutionException}, and the service's state will be 69 * {@link State#FAILED}. If it has already finished starting, {@link ListenableFuture#get} 70 * returns immediately. Cancelling this future has no effect on the service. 71 */ 72 73 @Deprecated 74 ListenableFuture<State> start(); 75 76 /** 77 * Initiates service startup (if necessary), returning once the service has finished starting. 78 * Unlike calling {@code start().get()}, this method throws no checked exceptions, and it cannot 79 * be {@linkplain Thread#interrupt interrupted}. 80 * 81 * @deprecated Use {@link #startAsync()} and {@link #awaitRunning} instead of this method. 82 * 83 * @throws UncheckedExecutionException if startup failed 84 * @return the state of the service when startup finished. 85 */ 86 87 @Deprecated 88 State startAndWait(); 89 90 /** 91 * If the service state is {@link State#NEW}, this initiates service startup and returns 92 * immediately. A stopped service may not be restarted. 93 * 94 * @return this 95 * @throws IllegalStateException if the service is not {@link State#NEW} 96 * 97 * @since 15.0 98 */ 99 Service startAsync(); 100 101 /** 102 * Returns {@code true} if this service is {@linkplain State#RUNNING running}. 103 */ 104 boolean isRunning(); 105 106 /** 107 * Returns the lifecycle state of the service. 108 */ 109 State state(); 110 111 /** 112 * If the service is {@linkplain State#STARTING starting} or {@linkplain State#RUNNING running}, 113 * this initiates service shutdown and returns immediately. If the service is 114 * {@linkplain State#NEW new}, it is {@linkplain State#TERMINATED terminated} without having been 115 * started nor stopped. If the service has already been stopped, this method returns immediately 116 * without taking action. 117 * 118 * @deprecated Use {@link #stopAsync} instead of this method to initiate service shutdown or use a 119 * service {@link Listener} to asynchronously wait for service shutdown. 120 * 121 * @return a future for the shutdown result, regardless of whether this call initiated shutdown. 122 * Calling {@link ListenableFuture#get} will block until the service has finished shutting 123 * down, and either returns {@link State#TERMINATED} or throws an 124 * {@link ExecutionException}. If it has already finished stopping, 125 * {@link ListenableFuture#get} returns immediately. Cancelling this future has no effect 126 * on the service. 127 */ 128 129 @Deprecated 130 ListenableFuture<State> stop(); 131 132 /** 133 * Initiates service shutdown (if necessary), returning once the service has finished stopping. If 134 * this is {@link State#STARTING}, startup will be cancelled. If this is {@link State#NEW}, it is 135 * {@link State#TERMINATED terminated} without having been started nor stopped. Unlike calling 136 * {@code stop().get()}, this method throws no checked exceptions. 137 * 138 * @deprecated Use {@link #stopAsync} and {@link #awaitTerminated} instead of this method. 139 * 140 * @throws UncheckedExecutionException if the service has failed or fails during shutdown 141 * @return the state of the service when shutdown finished. 142 */ 143 144 @Deprecated 145 State stopAndWait(); 146 147 /** 148 * If the service is {@linkplain State#STARTING starting} or {@linkplain State#RUNNING running}, 149 * this initiates service shutdown and returns immediately. If the service is 150 * {@linkplain State#NEW new}, it is {@linkplain State#TERMINATED terminated} without having been 151 * started nor stopped. If the service has already been stopped, this method returns immediately 152 * without taking action. 153 * 154 * @return this 155 * @since 15.0 156 */ 157 Service stopAsync(); 158 159 /** 160 * Waits for the {@link Service} to reach the {@linkplain State#RUNNING running state}. 161 * 162 * @throws IllegalStateException if the service reaches a state from which it is not possible to 163 * enter the {@link State#RUNNING} state. e.g. if the {@code state} is 164 * {@code State#TERMINATED} when this method is called then this will throw an 165 * IllegalStateException. 166 * 167 * @since 15.0 168 */ 169 void awaitRunning(); 170 171 /** 172 * Waits for the {@link Service} to reach the {@linkplain State#RUNNING running state} for no 173 * more than the given time. 174 * 175 * @param timeout the maximum time to wait 176 * @param unit the time unit of the timeout argument 177 * @throws TimeoutException if the service has not reached the given state within the deadline 178 * @throws IllegalStateException if the service reaches a state from which it is not possible to 179 * enter the {@link State#RUNNING RUNNING} state. e.g. if the {@code state} is 180 * {@code State#TERMINATED} when this method is called then this will throw an 181 * IllegalStateException. 182 * 183 * @since 15.0 184 */ 185 void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException; 186 187 /** 188 * Waits for the {@link Service} to reach the {@linkplain State#TERMINATED terminated state}. 189 * 190 * @throws IllegalStateException if the service {@linkplain State#FAILED fails}. 191 * 192 * @since 15.0 193 */ 194 void awaitTerminated(); 195 196 /** 197 * Waits for the {@link Service} to reach a terminal state (either 198 * {@link Service.State#TERMINATED terminated} or {@link Service.State#FAILED failed}) for no 199 * more than the given time. 200 * 201 * @param timeout the maximum time to wait 202 * @param unit the time unit of the timeout argument 203 * @throws TimeoutException if the service has not reached the given state within the deadline 204 * @throws IllegalStateException if the service {@linkplain State#FAILED fails}. 205 * @since 15.0 206 */ 207 void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException; 208 209 /** 210 * Returns the {@link Throwable} that caused this service to fail. 211 * 212 * @throws IllegalStateException if this service's state isn't {@linkplain State#FAILED FAILED}. 213 * 214 * @since 14.0 215 */ 216 Throwable failureCause(); 217 218 /** 219 * Registers a {@link Listener} to be {@linkplain Executor#execute executed} on the given 220 * executor. The listener will have the corresponding transition method called whenever the 221 * service changes state. The listener will not have previous state changes replayed, so it is 222 * suggested that listeners are added before the service starts. 223 * 224 * <p>{@code addListener} guarantees execution ordering across calls to a given listener but not 225 * across calls to multiple listeners. Specifically, a given listener will have its callbacks 226 * invoked in the same order as the underlying service enters those states. Additionally, at most 227 * one of the listener's callbacks will execute at once. However, multiple listeners' callbacks 228 * may execute concurrently, and listeners may execute in an order different from the one in which 229 * they were registered. 230 * 231 * <p>RuntimeExceptions thrown by a listener will be caught and logged. Any exception thrown 232 * during {@code Executor.execute} (e.g., a {@code RejectedExecutionException}) will be caught and 233 * logged. 234 * 235 * @param listener the listener to run when the service changes state is complete 236 * @param executor the executor in which the listeners callback methods will be run. For fast, 237 * lightweight listeners that would be safe to execute in any thread, consider 238 * {@link MoreExecutors#sameThreadExecutor}. 239 * @since 13.0 240 */ 241 void addListener(Listener listener, Executor executor); 242 243 /** 244 * The lifecycle states of a service. 245 * 246 * <p>The ordering of the {@link State} enum is defined such that if there is a state transition 247 * from {@code A -> B} then {@code A.compareTo(B} < 0}. N.B. The converse is not true, i.e. if 248 * {@code A.compareTo(B} < 0} then there is <b>not</b> guaranteed to be a valid state transition 249 * {@code A -> B}. 250 * 251 * @since 9.0 (in 1.0 as {@code com.google.common.base.Service.State}) 252 */ 253 @Beta // should come out of Beta when Service does 254 enum State { 255 /** 256 * A service in this state is inactive. It does minimal work and consumes 257 * minimal resources. 258 */ 259 NEW { 260 @Override boolean isTerminal() { 261 return false; 262 } 263 }, 264 265 /** 266 * A service in this state is transitioning to {@link #RUNNING}. 267 */ 268 STARTING { 269 @Override boolean isTerminal() { 270 return false; 271 } 272 }, 273 274 /** 275 * A service in this state is operational. 276 */ 277 RUNNING { 278 @Override boolean isTerminal() { 279 return false; 280 } 281 }, 282 283 /** 284 * A service in this state is transitioning to {@link #TERMINATED}. 285 */ 286 STOPPING { 287 @Override boolean isTerminal() { 288 return false; 289 } 290 }, 291 292 /** 293 * A service in this state has completed execution normally. It does minimal work and consumes 294 * minimal resources. 295 */ 296 TERMINATED { 297 @Override boolean isTerminal() { 298 return true; 299 } 300 }, 301 302 /** 303 * A service in this state has encountered a problem and may not be operational. It cannot be 304 * started nor stopped. 305 */ 306 FAILED { 307 @Override boolean isTerminal() { 308 return true; 309 } 310 }; 311 312 /** Returns true if this state is terminal. */ 313 abstract boolean isTerminal(); 314 } 315 316 /** 317 * A listener for the various state changes that a {@link Service} goes through in its lifecycle. 318 * 319 * <p>All methods are no-ops by default, implementors should override the ones they care about. 320 * 321 * @author Luke Sandberg 322 * @since 15.0 (present as an interface in 13.0) 323 */ 324 @Beta // should come out of Beta when Service does 325 abstract class Listener { 326 /** 327 * Called when the service transitions from {@linkplain State#NEW NEW} to 328 * {@linkplain State#STARTING STARTING}. This occurs when {@link Service#startAsync} is called 329 * the first time. 330 */ 331 public void starting() {} 332 333 /** 334 * Called when the service transitions from {@linkplain State#STARTING STARTING} to 335 * {@linkplain State#RUNNING RUNNING}. This occurs when a service has successfully started. 336 */ 337 public void running() {} 338 339 /** 340 * Called when the service transitions to the {@linkplain State#STOPPING STOPPING} state. The 341 * only valid values for {@code from} are {@linkplain State#STARTING STARTING} or 342 * {@linkplain State#RUNNING RUNNING}. This occurs when {@link Service#stopAsync} is called. 343 * 344 * @param from The previous state that is being transitioned from. 345 */ 346 public void stopping(State from) {} 347 348 /** 349 * Called when the service transitions to the {@linkplain State#TERMINATED TERMINATED} state. 350 * The {@linkplain State#TERMINATED TERMINATED} state is a terminal state in the transition 351 * diagram. Therefore, if this method is called, no other methods will be called on the 352 * {@link Listener}. 353 * 354 * @param from The previous state that is being transitioned from. The only valid values for 355 * this are {@linkplain State#NEW NEW}, {@linkplain State#RUNNING RUNNING} or 356 * {@linkplain State#STOPPING STOPPING}. 357 */ 358 public void terminated(State from) {} 359 360 /** 361 * Called when the service transitions to the {@linkplain State#FAILED FAILED} state. The 362 * {@linkplain State#FAILED FAILED} state is a terminal state in the transition diagram. 363 * Therefore, if this method is called, no other methods will be called on the {@link Listener}. 364 * 365 * @param from The previous state that is being transitioned from. Failure can occur in any 366 * state with the exception of {@linkplain State#NEW NEW} or 367 * {@linkplain State#TERMINATED TERMINATED}. 368 * @param failure The exception that caused the failure. 369 */ 370 public void failed(State from, Throwable failure) {} 371 } 372} 373