Home | History | Annotate | Download | only in concurrent
      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} -&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
     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    */
     65   Service startAsync();
     66 
     67   /**
     68    * Returns {@code true} if this service is {@linkplain State#RUNNING running}.
     69    */
     70   boolean isRunning();
     71 
     72   /**
     73    * Returns the lifecycle state of the service.
     74    */
     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    */
     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    */
     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    */
    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    */
    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    */
    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    */
    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    */
    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 {
    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 {
    199       @Override boolean isTerminal() {
    200         return false;
    201       }
    202     },
    203 
    204     /**
    205      * A service in this state is operational.
    206      */
    207     RUNNING {
    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 {
    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 {
    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 {
    237       @Override boolean isTerminal() {
    238         return true;
    239       }
    240     };
    241 
    242     /** Returns true if this state is terminal. */
    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      */
    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      */
    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      */
    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      */
    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      */
    300     public void failed(State from, Throwable failure) {}
    301   }
    302 }
    303