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.Throwables; 021 022import java.util.concurrent.Executor; 023 024/** 025 * Base class for services that do not need a thread while "running" 026 * but may need one during startup and shutdown. Subclasses can 027 * implement {@link #startUp} and {@link #shutDown} methods, each 028 * which run in a executor which by default uses a separate thread 029 * for each method. 030 * 031 * @author Chris Nokleberg 032 * @since 1.0 033 */ 034@Beta 035public abstract class AbstractIdleService implements Service { 036 037 /* use AbstractService for state management */ 038 private final Service delegate = new AbstractService() { 039 @Override protected final void doStart() { 040 executor().execute(new Runnable() { 041 @Override public void run() { 042 try { 043 startUp(); 044 notifyStarted(); 045 } catch (Throwable t) { 046 notifyFailed(t); 047 throw Throwables.propagate(t); 048 } 049 } 050 }); 051 } 052 053 @Override protected final void doStop() { 054 executor().execute(new Runnable() { 055 @Override public void run() { 056 try { 057 shutDown(); 058 notifyStopped(); 059 } catch (Throwable t) { 060 notifyFailed(t); 061 throw Throwables.propagate(t); 062 } 063 } 064 }); 065 } 066 }; 067 068 /** Constructor for use by subclasses. */ 069 protected AbstractIdleService() {} 070 071 /** Start the service. */ 072 protected abstract void startUp() throws Exception; 073 074 /** Stop the service. */ 075 protected abstract void shutDown() throws Exception; 076 077 /** 078 * Returns the {@link Executor} that will be used to run this service. 079 * Subclasses may override this method to use a custom {@link Executor}, which 080 * may configure its worker thread with a specific name, thread group or 081 * priority. The returned executor's {@link Executor#execute(Runnable) 082 * execute()} method is called when this service is started and stopped, 083 * and should return promptly. 084 */ 085 protected Executor executor() { 086 final State state = state(); 087 return new Executor() { 088 @Override 089 public void execute(Runnable command) { 090 MoreExecutors.newThread(serviceName() + " " + state, command).start(); 091 } 092 }; 093 } 094 095 @Override public String toString() { 096 return serviceName() + " [" + state() + "]"; 097 } 098 099 // 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 /** 126 * @since 13.0 127 */ 128 @Override public final void addListener(Listener listener, Executor executor) { 129 delegate.addListener(listener, executor); 130 } 131 132 /** 133 * @since 14.0 134 */ 135 @Override public final Throwable failureCause() { 136 return delegate.failureCause(); 137 } 138 139 /** 140 * Returns the name of this service. {@link AbstractIdleService} may include the name in debugging 141 * output. 142 * 143 * @since 14.0 144 */ 145 protected String serviceName() { 146 return getClass().getSimpleName(); 147 } 148}