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