001 /* 002 * Copyright (C) 2009 Google Inc. 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 017 package com.google.common.util.concurrent; 018 019 import com.google.common.annotations.Beta; 020 import com.google.common.base.Service; 021 import com.google.common.base.Throwables; 022 023 import java.util.concurrent.Executor; 024 import java.util.concurrent.Future; 025 026 /** 027 * Base class for services that do not need a thread while "running" 028 * but may need one during startup and shutdown. Subclasses can 029 * implement {@link #startUp} and {@link #shutDown} methods, each 030 * which run in a executor which by default uses a separate thread 031 * for each method. 032 * 033 * @author Chris Nokleberg 034 * @since 1 035 */ 036 @Beta 037 public abstract class AbstractIdleService implements Service { 038 039 /* use AbstractService for state management */ 040 private final Service delegate = new AbstractService() { 041 @Override protected final void doStart() { 042 executor(State.STARTING).execute(new Runnable() { 043 @Override public void run() { 044 try { 045 startUp(); 046 notifyStarted(); 047 } catch (Throwable t) { 048 notifyFailed(t); 049 throw Throwables.propagate(t); 050 } 051 } 052 }); 053 } 054 055 @Override protected final void doStop() { 056 executor(State.STOPPING).execute(new Runnable() { 057 @Override public void run() { 058 try { 059 shutDown(); 060 notifyStopped(); 061 } catch (Throwable t) { 062 notifyFailed(t); 063 throw Throwables.propagate(t); 064 } 065 } 066 }); 067 } 068 }; 069 070 /** Start the service. */ 071 protected abstract void startUp() throws Exception; 072 073 /** Stop the service. */ 074 protected abstract void shutDown() throws Exception; 075 076 /** 077 * Returns the {@link Executor} that will be used to run this service. 078 * Subclasses may override this method to use a custom {@link Executor}, which 079 * may configure its worker thread with a specific name, thread group or 080 * priority. The returned executor's {@link Executor#execute(Runnable) 081 * execute()} method is called when this service is started and stopped, 082 * and should return promptly. 083 * 084 * @param state {@link com.google.common.base.Service.State#STARTING} or 085 * {@link com.google.common.base.Service.State#STOPPING}, used by the 086 * default implementation for naming the thread 087 */ 088 protected Executor executor(final State state) { 089 return new Executor() { 090 public void execute(Runnable command) { 091 new Thread(command, getServiceName() + " " + state).start(); 092 } 093 }; 094 } 095 096 @Override public String toString() { 097 return getServiceName() + " [" + state() + "]"; 098 } 099 100 // We override instead of using ForwardingService so that these can be final. 101 102 @Override public final Future<State> start() { 103 return delegate.start(); 104 } 105 106 @Override public final State startAndWait() { 107 return delegate.startAndWait(); 108 } 109 110 @Override public final boolean isRunning() { 111 return delegate.isRunning(); 112 } 113 114 @Override public final State state() { 115 return delegate.state(); 116 } 117 118 @Override public final Future<State> stop() { 119 return delegate.stop(); 120 } 121 122 @Override public final State stopAndWait() { 123 return delegate.stopAndWait(); 124 } 125 126 private String getServiceName() { 127 return getClass().getSimpleName(); 128 } 129 }