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.GwtIncompatible; 018import com.google.common.base.Supplier; 019import com.google.errorprone.annotations.CanIgnoreReturnValue; 020import com.google.j2objc.annotations.WeakOuter; 021import java.time.Duration; 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@GwtIncompatible 035public abstract class AbstractIdleService implements Service { 036 037 /* Thread names will look like {@code "MyService STARTING"}. */ 038 private final Supplier<String> threadNameSupplier = new ThreadNameSupplier(); 039 040 @WeakOuter 041 private final class ThreadNameSupplier implements Supplier<String> { 042 @Override 043 public String get() { 044 return serviceName() + " " + state(); 045 } 046 } 047 048 /* use AbstractService for state management */ 049 private final Service delegate = new DelegateService(); 050 051 @WeakOuter 052 private final class DelegateService extends AbstractService { 053 @Override 054 protected final void doStart() { 055 MoreExecutors.renamingDecorator(executor(), threadNameSupplier) 056 .execute( 057 new Runnable() { 058 @Override 059 public void run() { 060 try { 061 startUp(); 062 notifyStarted(); 063 } catch (Throwable t) { 064 notifyFailed(t); 065 } 066 } 067 }); 068 } 069 070 @Override 071 protected final void doStop() { 072 MoreExecutors.renamingDecorator(executor(), threadNameSupplier) 073 .execute( 074 new Runnable() { 075 @Override 076 public void run() { 077 try { 078 shutDown(); 079 notifyStopped(); 080 } catch (Throwable t) { 081 notifyFailed(t); 082 } 083 } 084 }); 085 } 086 087 @Override 088 public String toString() { 089 return AbstractIdleService.this.toString(); 090 } 091 } 092 093 /** Constructor for use by subclasses. */ 094 protected AbstractIdleService() {} 095 096 /** Start the service. */ 097 protected abstract void startUp() throws Exception; 098 099 /** Stop the service. */ 100 protected abstract void shutDown() throws Exception; 101 102 /** 103 * Returns the {@link Executor} that will be used to run this service. Subclasses may override 104 * this method to use a custom {@link Executor}, which may configure its worker thread with a 105 * specific name, thread group or priority. The returned executor's {@link 106 * Executor#execute(Runnable) execute()} method is called when this service is started and 107 * stopped, and should return promptly. 108 */ 109 protected Executor executor() { 110 return new Executor() { 111 @Override 112 public void execute(Runnable command) { 113 MoreExecutors.newThread(threadNameSupplier.get(), command).start(); 114 } 115 }; 116 } 117 118 @Override 119 public String toString() { 120 return serviceName() + " [" + state() + "]"; 121 } 122 123 @Override 124 public final boolean isRunning() { 125 return delegate.isRunning(); 126 } 127 128 @Override 129 public final State state() { 130 return delegate.state(); 131 } 132 133 /** @since 13.0 */ 134 @Override 135 public final void addListener(Listener listener, Executor executor) { 136 delegate.addListener(listener, executor); 137 } 138 139 /** @since 14.0 */ 140 @Override 141 public final Throwable failureCause() { 142 return delegate.failureCause(); 143 } 144 145 /** @since 15.0 */ 146 @CanIgnoreReturnValue 147 @Override 148 public final Service startAsync() { 149 delegate.startAsync(); 150 return this; 151 } 152 153 /** @since 15.0 */ 154 @CanIgnoreReturnValue 155 @Override 156 public final Service stopAsync() { 157 delegate.stopAsync(); 158 return this; 159 } 160 161 /** @since 15.0 */ 162 @Override 163 public final void awaitRunning() { 164 delegate.awaitRunning(); 165 } 166 167 /** @since 28.0 */ 168 @Override 169 public final void awaitRunning(Duration timeout) throws TimeoutException { 170 Service.super.awaitRunning(timeout); 171 } 172 173 /** @since 15.0 */ 174 @Override 175 public final void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException { 176 delegate.awaitRunning(timeout, unit); 177 } 178 179 /** @since 15.0 */ 180 @Override 181 public final void awaitTerminated() { 182 delegate.awaitTerminated(); 183 } 184 185 /** @since 28.0 */ 186 @Override 187 public final void awaitTerminated(Duration timeout) throws TimeoutException { 188 Service.super.awaitTerminated(timeout); 189 } 190 191 /** @since 15.0 */ 192 @Override 193 public final void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException { 194 delegate.awaitTerminated(timeout, unit); 195 } 196 197 /** 198 * Returns the name of this service. {@link AbstractIdleService} may include the name in debugging 199 * output. 200 * 201 * @since 14.0 202 */ 203 protected String serviceName() { 204 return getClass().getSimpleName(); 205 } 206}