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 017package com.google.common.util.concurrent; 018 019import com.google.common.annotations.Beta; 020import com.google.common.base.Supplier; 021import com.google.common.base.Throwables; 022 023import java.util.concurrent.Executor; 024import java.util.concurrent.TimeUnit; 025import java.util.concurrent.TimeoutException; 026 027/** 028 * Base class for services that do not need a thread while "running" 029 * but may need one during startup and shutdown. Subclasses can 030 * implement {@link #startUp} and {@link #shutDown} methods, each 031 * which run in a executor which by default uses a separate thread 032 * for each method. 033 * 034 * @author Chris Nokleberg 035 * @since 1.0 036 */ 037@Beta 038public abstract class AbstractIdleService implements Service { 039 040 /* Thread names will look like {@code "MyService STARTING"}. */ 041 private final Supplier<String> threadNameSupplier = new Supplier<String>() { 042 @Override public String get() { 043 return serviceName() + " " + state(); 044 } 045 }; 046 047 /* use AbstractService for state management */ 048 private final Service delegate = new AbstractService() { 049 @Override protected final void doStart() { 050 MoreExecutors.renamingDecorator(executor(), threadNameSupplier) 051 .execute(new Runnable() { 052 @Override public void run() { 053 try { 054 startUp(); 055 notifyStarted(); 056 } catch (Throwable t) { 057 notifyFailed(t); 058 throw Throwables.propagate(t); 059 } 060 } 061 }); 062 } 063 064 @Override protected final void doStop() { 065 MoreExecutors.renamingDecorator(executor(), threadNameSupplier) 066 .execute(new Runnable() { 067 @Override public void run() { 068 try { 069 shutDown(); 070 notifyStopped(); 071 } catch (Throwable t) { 072 notifyFailed(t); 073 throw Throwables.propagate(t); 074 } 075 } 076 }); 077 } 078 }; 079 080 /** Constructor for use by subclasses. */ 081 protected AbstractIdleService() {} 082 083 /** Start the service. */ 084 protected abstract void startUp() throws Exception; 085 086 /** Stop the service. */ 087 protected abstract void shutDown() throws Exception; 088 089 /** 090 * Returns the {@link Executor} that will be used to run this service. 091 * Subclasses may override this method to use a custom {@link Executor}, which 092 * may configure its worker thread with a specific name, thread group or 093 * priority. The returned executor's {@link Executor#execute(Runnable) 094 * execute()} method is called when this service is started and stopped, 095 * and should return promptly. 096 */ 097 protected Executor executor() { 098 return new Executor() { 099 @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 // We override instead of using ForwardingService so that these can be final. 110 111 @Deprecated 112 @Override 113 public final ListenableFuture<State> start() { 114 return delegate.start(); 115 } 116 117 @Deprecated 118 @Override 119 public final State startAndWait() { 120 return delegate.startAndWait(); 121 } 122 123 @Override public final boolean isRunning() { 124 return delegate.isRunning(); 125 } 126 127 @Override public final State state() { 128 return delegate.state(); 129 } 130 131 @Deprecated 132 @Override 133 public final ListenableFuture<State> stop() { 134 return delegate.stop(); 135 } 136 137 @Deprecated 138 @Override 139 public final State stopAndWait() { 140 return delegate.stopAndWait(); 141 } 142 143 /** 144 * @since 13.0 145 */ 146 @Override public final void addListener(Listener listener, Executor executor) { 147 delegate.addListener(listener, executor); 148 } 149 150 /** 151 * @since 14.0 152 */ 153 @Override public final Throwable failureCause() { 154 return delegate.failureCause(); 155 } 156 157 /** 158 * @since 15.0 159 */ 160 @Override public final Service startAsync() { 161 delegate.startAsync(); 162 return this; 163 } 164 165 /** 166 * @since 15.0 167 */ 168 @Override public final Service stopAsync() { 169 delegate.stopAsync(); 170 return this; 171 } 172 173 /** 174 * @since 15.0 175 */ 176 @Override public final void awaitRunning() { 177 delegate.awaitRunning(); 178 } 179 180 /** 181 * @since 15.0 182 */ 183 @Override public final void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException { 184 delegate.awaitRunning(timeout, unit); 185 } 186 187 /** 188 * @since 15.0 189 */ 190 @Override public final void awaitTerminated() { 191 delegate.awaitTerminated(); 192 } 193 194 /** 195 * @since 15.0 196 */ 197 @Override public final void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException { 198 delegate.awaitTerminated(timeout, unit); 199 } 200 201 /** 202 * Returns the name of this service. {@link AbstractIdleService} may include the name in debugging 203 * output. 204 * 205 * @since 14.0 206 */ 207 protected String serviceName() { 208 return getClass().getSimpleName(); 209 } 210}