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 import com.google.common.base.Supplier;
     21 import com.google.common.base.Throwables;
     22 
     23 import java.util.concurrent.Executor;
     24 import java.util.concurrent.TimeUnit;
     25 import java.util.concurrent.TimeoutException;
     26 
     27 /**
     28  * Base class for services that do not need a thread while "running"
     29  * but may need one during startup and shutdown. Subclasses can
     30  * implement {@link #startUp} and {@link #shutDown} methods, each
     31  * which run in a executor which by default uses a separate thread
     32  * for each method.
     33  *
     34  * @author Chris Nokleberg
     35  * @since 1.0
     36  */
     37 @Beta
     38 public abstract class AbstractIdleService implements Service {
     39 
     40   /* Thread names will look like {@code "MyService STARTING"}. */
     41   private final Supplier<String> threadNameSupplier = new Supplier<String>() {
     42     @Override public String get() {
     43       return serviceName() + " " + state();
     44     }
     45   };
     46 
     47   /* use AbstractService for state management */
     48   private final Service delegate = new AbstractService() {
     49     @Override protected final void doStart() {
     50       MoreExecutors.renamingDecorator(executor(), threadNameSupplier)
     51           .execute(new Runnable() {
     52             @Override public void run() {
     53               try {
     54                 startUp();
     55                 notifyStarted();
     56               } catch (Throwable t) {
     57                 notifyFailed(t);
     58                 throw Throwables.propagate(t);
     59               }
     60             }
     61           });
     62     }
     63 
     64     @Override protected final void doStop() {
     65       MoreExecutors.renamingDecorator(executor(), threadNameSupplier)
     66           .execute(new Runnable() {
     67             @Override public void run() {
     68               try {
     69                 shutDown();
     70                 notifyStopped();
     71               } catch (Throwable t) {
     72                 notifyFailed(t);
     73                 throw Throwables.propagate(t);
     74               }
     75             }
     76           });
     77     }
     78   };
     79 
     80   /** Constructor for use by subclasses. */
     81   protected AbstractIdleService() {}
     82 
     83   /** Start the service. */
     84   protected abstract void startUp() throws Exception;
     85 
     86   /** Stop the service. */
     87   protected abstract void shutDown() throws Exception;
     88 
     89   /**
     90    * Returns the {@link Executor} that will be used to run this service.
     91    * Subclasses may override this method to use a custom {@link Executor}, which
     92    * may configure its worker thread with a specific name, thread group or
     93    * priority. The returned executor's {@link Executor#execute(Runnable)
     94    * execute()} method is called when this service is started and stopped,
     95    * and should return promptly.
     96    */
     97   protected Executor executor() {
     98     return new Executor() {
     99       @Override public void execute(Runnable command) {
    100         MoreExecutors.newThread(threadNameSupplier.get(), command).start();
    101       }
    102     };
    103   }
    104 
    105   @Override public String toString() {
    106     return serviceName() + " [" + state() + "]";
    107   }
    108 
    109   @Override public final boolean isRunning() {
    110     return delegate.isRunning();
    111   }
    112 
    113   @Override public final State state() {
    114     return delegate.state();
    115   }
    116 
    117   /**
    118    * @since 13.0
    119    */
    120   @Override public final void addListener(Listener listener, Executor executor) {
    121     delegate.addListener(listener, executor);
    122   }
    123 
    124   /**
    125    * @since 14.0
    126    */
    127   @Override public final Throwable failureCause() {
    128     return delegate.failureCause();
    129   }
    130 
    131   /**
    132    * @since 15.0
    133    */
    134   @Override public final Service startAsync() {
    135     delegate.startAsync();
    136     return this;
    137   }
    138 
    139   /**
    140    * @since 15.0
    141    */
    142   @Override public final Service stopAsync() {
    143     delegate.stopAsync();
    144     return this;
    145   }
    146 
    147   /**
    148    * @since 15.0
    149    */
    150   @Override public final void awaitRunning() {
    151     delegate.awaitRunning();
    152   }
    153 
    154   /**
    155    * @since 15.0
    156    */
    157   @Override public final void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException {
    158     delegate.awaitRunning(timeout, unit);
    159   }
    160 
    161   /**
    162    * @since 15.0
    163    */
    164   @Override public final void awaitTerminated() {
    165     delegate.awaitTerminated();
    166   }
    167 
    168   /**
    169    * @since 15.0
    170    */
    171   @Override public final void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException {
    172     delegate.awaitTerminated(timeout, unit);
    173   }
    174 
    175   /**
    176    * Returns the name of this service. {@link AbstractIdleService} may include the name in debugging
    177    * output.
    178    *
    179    * @since 14.0
    180    */
    181   protected String serviceName() {
    182     return getClass().getSimpleName();
    183   }
    184 }
    185