• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.google.common.util.concurrent.Platform.restoreInterruptIfIsInterruptedException;
18 
19 import com.google.common.annotations.GwtIncompatible;
20 import com.google.common.annotations.J2ktIncompatible;
21 import com.google.common.base.Supplier;
22 import com.google.errorprone.annotations.CanIgnoreReturnValue;
23 import com.google.j2objc.annotations.WeakOuter;
24 import java.time.Duration;
25 import java.util.concurrent.Executor;
26 import java.util.concurrent.TimeUnit;
27 import java.util.concurrent.TimeoutException;
28 
29 /**
30  * Base class for services that do not need a thread while "running" but may need one during startup
31  * and shutdown. Subclasses can implement {@link #startUp} and {@link #shutDown} methods, each which
32  * run in an executor which by default uses a separate thread for each method.
33  *
34  * @author Chris Nokleberg
35  * @since 1.0
36  */
37 @GwtIncompatible
38 @J2ktIncompatible
39 @ElementTypesAreNonnullByDefault
40 public abstract class AbstractIdleService implements Service {
41 
42   /* Thread names will look like {@code "MyService STARTING"}. */
43   private final Supplier<String> threadNameSupplier = new ThreadNameSupplier();
44 
45   @WeakOuter
46   private final class ThreadNameSupplier implements Supplier<String> {
47     @Override
get()48     public String get() {
49       return serviceName() + " " + state();
50     }
51   }
52 
53   /* use AbstractService for state management */
54   private final Service delegate = new DelegateService();
55 
56   @WeakOuter
57   private final class DelegateService extends AbstractService {
58     @Override
doStart()59     protected final void doStart() {
60       MoreExecutors.renamingDecorator(executor(), threadNameSupplier)
61           .execute(
62               () -> {
63                 try {
64                   startUp();
65                   notifyStarted();
66                 } catch (Throwable t) {
67                   restoreInterruptIfIsInterruptedException(t);
68                   notifyFailed(t);
69                 }
70               });
71     }
72 
73     @Override
doStop()74     protected final void doStop() {
75       MoreExecutors.renamingDecorator(executor(), threadNameSupplier)
76           .execute(
77               () -> {
78                 try {
79                   shutDown();
80                   notifyStopped();
81                 } catch (Throwable t) {
82                   restoreInterruptIfIsInterruptedException(t);
83                   notifyFailed(t);
84                 }
85               });
86     }
87 
88     @Override
toString()89     public String toString() {
90       return AbstractIdleService.this.toString();
91     }
92   }
93 
94   /** Constructor for use by subclasses. */
AbstractIdleService()95   protected AbstractIdleService() {}
96 
97   /** Start the service. */
startUp()98   protected abstract void startUp() throws Exception;
99 
100   /** Stop the service. */
shutDown()101   protected abstract void shutDown() throws Exception;
102 
103   /**
104    * Returns the {@link Executor} that will be used to run this service. Subclasses may override
105    * this method to use a custom {@link Executor}, which may configure its worker thread with a
106    * specific name, thread group or priority. The returned executor's {@link
107    * Executor#execute(Runnable) execute()} method is called when this service is started and
108    * stopped, and should return promptly.
109    */
executor()110   protected Executor executor() {
111     return command -> MoreExecutors.newThread(threadNameSupplier.get(), command).start();
112   }
113 
114   @Override
toString()115   public String toString() {
116     return serviceName() + " [" + state() + "]";
117   }
118 
119   @Override
isRunning()120   public final boolean isRunning() {
121     return delegate.isRunning();
122   }
123 
124   @Override
state()125   public final State state() {
126     return delegate.state();
127   }
128 
129   /** @since 13.0 */
130   @Override
addListener(Listener listener, Executor executor)131   public final void addListener(Listener listener, Executor executor) {
132     delegate.addListener(listener, executor);
133   }
134 
135   /** @since 14.0 */
136   @Override
failureCause()137   public final Throwable failureCause() {
138     return delegate.failureCause();
139   }
140 
141   /** @since 15.0 */
142   @CanIgnoreReturnValue
143   @Override
startAsync()144   public final Service startAsync() {
145     delegate.startAsync();
146     return this;
147   }
148 
149   /** @since 15.0 */
150   @CanIgnoreReturnValue
151   @Override
stopAsync()152   public final Service stopAsync() {
153     delegate.stopAsync();
154     return this;
155   }
156 
157   /** @since 15.0 */
158   @Override
awaitRunning()159   public final void awaitRunning() {
160     delegate.awaitRunning();
161   }
162 
163   /** @since 28.0 */
164   @Override
awaitRunning(Duration timeout)165   public final void awaitRunning(Duration timeout) throws TimeoutException {
166     Service.super.awaitRunning(timeout);
167   }
168 
169   /** @since 15.0 */
170   @Override
awaitRunning(long timeout, TimeUnit unit)171   public final void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException {
172     delegate.awaitRunning(timeout, unit);
173   }
174 
175   /** @since 15.0 */
176   @Override
awaitTerminated()177   public final void awaitTerminated() {
178     delegate.awaitTerminated();
179   }
180 
181   /** @since 28.0 */
182   @Override
awaitTerminated(Duration timeout)183   public final void awaitTerminated(Duration timeout) throws TimeoutException {
184     Service.super.awaitTerminated(timeout);
185   }
186 
187   /** @since 15.0 */
188   @Override
awaitTerminated(long timeout, TimeUnit unit)189   public final void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException {
190     delegate.awaitTerminated(timeout, unit);
191   }
192 
193   /**
194    * Returns the name of this service. {@link AbstractIdleService} may include the name in debugging
195    * output.
196    *
197    * @since 14.0
198    */
serviceName()199   protected String serviceName() {
200     return getClass().getSimpleName();
201   }
202 }
203