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} -&gt;
33 *   <li>{@linkplain State#STARTING STARTING} -&gt;
34 *   <li>{@linkplain State#RUNNING RUNNING} -&gt;
35 *   <li>{@linkplain State#STOPPING STOPPING} -&gt;
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