AbstractIdleService.java revision 7dd252788645e940eada959bdde927426e2531c9
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 40 protected final void doStart() { 41 executor().execute(new Runnable() { 42 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 55 protected final void doStop() { 56 executor().execute(new Runnable() { 57 public void run() { 58 try { 59 shutDown(); 60 notifyStopped(); 61 } catch (Throwable t) { 62 notifyFailed(t); 63 throw Throwables.propagate(t); 64 } 65 } 66 }); 67 } 68 }; 69 70 /** Constructor for use by subclasses. */ 71 protected AbstractIdleService() {} 72 73 /** Start the service. */ 74 protected abstract void startUp() throws Exception; 75 76 /** Stop the service. */ 77 protected abstract void shutDown() throws Exception; 78 79 /** 80 * Returns the {@link Executor} that will be used to run this service. 81 * Subclasses may override this method to use a custom {@link Executor}, which 82 * may configure its worker thread with a specific name, thread group or 83 * priority. The returned executor's {@link Executor#execute(Runnable) 84 * execute()} method is called when this service is started and stopped, 85 * and should return promptly. 86 */ 87 protected Executor executor() { 88 final State state = state(); 89 return new Executor() { 90 91 public void execute(Runnable command) { 92 MoreExecutors.newThread(serviceName() + " " + state, command).start(); 93 } 94 }; 95 } 96 97 @Override 98 public String toString() { 99 return serviceName() + " [" + state() + "]"; 100 } 101 102 // We override instead of using ForwardingService so that these can be final. 103 104 public final ListenableFuture<State> start() { 105 return delegate.start(); 106 } 107 108 public final State startAndWait() { 109 return delegate.startAndWait(); 110 } 111 112 public final boolean isRunning() { 113 return delegate.isRunning(); 114 } 115 116 public final State state() { 117 return delegate.state(); 118 } 119 120 public final ListenableFuture<State> stop() { 121 return delegate.stop(); 122 } 123 124 public final State stopAndWait() { 125 return delegate.stopAndWait(); 126 } 127 128 /** 129 * @since 13.0 130 */ 131 public final void addListener(Listener listener, Executor executor) { 132 delegate.addListener(listener, executor); 133 } 134 135 /** 136 * @since 14.0 137 */ 138 public final Throwable failureCause() { 139 return delegate.failureCause(); 140 } 141 142 /** 143 * Returns the name of this service. {@link AbstractIdleService} may include the name in debugging 144 * output. 145 * 146 * @since 14.0 147 */ 148 protected String serviceName() { 149 return getClass().getSimpleName(); 150 } 151} 152