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 17 package com.google.common.util.concurrent; 18 19 import com.google.common.annotations.Beta; 20 21 import java.util.concurrent.Executor; 22 import java.util.concurrent.TimeUnit; 23 import 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 55 public interface Service { 56 /** 57 * If the service state is {@link State#NEW}, this initiates service startup and returns 58 * immediately. A stopped service may not be restarted. 59 * 60 * @return this 61 * @throws IllegalStateException if the service is not {@link State#NEW} 62 * 63 * @since 15.0 64 */ startAsync()65 Service startAsync(); 66 67 /** 68 * Returns {@code true} if this service is {@linkplain State#RUNNING running}. 69 */ isRunning()70 boolean isRunning(); 71 72 /** 73 * Returns the lifecycle state of the service. 74 */ state()75 State state(); 76 77 /** 78 * If the service is {@linkplain State#STARTING starting} or {@linkplain State#RUNNING running}, 79 * this initiates service shutdown and returns immediately. If the service is 80 * {@linkplain State#NEW new}, it is {@linkplain State#TERMINATED terminated} without having been 81 * started nor stopped. If the service has already been stopped, this method returns immediately 82 * without taking action. 83 * 84 * @return this 85 * @since 15.0 86 */ stopAsync()87 Service stopAsync(); 88 89 /** 90 * Waits for the {@link Service} to reach the {@linkplain State#RUNNING running state}. 91 * 92 * @throws IllegalStateException if the service reaches a state from which it is not possible to 93 * enter the {@link State#RUNNING} state. e.g. if the {@code state} is 94 * {@code State#TERMINATED} when this method is called then this will throw an 95 * IllegalStateException. 96 * 97 * @since 15.0 98 */ awaitRunning()99 void awaitRunning(); 100 101 /** 102 * Waits for the {@link Service} to reach the {@linkplain State#RUNNING running state} for no 103 * more than the given time. 104 * 105 * @param timeout the maximum time to wait 106 * @param unit the time unit of the timeout argument 107 * @throws TimeoutException if the service has not reached the given state within the deadline 108 * @throws IllegalStateException if the service reaches a state from which it is not possible to 109 * enter the {@link State#RUNNING RUNNING} state. e.g. if the {@code state} is 110 * {@code State#TERMINATED} when this method is called then this will throw an 111 * IllegalStateException. 112 * 113 * @since 15.0 114 */ awaitRunning(long timeout, TimeUnit unit)115 void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException; 116 117 /** 118 * Waits for the {@link Service} to reach the {@linkplain State#TERMINATED terminated state}. 119 * 120 * @throws IllegalStateException if the service {@linkplain State#FAILED fails}. 121 * 122 * @since 15.0 123 */ awaitTerminated()124 void awaitTerminated(); 125 126 /** 127 * Waits for the {@link Service} to reach a terminal state (either 128 * {@link Service.State#TERMINATED terminated} or {@link Service.State#FAILED failed}) for no 129 * more than the given time. 130 * 131 * @param timeout the maximum time to wait 132 * @param unit the time unit of the timeout argument 133 * @throws TimeoutException if the service has not reached the given state within the deadline 134 * @throws IllegalStateException if the service {@linkplain State#FAILED fails}. 135 * @since 15.0 136 */ awaitTerminated(long timeout, TimeUnit unit)137 void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException; 138 139 /** 140 * Returns the {@link Throwable} that caused this service to fail. 141 * 142 * @throws IllegalStateException if this service's state isn't {@linkplain State#FAILED FAILED}. 143 * 144 * @since 14.0 145 */ failureCause()146 Throwable failureCause(); 147 148 /** 149 * Registers a {@link Listener} to be {@linkplain Executor#execute executed} on the given 150 * executor. The listener will have the corresponding transition method called whenever the 151 * service changes state. The listener will not have previous state changes replayed, so it is 152 * suggested that listeners are added before the service starts. 153 * 154 * <p>{@code addListener} guarantees execution ordering across calls to a given listener but not 155 * across calls to multiple listeners. Specifically, a given listener will have its callbacks 156 * invoked in the same order as the underlying service enters those states. Additionally, at most 157 * one of the listener's callbacks will execute at once. However, multiple listeners' callbacks 158 * may execute concurrently, and listeners may execute in an order different from the one in which 159 * they were registered. 160 * 161 * <p>RuntimeExceptions thrown by a listener will be caught and logged. Any exception thrown 162 * during {@code Executor.execute} (e.g., a {@code RejectedExecutionException}) will be caught and 163 * logged. 164 * 165 * @param listener the listener to run when the service changes state is complete 166 * @param executor the executor in which the listeners callback methods will be run. For fast, 167 * lightweight listeners that would be safe to execute in any thread, consider 168 * {@link MoreExecutors#directExecutor}. 169 * @since 13.0 170 */ addListener(Listener listener, Executor executor)171 void addListener(Listener listener, Executor executor); 172 173 /** 174 * The lifecycle states of a service. 175 * 176 * <p>The ordering of the {@link State} enum is defined such that if there is a state transition 177 * from {@code A -> B} then {@code A.compareTo(B} < 0}. N.B. The converse is not true, i.e. if 178 * {@code A.compareTo(B} < 0} then there is <b>not</b> guaranteed to be a valid state transition 179 * {@code A -> B}. 180 * 181 * @since 9.0 (in 1.0 as {@code com.google.common.base.Service.State}) 182 */ 183 @Beta // should come out of Beta when Service does 184 enum State { 185 /** 186 * A service in this state is inactive. It does minimal work and consumes 187 * minimal resources. 188 */ 189 NEW { isTerminal()190 @Override boolean isTerminal() { 191 return false; 192 } 193 }, 194 195 /** 196 * A service in this state is transitioning to {@link #RUNNING}. 197 */ 198 STARTING { isTerminal()199 @Override boolean isTerminal() { 200 return false; 201 } 202 }, 203 204 /** 205 * A service in this state is operational. 206 */ 207 RUNNING { isTerminal()208 @Override boolean isTerminal() { 209 return false; 210 } 211 }, 212 213 /** 214 * A service in this state is transitioning to {@link #TERMINATED}. 215 */ 216 STOPPING { isTerminal()217 @Override boolean isTerminal() { 218 return false; 219 } 220 }, 221 222 /** 223 * A service in this state has completed execution normally. It does minimal work and consumes 224 * minimal resources. 225 */ 226 TERMINATED { isTerminal()227 @Override boolean isTerminal() { 228 return true; 229 } 230 }, 231 232 /** 233 * A service in this state has encountered a problem and may not be operational. It cannot be 234 * started nor stopped. 235 */ 236 FAILED { isTerminal()237 @Override boolean isTerminal() { 238 return true; 239 } 240 }; 241 242 /** Returns true if this state is terminal. */ isTerminal()243 abstract boolean isTerminal(); 244 } 245 246 /** 247 * A listener for the various state changes that a {@link Service} goes through in its lifecycle. 248 * 249 * <p>All methods are no-ops by default, implementors should override the ones they care about. 250 * 251 * @author Luke Sandberg 252 * @since 15.0 (present as an interface in 13.0) 253 */ 254 @Beta // should come out of Beta when Service does 255 abstract class Listener { 256 /** 257 * Called when the service transitions from {@linkplain State#NEW NEW} to 258 * {@linkplain State#STARTING STARTING}. This occurs when {@link Service#startAsync} is called 259 * the first time. 260 */ starting()261 public void starting() {} 262 263 /** 264 * Called when the service transitions from {@linkplain State#STARTING STARTING} to 265 * {@linkplain State#RUNNING RUNNING}. This occurs when a service has successfully started. 266 */ running()267 public void running() {} 268 269 /** 270 * Called when the service transitions to the {@linkplain State#STOPPING STOPPING} state. The 271 * only valid values for {@code from} are {@linkplain State#STARTING STARTING} or 272 * {@linkplain State#RUNNING RUNNING}. This occurs when {@link Service#stopAsync} is called. 273 * 274 * @param from The previous state that is being transitioned from. 275 */ stopping(State from)276 public void stopping(State from) {} 277 278 /** 279 * Called when the service transitions to the {@linkplain State#TERMINATED TERMINATED} state. 280 * The {@linkplain State#TERMINATED TERMINATED} state is a terminal state in the transition 281 * diagram. Therefore, if this method is called, no other methods will be called on the 282 * {@link Listener}. 283 * 284 * @param from The previous state that is being transitioned from. The only valid values for 285 * this are {@linkplain State#NEW NEW}, {@linkplain State#RUNNING RUNNING} or 286 * {@linkplain State#STOPPING STOPPING}. 287 */ terminated(State from)288 public void terminated(State from) {} 289 290 /** 291 * Called when the service transitions to the {@linkplain State#FAILED FAILED} state. The 292 * {@linkplain State#FAILED FAILED} state is a terminal state in the transition diagram. 293 * Therefore, if this method is called, no other methods will be called on the {@link Listener}. 294 * 295 * @param from The previous state that is being transitioned from. Failure can occur in any 296 * state with the exception of {@linkplain State#NEW NEW} or 297 * {@linkplain State#TERMINATED TERMINATED}. 298 * @param failure The exception that caused the failure. 299 */ failed(State from, Throwable failure)300 public void failed(State from, Throwable failure) {} 301 } 302 } 303