001/* 002 * Copyright (C) 2009 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.util.concurrent; 016 017import static com.google.common.util.concurrent.Platform.restoreInterruptIfIsInterruptedException; 018 019import com.google.common.annotations.GwtIncompatible; 020import com.google.common.annotations.J2ktIncompatible; 021import com.google.errorprone.annotations.CanIgnoreReturnValue; 022import java.util.concurrent.Executor; 023import java.util.concurrent.TimeUnit; 024import java.util.concurrent.TimeoutException; 025 026/** 027 * Base class for services that can implement {@link #startUp}, {@link #run} and {@link #shutDown} 028 * methods. This class uses a single thread to execute the service; consider {@link AbstractService} 029 * if you would like to manage any threading manually. 030 * 031 * @author Jesse Wilson 032 * @since 1.0 033 */ 034@GwtIncompatible 035@J2ktIncompatible 036public abstract class AbstractExecutionThreadService implements Service { 037 /* use AbstractService for state management */ 038 private final Service delegate = 039 new AbstractService() { 040 @Override 041 protected final void doStart() { 042 Executor executor = MoreExecutors.renamingDecorator(executor(), () -> serviceName()); 043 executor.execute( 044 () -> { 045 try { 046 startUp(); 047 notifyStarted(); 048 // If stopAsync() is called while starting we may be in the STOPPING state in 049 // which case we should skip right down to shutdown. 050 if (isRunning()) { 051 try { 052 AbstractExecutionThreadService.this.run(); 053 } catch (Throwable t) { 054 restoreInterruptIfIsInterruptedException(t); 055 try { 056 shutDown(); 057 } catch (Exception ignored) { 058 restoreInterruptIfIsInterruptedException(ignored); 059 t.addSuppressed(ignored); 060 } 061 notifyFailed(t); 062 return; 063 } 064 } 065 066 shutDown(); 067 notifyStopped(); 068 } catch (Throwable t) { 069 restoreInterruptIfIsInterruptedException(t); 070 notifyFailed(t); 071 } 072 }); 073 } 074 075 @Override 076 protected void doStop() { 077 triggerShutdown(); 078 } 079 080 @Override 081 public String toString() { 082 return AbstractExecutionThreadService.this.toString(); 083 } 084 }; 085 086 /** Constructor for use by subclasses. */ 087 protected AbstractExecutionThreadService() {} 088 089 /** 090 * Start the service. This method is invoked on the execution thread. 091 * 092 * <p>By default this method does nothing. 093 */ 094 protected void startUp() throws Exception {} 095 096 /** 097 * Run the service. This method is invoked on the execution thread. Implementations must respond 098 * to stop requests. You could poll for lifecycle changes in a work loop: 099 * 100 * <pre> 101 * public void run() { 102 * while ({@link #isRunning()}) { 103 * // perform a unit of work 104 * } 105 * } 106 * </pre> 107 * 108 * <p>...or you could respond to stop requests by implementing {@link #triggerShutdown()}, which 109 * should cause {@link #run()} to return. 110 */ 111 protected abstract void run() throws Exception; 112 113 /** 114 * Stop the service. This method is invoked on the execution thread. 115 * 116 * <p>By default this method does nothing. 117 */ 118 // TODO: consider supporting a TearDownTestCase-like API 119 protected void shutDown() throws Exception {} 120 121 /** 122 * Invoked to request the service to stop. 123 * 124 * <p>By default this method does nothing. 125 * 126 * <p>Currently, this method is invoked while holding a lock. If an implementation of this method 127 * blocks, it can prevent this service from changing state. If you need to performing a blocking 128 * operation in order to trigger shutdown, consider instead registering a listener and 129 * implementing {@code stopping}. Note, however, that {@code stopping} does not run at exactly the 130 * same times as {@code triggerShutdown}. 131 */ 132 protected void triggerShutdown() {} 133 134 /** 135 * Returns the {@link Executor} that will be used to run this service. Subclasses may override 136 * this method to use a custom {@link Executor}, which may configure its worker thread with a 137 * specific name, thread group or priority. The returned executor's {@link 138 * Executor#execute(Runnable) execute()} method is called when this service is started, and should 139 * return promptly. 140 * 141 * <p>The default implementation returns a new {@link Executor} that sets the name of its threads 142 * to the string returned by {@link #serviceName} 143 */ 144 protected Executor executor() { 145 return command -> MoreExecutors.newThread(serviceName(), command).start(); 146 } 147 148 @Override 149 public String toString() { 150 return serviceName() + " [" + state() + "]"; 151 } 152 153 @Override 154 public final boolean isRunning() { 155 return delegate.isRunning(); 156 } 157 158 @Override 159 public final State state() { 160 return delegate.state(); 161 } 162 163 /** 164 * @since 13.0 165 */ 166 @Override 167 public final void addListener(Listener listener, Executor executor) { 168 delegate.addListener(listener, executor); 169 } 170 171 /** 172 * @since 14.0 173 */ 174 @Override 175 public final Throwable failureCause() { 176 return delegate.failureCause(); 177 } 178 179 /** 180 * @since 15.0 181 */ 182 @CanIgnoreReturnValue 183 @Override 184 public final Service startAsync() { 185 delegate.startAsync(); 186 return this; 187 } 188 189 /** 190 * @since 15.0 191 */ 192 @CanIgnoreReturnValue 193 @Override 194 public final Service stopAsync() { 195 delegate.stopAsync(); 196 return this; 197 } 198 199 /** 200 * @since 15.0 201 */ 202 @Override 203 public final void awaitRunning() { 204 delegate.awaitRunning(); 205 } 206 207 /** 208 * @since 15.0 209 */ 210 @Override 211 public final void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException { 212 delegate.awaitRunning(timeout, unit); 213 } 214 215 /** 216 * @since 15.0 217 */ 218 @Override 219 public final void awaitTerminated() { 220 delegate.awaitTerminated(); 221 } 222 223 /** 224 * @since 15.0 225 */ 226 @Override 227 public final void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException { 228 delegate.awaitTerminated(timeout, unit); 229 } 230 231 /** 232 * Returns the name of this service. {@link AbstractExecutionThreadService} may include the name 233 * in debugging output. 234 * 235 * <p>Subclasses may override this method. 236 * 237 * @since 14.0 (present in 10.0 as getServiceName) 238 */ 239 protected String serviceName() { 240 return getClass().getSimpleName(); 241 } 242}