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