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