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