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 }