
javadoc.src-html.com.google.common.util.concurrent.AbstractExecutionThreadService.html Maven / Gradle / Ivy
001 /*
002 * Copyright (C) 2009 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package com.google.common.util.concurrent;
018
019 import com.google.common.annotations.Beta;
020 import com.google.common.base.Throwables;
021
022 import java.util.concurrent.Executor;
023 import java.util.logging.Level;
024 import java.util.logging.Logger;
025
026 /**
027 * Base class for services that can implement {@link #startUp}, {@link #run} and
028 * {@link #shutDown} methods. This class uses a single thread to execute the
029 * service; consider {@link AbstractService} if you would like to manage any
030 * threading manually.
031 *
032 * @author Jesse Wilson
033 * @since 1.0
034 */
035 @Beta
036 public abstract class AbstractExecutionThreadService implements Service {
037 private static final Logger logger = Logger.getLogger(
038 AbstractExecutionThreadService.class.getName());
039
040 /* use AbstractService for state management */
041 private final Service delegate = new AbstractService() {
042 @Override protected final void doStart() {
043 executor().execute(new Runnable() {
044 @Override
045 public void run() {
046 try {
047 startUp();
048 notifyStarted();
049
050 if (isRunning()) {
051 try {
052 AbstractExecutionThreadService.this.run();
053 } catch (Throwable t) {
054 try {
055 shutDown();
056 } catch (Exception ignored) {
057 logger.log(Level.WARNING,
058 "Error while attempting to shut down the service after failure.", ignored);
059 }
060 throw t;
061 }
062 }
063
064 shutDown();
065 notifyStopped();
066 } catch (Throwable t) {
067 notifyFailed(t);
068 throw Throwables.propagate(t);
069 }
070 }
071 });
072 }
073
074 @Override protected void doStop() {
075 triggerShutdown();
076 }
077 };
078
079 /**
080 * Start the service. This method is invoked on the execution thread.
081 */
082 protected void startUp() throws Exception {}
083
084 /**
085 * Run the service. This method is invoked on the execution thread.
086 * Implementations must respond to stop requests. You could poll for lifecycle
087 * changes in a work loop:
088 * <pre>
089 * public void run() {
090 * while ({@link #isRunning()}) {
091 * // perform a unit of work
092 * }
093 * }
094 * </pre>
095 * ...or you could respond to stop requests by implementing {@link
096 * #triggerShutdown()}, which should cause {@link #run()} to return.
097 */
098 protected abstract void run() throws Exception;
099
100 /**
101 * Stop the service. This method is invoked on the execution thread.
102 */
103 // TODO: consider supporting a TearDownTestCase-like API
104 protected void shutDown() throws Exception {}
105
106 /**
107 * Invoked to request the service to stop.
108 */
109 protected void triggerShutdown() {}
110
111 /**
112 * Returns the {@link Executor} that will be used to run this service.
113 * Subclasses may override this method to use a custom {@link Executor}, which
114 * may configure its worker thread with a specific name, thread group or
115 * priority. The returned executor's {@link Executor#execute(Runnable)
116 * execute()} method is called when this service is started, and should return
117 * promptly.
118 *
119 * <p>The default implementation returns a new {@link Executor} that sets the
120 * name of its threads to the string returned by {@link #getServiceName}
121 */
122 protected Executor executor() {
123 return new Executor() {
124 @Override
125 public void execute(Runnable command) {
126 new Thread(command, getServiceName()).start();
127 }
128 };
129 }
130
131 @Override public String toString() {
132 return getServiceName() + " [" + state() + "]";
133 }
134
135 // We override instead of using ForwardingService so that these can be final.
136
137 @Override public final ListenableFuture<State> start() {
138 return delegate.start();
139 }
140
141 @Override public final State startAndWait() {
142 return delegate.startAndWait();
143 }
144
145 @Override public final boolean isRunning() {
146 return delegate.isRunning();
147 }
148
149 @Override public final State state() {
150 return delegate.state();
151 }
152
153 @Override public final ListenableFuture<State> stop() {
154 return delegate.stop();
155 }
156
157 @Override public final State stopAndWait() {
158 return delegate.stopAndWait();
159 }
160
161 /**
162 * Returns the name of this service. {@link AbstractExecutionThreadService} may include the name
163 * in debugging output.
164 *
165 * <p>Subclasses may override this method.
166 *
167 * @since 10.0
168 */
169 protected String getServiceName() {
170 return getClass().getSimpleName();
171 }
172 }
© 2015 - 2025 Weber Informatics LLC | Privacy Policy