165888c01862049c0f7744cf4dfac371ce780fb24dhanji/** 265888c01862049c0f7744cf4dfac371ce780fb24dhanji * Copyright (C) 2010 Google Inc. 365888c01862049c0f7744cf4dfac371ce780fb24dhanji * 465888c01862049c0f7744cf4dfac371ce780fb24dhanji * Licensed under the Apache License, Version 2.0 (the "License"); 565888c01862049c0f7744cf4dfac371ce780fb24dhanji * you may not use this file except in compliance with the License. 665888c01862049c0f7744cf4dfac371ce780fb24dhanji * You may obtain a copy of the License at 765888c01862049c0f7744cf4dfac371ce780fb24dhanji * 865888c01862049c0f7744cf4dfac371ce780fb24dhanji * http://www.apache.org/licenses/LICENSE-2.0 965888c01862049c0f7744cf4dfac371ce780fb24dhanji * 1065888c01862049c0f7744cf4dfac371ce780fb24dhanji * Unless required by applicable law or agreed to in writing, software 1165888c01862049c0f7744cf4dfac371ce780fb24dhanji * distributed under the License is distributed on an "AS IS" BASIS, 1265888c01862049c0f7744cf4dfac371ce780fb24dhanji * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1365888c01862049c0f7744cf4dfac371ce780fb24dhanji * See the License for the specific language governing permissions and 1465888c01862049c0f7744cf4dfac371ce780fb24dhanji * limitations under the License. 1565888c01862049c0f7744cf4dfac371ce780fb24dhanji */ 1665888c01862049c0f7744cf4dfac371ce780fb24dhanji 1765888c01862049c0f7744cf4dfac371ce780fb24dhanjipackage com.google.inject.service; 1865888c01862049c0f7744cf4dfac371ce780fb24dhanji 19d9c913acca55023ef5d76a32c3d4a51ee6b420cbsberlinimport com.google.common.base.Preconditions; 20b7a02b02d81c830d148355c90bc309bcd66fb592sberlin 2165888c01862049c0f7744cf4dfac371ce780fb24dhanjiimport java.util.concurrent.Callable; 2265888c01862049c0f7744cf4dfac371ce780fb24dhanjiimport java.util.concurrent.ExecutorService; 2365888c01862049c0f7744cf4dfac371ce780fb24dhanjiimport java.util.concurrent.Future; 2465888c01862049c0f7744cf4dfac371ce780fb24dhanjiimport java.util.concurrent.FutureTask; 2565888c01862049c0f7744cf4dfac371ce780fb24dhanji 2665888c01862049c0f7744cf4dfac371ce780fb24dhanji/** 2765888c01862049c0f7744cf4dfac371ce780fb24dhanji * An asynchronous implementation of {@link com.google.inject.service.Service} 2865888c01862049c0f7744cf4dfac371ce780fb24dhanji * that provides convenience callbacks to create your own services. 2965888c01862049c0f7744cf4dfac371ce780fb24dhanji * 3065888c01862049c0f7744cf4dfac371ce780fb24dhanji * @author dhanji@gmail.com (Dhanji R. Prasanna) 3165888c01862049c0f7744cf4dfac371ce780fb24dhanji */ 3265888c01862049c0f7744cf4dfac371ce780fb24dhanjipublic abstract class AsyncService implements Service { 331a30c07469f896097c1311e039ca3066873f5db9cgdecker private static final Runnable DO_NOTHING = new Runnable() { 341a30c07469f896097c1311e039ca3066873f5db9cgdecker @Override public void run() {} 351a30c07469f896097c1311e039ca3066873f5db9cgdecker }; 361a30c07469f896097c1311e039ca3066873f5db9cgdecker 3765888c01862049c0f7744cf4dfac371ce780fb24dhanji private final ExecutorService executor; 3865888c01862049c0f7744cf4dfac371ce780fb24dhanji 3965888c01862049c0f7744cf4dfac371ce780fb24dhanji private volatile State state; 4065888c01862049c0f7744cf4dfac371ce780fb24dhanji 4165888c01862049c0f7744cf4dfac371ce780fb24dhanji public AsyncService(ExecutorService executor) { 4265888c01862049c0f7744cf4dfac371ce780fb24dhanji this.executor = executor; 4365888c01862049c0f7744cf4dfac371ce780fb24dhanji } 4465888c01862049c0f7744cf4dfac371ce780fb24dhanji 4565888c01862049c0f7744cf4dfac371ce780fb24dhanji public synchronized final Future<State> start() { 4665888c01862049c0f7744cf4dfac371ce780fb24dhanji Preconditions.checkState(state != State.STOPPED, 4765888c01862049c0f7744cf4dfac371ce780fb24dhanji "Cannot restart a service that has been stopped"); 4865888c01862049c0f7744cf4dfac371ce780fb24dhanji 4965888c01862049c0f7744cf4dfac371ce780fb24dhanji // Starts are idempotent. 5065888c01862049c0f7744cf4dfac371ce780fb24dhanji if (state == State.STARTED) { 511a30c07469f896097c1311e039ca3066873f5db9cgdecker return new FutureTask<State>(DO_NOTHING, State.STARTED); 5265888c01862049c0f7744cf4dfac371ce780fb24dhanji } 5365888c01862049c0f7744cf4dfac371ce780fb24dhanji 544ccf2a3077e701e089cc8d26c831ec493319b37adhanji return executor.submit(new Callable<State>() { 5565888c01862049c0f7744cf4dfac371ce780fb24dhanji public State call() { 5665888c01862049c0f7744cf4dfac371ce780fb24dhanji onStart(); 5765888c01862049c0f7744cf4dfac371ce780fb24dhanji return state = State.STARTED; 5865888c01862049c0f7744cf4dfac371ce780fb24dhanji } 5965888c01862049c0f7744cf4dfac371ce780fb24dhanji }); 6065888c01862049c0f7744cf4dfac371ce780fb24dhanji } 6165888c01862049c0f7744cf4dfac371ce780fb24dhanji 6265888c01862049c0f7744cf4dfac371ce780fb24dhanji /** 6365888c01862049c0f7744cf4dfac371ce780fb24dhanji * Called back when this service must do its start work. Typically occurs 6465888c01862049c0f7744cf4dfac371ce780fb24dhanji * in a background thread. The result of this method is returned to the 6565888c01862049c0f7744cf4dfac371ce780fb24dhanji * original caller of {@link Service#start()} and can thus be used to 6665888c01862049c0f7744cf4dfac371ce780fb24dhanji * return a status message after start completes (or fails as the case 6765888c01862049c0f7744cf4dfac371ce780fb24dhanji * may be). 6865888c01862049c0f7744cf4dfac371ce780fb24dhanji */ 6965888c01862049c0f7744cf4dfac371ce780fb24dhanji protected abstract void onStart(); 7065888c01862049c0f7744cf4dfac371ce780fb24dhanji 7165888c01862049c0f7744cf4dfac371ce780fb24dhanji public synchronized final Future<State> stop() { 7265888c01862049c0f7744cf4dfac371ce780fb24dhanji Preconditions.checkState(state != null, "Must start this service before you stop it!"); 7365888c01862049c0f7744cf4dfac371ce780fb24dhanji 7465888c01862049c0f7744cf4dfac371ce780fb24dhanji // Likewise, stops are idempotent. 7565888c01862049c0f7744cf4dfac371ce780fb24dhanji if (state == State.STOPPED) { 761a30c07469f896097c1311e039ca3066873f5db9cgdecker return new FutureTask<State>(DO_NOTHING, State.STOPPED); 7765888c01862049c0f7744cf4dfac371ce780fb24dhanji } 7865888c01862049c0f7744cf4dfac371ce780fb24dhanji 794ccf2a3077e701e089cc8d26c831ec493319b37adhanji return executor.submit(new Callable<State>() { 8065888c01862049c0f7744cf4dfac371ce780fb24dhanji public State call() { 8165888c01862049c0f7744cf4dfac371ce780fb24dhanji onStop(); 8265888c01862049c0f7744cf4dfac371ce780fb24dhanji return state = State.STOPPED; 8365888c01862049c0f7744cf4dfac371ce780fb24dhanji } 8465888c01862049c0f7744cf4dfac371ce780fb24dhanji }); 8565888c01862049c0f7744cf4dfac371ce780fb24dhanji } 8665888c01862049c0f7744cf4dfac371ce780fb24dhanji 8765888c01862049c0f7744cf4dfac371ce780fb24dhanji /** 8865888c01862049c0f7744cf4dfac371ce780fb24dhanji * Called back when this service must shutdown. Typically occurs 8965888c01862049c0f7744cf4dfac371ce780fb24dhanji * in a background thread. The result of this method is returned to the 9065888c01862049c0f7744cf4dfac371ce780fb24dhanji * original caller of {@link Service#stop()} and can thus be used to 9165888c01862049c0f7744cf4dfac371ce780fb24dhanji * return a status message after stop completes (or fails as the case 9265888c01862049c0f7744cf4dfac371ce780fb24dhanji * may be). 9365888c01862049c0f7744cf4dfac371ce780fb24dhanji */ 9465888c01862049c0f7744cf4dfac371ce780fb24dhanji protected abstract void onStop(); 9565888c01862049c0f7744cf4dfac371ce780fb24dhanji 9665888c01862049c0f7744cf4dfac371ce780fb24dhanji public final State state() { 9765888c01862049c0f7744cf4dfac371ce780fb24dhanji return state; 9865888c01862049c0f7744cf4dfac371ce780fb24dhanji } 9965888c01862049c0f7744cf4dfac371ce780fb24dhanji} 100