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 @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}