1/* 2 * Copyright (C) 2009 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.google.common.util.concurrent; 18 19import com.google.common.annotations.Beta; 20import com.google.common.base.Supplier; 21import com.google.common.base.Throwables; 22 23import java.util.concurrent.Executor; 24import java.util.concurrent.TimeUnit; 25import java.util.concurrent.TimeoutException; 26 27/** 28 * Base class for services that do not need a thread while "running" 29 * but may need one during startup and shutdown. Subclasses can 30 * implement {@link #startUp} and {@link #shutDown} methods, each 31 * which run in a executor which by default uses a separate thread 32 * for each method. 33 * 34 * @author Chris Nokleberg 35 * @since 1.0 36 */ 37@Beta 38public abstract class AbstractIdleService implements Service { 39 40 /* Thread names will look like {@code "MyService STARTING"}. */ 41 private final Supplier<String> threadNameSupplier = new Supplier<String>() { 42 @Override public String get() { 43 return serviceName() + " " + state(); 44 } 45 }; 46 47 /* use AbstractService for state management */ 48 private final Service delegate = new AbstractService() { 49 @Override protected final void doStart() { 50 MoreExecutors.renamingDecorator(executor(), threadNameSupplier) 51 .execute(new Runnable() { 52 @Override public void run() { 53 try { 54 startUp(); 55 notifyStarted(); 56 } catch (Throwable t) { 57 notifyFailed(t); 58 throw Throwables.propagate(t); 59 } 60 } 61 }); 62 } 63 64 @Override protected final void doStop() { 65 MoreExecutors.renamingDecorator(executor(), threadNameSupplier) 66 .execute(new Runnable() { 67 @Override public void run() { 68 try { 69 shutDown(); 70 notifyStopped(); 71 } catch (Throwable t) { 72 notifyFailed(t); 73 throw Throwables.propagate(t); 74 } 75 } 76 }); 77 } 78 }; 79 80 /** Constructor for use by subclasses. */ 81 protected AbstractIdleService() {} 82 83 /** Start the service. */ 84 protected abstract void startUp() throws Exception; 85 86 /** Stop the service. */ 87 protected abstract void shutDown() throws Exception; 88 89 /** 90 * Returns the {@link Executor} that will be used to run this service. 91 * Subclasses may override this method to use a custom {@link Executor}, which 92 * may configure its worker thread with a specific name, thread group or 93 * priority. The returned executor's {@link Executor#execute(Runnable) 94 * execute()} method is called when this service is started and stopped, 95 * and should return promptly. 96 */ 97 protected Executor executor() { 98 return new Executor() { 99 @Override public void execute(Runnable command) { 100 MoreExecutors.newThread(threadNameSupplier.get(), command).start(); 101 } 102 }; 103 } 104 105 @Override public String toString() { 106 return serviceName() + " [" + state() + "]"; 107 } 108 109 @Override public final boolean isRunning() { 110 return delegate.isRunning(); 111 } 112 113 @Override public final State state() { 114 return delegate.state(); 115 } 116 117 /** 118 * @since 13.0 119 */ 120 @Override public final void addListener(Listener listener, Executor executor) { 121 delegate.addListener(listener, executor); 122 } 123 124 /** 125 * @since 14.0 126 */ 127 @Override public final Throwable failureCause() { 128 return delegate.failureCause(); 129 } 130 131 /** 132 * @since 15.0 133 */ 134 @Override public final Service startAsync() { 135 delegate.startAsync(); 136 return this; 137 } 138 139 /** 140 * @since 15.0 141 */ 142 @Override public final Service stopAsync() { 143 delegate.stopAsync(); 144 return this; 145 } 146 147 /** 148 * @since 15.0 149 */ 150 @Override public final void awaitRunning() { 151 delegate.awaitRunning(); 152 } 153 154 /** 155 * @since 15.0 156 */ 157 @Override public final void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException { 158 delegate.awaitRunning(timeout, unit); 159 } 160 161 /** 162 * @since 15.0 163 */ 164 @Override public final void awaitTerminated() { 165 delegate.awaitTerminated(); 166 } 167 168 /** 169 * @since 15.0 170 */ 171 @Override public final void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException { 172 delegate.awaitTerminated(timeout, unit); 173 } 174 175 /** 176 * Returns the name of this service. {@link AbstractIdleService} may include the name in debugging 177 * output. 178 * 179 * @since 14.0 180 */ 181 protected String serviceName() { 182 return getClass().getSimpleName(); 183 } 184} 185