Coverage Summary for Class: AbstractExecutionThreadService (com.google.common.util.concurrent)

Class Method, % Line, %
AbstractExecutionThreadService 0% (0/18) 0% (0/20)
AbstractExecutionThreadService$1 0% (0/4) 0% (0/7)
AbstractExecutionThreadService$1$1 0% (0/2) 0% (0/2)
AbstractExecutionThreadService$1$2 0% (0/2) 0% (0/17)
AbstractExecutionThreadService$2 0% (0/2) 0% (0/2)
Total 0% (0/28) 0% (0/48)


1 /* 2  * Copyright (C) 2009 The Guava Authors 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5  * in compliance with the License. You may obtain a copy of the License at 6  * 7  * http://www.apache.org/licenses/LICENSE-2.0 8  * 9  * Unless required by applicable law or agreed to in writing, software distributed under the License 10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11  * or implied. See the License for the specific language governing permissions and limitations under 12  * the License. 13  */ 14  15 package com.google.common.util.concurrent; 16  17 import com.google.common.annotations.Beta; 18 import com.google.common.annotations.GwtIncompatible; 19 import com.google.common.base.Supplier; 20 import com.google.errorprone.annotations.CanIgnoreReturnValue; 21 import java.time.Duration; 22 import java.util.concurrent.Executor; 23 import java.util.concurrent.TimeUnit; 24 import java.util.concurrent.TimeoutException; 25 import java.util.logging.Level; 26 import java.util.logging.Logger; 27  28 /** 29  * Base class for services that can implement {@link #startUp}, {@link #run} and {@link #shutDown} 30  * methods. This class uses a single thread to execute the service; consider {@link AbstractService} 31  * if you would like to manage any threading manually. 32  * 33  * @author Jesse Wilson 34  * @since 1.0 35  */ 36 @GwtIncompatible 37 @ElementTypesAreNonnullByDefault 38 public abstract class AbstractExecutionThreadService implements Service { 39  private static final Logger logger = 40  Logger.getLogger(AbstractExecutionThreadService.class.getName()); 41  42  /* use AbstractService for state management */ 43  private final Service delegate = 44  new AbstractService() { 45  @Override 46  protected final void doStart() { 47  Executor executor = 48  MoreExecutors.renamingDecorator( 49  executor(), 50  new Supplier<String>() { 51  @Override 52  public String get() { 53  return serviceName(); 54  } 55  }); 56  executor.execute( 57  new Runnable() { 58  @Override 59  public void run() { 60  try { 61  startUp(); 62  notifyStarted(); 63  // If stopAsync() is called while starting we may be in the STOPPING state in 64  // which case we should skip right down to shutdown. 65  if (isRunning()) { 66  try { 67  AbstractExecutionThreadService.this.run(); 68  } catch (Throwable t) { 69  try { 70  shutDown(); 71  } catch (Exception ignored) { 72  // TODO(lukes): if guava ever moves to java7, this would be a good 73  // candidate for a suppressed exception, or maybe we could generalize 74  // Closer.Suppressor 75  logger.log( 76  Level.WARNING, 77  "Error while attempting to shut down the service after failure.", 78  ignored); 79  } 80  notifyFailed(t); 81  return; 82  } 83  } 84  85  shutDown(); 86  notifyStopped(); 87  } catch (Throwable t) { 88  notifyFailed(t); 89  } 90  } 91  }); 92  } 93  94  @Override 95  protected void doStop() { 96  triggerShutdown(); 97  } 98  99  @Override 100  public String toString() { 101  return AbstractExecutionThreadService.this.toString(); 102  } 103  }; 104  105  /** Constructor for use by subclasses. */ 106  protected AbstractExecutionThreadService() {} 107  108  /** 109  * Start the service. This method is invoked on the execution thread. 110  * 111  * <p>By default this method does nothing. 112  */ 113  protected void startUp() throws Exception {} 114  115  /** 116  * Run the service. This method is invoked on the execution thread. Implementations must respond 117  * to stop requests. You could poll for lifecycle changes in a work loop: 118  * 119  * <pre> 120  * public void run() { 121  * while ({@link #isRunning()}) { 122  * // perform a unit of work 123  * } 124  * } 125  * </pre> 126  * 127  * <p>...or you could respond to stop requests by implementing {@link #triggerShutdown()}, which 128  * should cause {@link #run()} to return. 129  */ 130  protected abstract void run() throws Exception; 131  132  /** 133  * Stop the service. This method is invoked on the execution thread. 134  * 135  * <p>By default this method does nothing. 136  */ 137  // TODO: consider supporting a TearDownTestCase-like API 138  protected void shutDown() throws Exception {} 139  140  /** 141  * Invoked to request the service to stop. 142  * 143  * <p>By default this method does nothing. 144  * 145  * <p>Currently, this method is invoked while holding a lock. If an implementation of this method 146  * blocks, it can prevent this service from changing state. If you need to performing a blocking 147  * operation in order to trigger shutdown, consider instead registering a listener and 148  * implementing {@code stopping}. Note, however, that {@code stopping} does not run at exactly the 149  * same times as {@code triggerShutdown}. 150  */ 151  @Beta 152  protected void triggerShutdown() {} 153  154  /** 155  * Returns the {@link Executor} that will be used to run this service. Subclasses may override 156  * this method to use a custom {@link Executor}, which may configure its worker thread with a 157  * specific name, thread group or priority. The returned executor's {@link 158  * Executor#execute(Runnable) execute()} method is called when this service is started, and should 159  * return promptly. 160  * 161  * <p>The default implementation returns a new {@link Executor} that sets the name of its threads 162  * to the string returned by {@link #serviceName} 163  */ 164  protected Executor executor() { 165  return new Executor() { 166  @Override 167  public void execute(Runnable command) { 168  MoreExecutors.newThread(serviceName(), command).start(); 169  } 170  }; 171  } 172  173  @Override 174  public String toString() { 175  return serviceName() + " [" + state() + "]"; 176  } 177  178  @Override 179  public final boolean isRunning() { 180  return delegate.isRunning(); 181  } 182  183  @Override 184  public final State state() { 185  return delegate.state(); 186  } 187  188  /** @since 13.0 */ 189  @Override 190  public final void addListener(Listener listener, Executor executor) { 191  delegate.addListener(listener, executor); 192  } 193  194  /** @since 14.0 */ 195  @Override 196  public final Throwable failureCause() { 197  return delegate.failureCause(); 198  } 199  200  /** @since 15.0 */ 201  @CanIgnoreReturnValue 202  @Override 203  public final Service startAsync() { 204  delegate.startAsync(); 205  return this; 206  } 207  208  /** @since 15.0 */ 209  @CanIgnoreReturnValue 210  @Override 211  public final Service stopAsync() { 212  delegate.stopAsync(); 213  return this; 214  } 215  216  /** @since 15.0 */ 217  @Override 218  public final void awaitRunning() { 219  delegate.awaitRunning(); 220  } 221  222  /** @since 28.0 */ 223  @Override 224  public final void awaitRunning(Duration timeout) throws TimeoutException { 225  Service.super.awaitRunning(timeout); 226  } 227  228  /** @since 15.0 */ 229  @Override 230  public final void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException { 231  delegate.awaitRunning(timeout, unit); 232  } 233  234  /** @since 15.0 */ 235  @Override 236  public final void awaitTerminated() { 237  delegate.awaitTerminated(); 238  } 239  240  /** @since 28.0 */ 241  @Override 242  public final void awaitTerminated(Duration timeout) throws TimeoutException { 243  Service.super.awaitTerminated(timeout); 244  } 245  246  /** @since 15.0 */ 247  @Override 248  public final void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException { 249  delegate.awaitTerminated(timeout, unit); 250  } 251  252  /** 253  * Returns the name of this service. {@link AbstractExecutionThreadService} may include the name 254  * in debugging output. 255  * 256  * <p>Subclasses may override this method. 257  * 258  * @since 14.0 (present in 10.0 as getServiceName) 259  */ 260  protected String serviceName() { 261  return getClass().getSimpleName(); 262  } 263 }