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 /** @since 13.0 */ 164 @Override 165 public final void addListener(Listener listener, Executor executor) { 166 delegate.addListener(listener, executor); 167 } 168 169 /** @since 14.0 */ 170 @Override 171 public final Throwable failureCause() { 172 return delegate.failureCause(); 173 } 174 175 /** @since 15.0 */ 176 @CanIgnoreReturnValue 177 @Override 178 public final Service startAsync() { 179 delegate.startAsync(); 180 return this; 181 } 182 183 /** @since 15.0 */ 184 @CanIgnoreReturnValue 185 @Override 186 public final Service stopAsync() { 187 delegate.stopAsync(); 188 return this; 189 } 190 191 /** @since 15.0 */ 192 @Override 193 public final void awaitRunning() { 194 delegate.awaitRunning(); 195 } 196 197 /** @since 15.0 */ 198 @Override 199 public final void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException { 200 delegate.awaitRunning(timeout, unit); 201 } 202 203 /** @since 15.0 */ 204 @Override 205 public final void awaitTerminated() { 206 delegate.awaitTerminated(); 207 } 208 209 /** @since 15.0 */ 210 @Override 211 public final void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException { 212 delegate.awaitTerminated(timeout, unit); 213 } 214 215 /** 216 * Returns the name of this service. {@link AbstractExecutionThreadService} may include the name 217 * in debugging output. 218 * 219 * <p>Subclasses may override this method. 220 * 221 * @since 14.0 (present in 10.0 as getServiceName) 222 */ 223 protected String serviceName() { 224 return getClass().getSimpleName(); 225 } 226}