Home | History | Annotate | Download | only in concurrent
      1 /*
      2  * Copyright (C) 2009 Google Inc.
      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.base.Service;
     20 import com.google.common.base.Throwables;
     21 
     22 import java.util.concurrent.Executor;
     23 import java.util.concurrent.Future;
     24 
     25 /**
     26  * Base class for services that can implement {@link #startUp}, {@link #run} and
     27  * {@link #shutDown} methods. This class uses a single thread to execute the
     28  * service; consider {@link AbstractService} if you would like to manage any
     29  * threading manually.
     30  *
     31  * @author Jesse Wilson
     32  * @since 2009.09.15 <b>tentative</b>
     33  */
     34 public abstract class AbstractExecutionThreadService implements Service {
     35 
     36   /* use AbstractService for state management */
     37   private final Service delegate = new AbstractService() {
     38     @Override protected final void doStart() {
     39       executor().execute(new Runnable() {
     40         public void run() {
     41           try {
     42             startUp();
     43             notifyStarted();
     44 
     45             if (isRunning()) {
     46               try {
     47                 AbstractExecutionThreadService.this.run();
     48               } catch (Throwable t) {
     49                 try {
     50                   shutDown();
     51                 } catch (Exception ignored) {}
     52                 throw t;
     53               }
     54             }
     55 
     56             shutDown();
     57             notifyStopped();
     58           } catch (Throwable t) {
     59             notifyFailed(t);
     60             throw Throwables.propagate(t);
     61           }
     62         }
     63       });
     64     }
     65 
     66     @Override protected void doStop() {
     67       triggerShutdown();
     68     }
     69   };
     70 
     71   /**
     72    * Start the service. This method is invoked on the execution thread.
     73    */
     74   protected void startUp() throws Exception {}
     75 
     76   /**
     77    * Run the service. This method is invoked on the execution thread.
     78    * Implementations must respond to stop requests. You could poll for lifecycle
     79    * changes in a work loop:
     80    * <pre>
     81    *   public void run() {
     82    *     while ({@link #isRunning()}) {
     83    *       // perform a unit of work
     84    *     }
     85    *   }
     86    * </pre>
     87    * ...or you could respond to stop requests by implementing {@link
     88    * #triggerShutdown()}, which should cause {@link #run()} to return.
     89    */
     90   protected abstract void run() throws Exception;
     91 
     92   /**
     93    * Stop the service. This method is invoked on the execution thread.
     94    */
     95   // TODO: consider supporting a TearDownTestCase-like API
     96   protected void shutDown() throws Exception {}
     97 
     98   /**
     99    * Invoked to request the service to stop.
    100    */
    101   protected void triggerShutdown() {}
    102 
    103   /**
    104    * Returns the {@link Executor} that will be used to run this service.
    105    * Subclasses may override this method to use a custom {@link Executor}, which
    106    * may configure its worker thread with a specific name, thread group or
    107    * priority. The returned executor's {@link Executor#execute(Runnable)
    108    * execute()} method is called when this service is started, and should return
    109    * promptly.
    110    */
    111   protected Executor executor() {
    112     return new Executor() {
    113       public void execute(Runnable command) {
    114         new Thread(command, AbstractExecutionThreadService.this.toString())
    115             .start();
    116       }
    117     };
    118   }
    119 
    120   @Override public String toString() {
    121     return getClass().getSimpleName();
    122   }
    123 
    124   // We override instead of using ForwardingService so that these can be final.
    125 
    126   /*@Override*/ public final Future<State> start() {
    127     return delegate.start();
    128   }
    129 
    130   /*@Override*/ public final State startAndWait() {
    131     return delegate.startAndWait();
    132   }
    133 
    134   /*@Override*/ public final boolean isRunning() {
    135     return delegate.isRunning();
    136   }
    137 
    138   /*@Override*/ public final State state() {
    139     return delegate.state();
    140   }
    141 
    142   /*@Override*/ public final Future<State> stop() {
    143     return delegate.stop();
    144   }
    145 
    146   /*@Override*/ public final State stopAndWait() {
    147     return delegate.stopAndWait();
    148   }
    149 }
    150