1 /* 2 * Copyright (C) 2009 Google Inc. 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 17 package com.google.common.util.concurrent; 18 19 import com.google.common.base.Service; 20 import com.google.common.base.Service.State; // for javadoc 21 import com.google.common.base.Throwables; 22 23 import java.util.concurrent.Executor; 24 import java.util.concurrent.Future; 25 26 /** 27 * Base class for services that do not need a thread while "running" 28 * but may need one during startup and shutdown. Subclasses can 29 * implement {@link #startUp} and {@link #shutDown} methods, each 30 * which run in a executor which by default uses a separate thread 31 * for each method. 32 * 33 * @author Chris Nokleberg 34 * @since 2009.09.15 <b>tentative</b> 35 */ 36 public abstract class AbstractIdleService implements Service { 37 38 /* use AbstractService for state management */ 39 private final Service delegate = new AbstractService() { 40 @Override protected final void doStart() { 41 executor(State.STARTING).execute(new Runnable() { 42 /*@Override*/ public void run() { 43 try { 44 startUp(); 45 notifyStarted(); 46 } catch (Throwable t) { 47 notifyFailed(t); 48 throw Throwables.propagate(t); 49 } 50 } 51 }); 52 } 53 54 @Override protected final void doStop() { 55 executor(State.STOPPING).execute(new Runnable() { 56 /*@Override*/ public void run() { 57 try { 58 shutDown(); 59 notifyStopped(); 60 } catch (Throwable t) { 61 notifyFailed(t); 62 throw Throwables.propagate(t); 63 } 64 } 65 }); 66 } 67 }; 68 69 /** Start the service. */ startUp()70 protected abstract void startUp() throws Exception; 71 72 /** Stop the service. */ shutDown()73 protected abstract void shutDown() throws Exception; 74 75 /** 76 * Returns the {@link Executor} that will be used to run this service. 77 * Subclasses may override this method to use a custom {@link Executor}, which 78 * may configure its worker thread with a specific name, thread group or 79 * priority. The returned executor's {@link Executor#execute(Runnable) 80 * execute()} method is called when this service is started and stopped, 81 * and should return promptly. 82 * 83 * @param state {@link State#STARTING} or {@link State#STOPPING}, used by the 84 * default implementation for naming the thread 85 */ executor(final State state)86 protected Executor executor(final State state) { 87 return new Executor() { 88 public void execute(Runnable command) { 89 new Thread(command, AbstractIdleService.this.toString() + " " + state) 90 .start(); 91 } 92 }; 93 } 94 95 @Override public String toString() { 96 return getClass().getSimpleName(); 97 } 98 99 // We override instead of using ForwardingService so that these can be final. 100 101 /*@Override*/ public final Future<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 Future<State> stop() { 118 return delegate.stop(); 119 } 120 121 /*@Override*/ public final State stopAndWait() { 122 return delegate.stopAndWait(); 123 } 124 } 125