1bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor/* 21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * Copyright (C) 2009 The Guava Authors 3bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * 4bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * Licensed under the Apache License, Version 2.0 (the "License"); 5bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * you may not use this file except in compliance with the License. 6bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * You may obtain a copy of the License at 7bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * 8bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * http://www.apache.org/licenses/LICENSE-2.0 9bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * 10bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * Unless required by applicable law or agreed to in writing, software 11bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * distributed under the License is distributed on an "AS IS" BASIS, 12bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * See the License for the specific language governing permissions and 14bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * limitations under the License. 15bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor */ 16bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 17bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorpackage com.google.common.util.concurrent; 18bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringertimport com.google.common.annotations.Beta; 20bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport com.google.common.base.Throwables; 21bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 22bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorimport java.util.concurrent.Executor; 23bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 24bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor/** 25bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * Base class for services that do not need a thread while "running" 26bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * but may need one during startup and shutdown. Subclasses can 27bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * implement {@link #startUp} and {@link #shutDown} methods, each 28bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * which run in a executor which by default uses a separate thread 29bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * for each method. 30bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * 31bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * @author Chris Nokleberg 321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @since 1.0 33bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor */ 341d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert@Beta 35bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnorpublic abstract class AbstractIdleService implements Service { 36bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 37bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor /* use AbstractService for state management */ 38bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor private final Service delegate = new AbstractService() { 39bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor @Override protected final void doStart() { 40bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor executor(State.STARTING).execute(new Runnable() { 411d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public void run() { 42bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor try { 43bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor startUp(); 44bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor notifyStarted(); 45bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } catch (Throwable t) { 46bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor notifyFailed(t); 47bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor throw Throwables.propagate(t); 48bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 49bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 50bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor }); 51bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 52bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 53bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor @Override protected final void doStop() { 54bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor executor(State.STOPPING).execute(new Runnable() { 551d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public void run() { 56bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor try { 57bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor shutDown(); 58bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor notifyStopped(); 59bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } catch (Throwable t) { 60bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor notifyFailed(t); 61bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor throw Throwables.propagate(t); 62bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 63bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 64bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor }); 65bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 66bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor }; 67bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 68bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor /** Start the service. */ 69bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor protected abstract void startUp() throws Exception; 70bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 71bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor /** Stop the service. */ 72bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor protected abstract void shutDown() throws Exception; 73bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 74bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor /** 75bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * Returns the {@link Executor} that will be used to run this service. 76bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * Subclasses may override this method to use a custom {@link Executor}, which 77bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * may configure its worker thread with a specific name, thread group or 78bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * priority. The returned executor's {@link Executor#execute(Runnable) 79bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * execute()} method is called when this service is started and stopped, 80bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * and should return promptly. 81bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor * 821d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * @param state {@link Service.State#STARTING} or 831d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * {@link Service.State#STOPPING}, used by the default implementation for 841d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert * naming the thread 85bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor */ 86bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor protected Executor executor(final State state) { 87bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor return new Executor() { 881d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override 89bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor public void execute(Runnable command) { 901d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert new Thread(command, getServiceName() + " " + state).start(); 91bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 92bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor }; 93bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 94bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 95bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor @Override public String toString() { 961d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return getServiceName() + " [" + state() + "]"; 97bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 98bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 99bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor // We override instead of using ForwardingService so that these can be final. 100bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 1011d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public final ListenableFuture<State> start() { 102bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor return delegate.start(); 103bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 104bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 1051d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public final State startAndWait() { 106bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor return delegate.startAndWait(); 107bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 108bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 1091d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public final boolean isRunning() { 110bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor return delegate.isRunning(); 111bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 112bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 1131d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public final State state() { 114bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor return delegate.state(); 115bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 116bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 1171d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public final ListenableFuture<State> stop() { 118bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor return delegate.stop(); 119bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 120bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor 1211d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert @Override public final State stopAndWait() { 122bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor return delegate.stopAndWait(); 123bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor } 1241d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert 1251d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert private String getServiceName() { 1261d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert return getClass().getSimpleName(); 1271d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert } 128bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor} 129