1/**
2 * Copyright (C) 2010 Google Inc.
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.inject.service;
18
19import com.google.common.base.Preconditions;
20
21import java.util.concurrent.Callable;
22import java.util.concurrent.ExecutorService;
23import java.util.concurrent.Future;
24import java.util.concurrent.FutureTask;
25
26/**
27 * An asynchronous implementation of {@link com.google.inject.service.Service}
28 * that provides convenience callbacks to create your own services.
29 *
30 * @author dhanji@gmail.com (Dhanji R. Prasanna)
31 */
32public abstract class AsyncService implements Service {
33  private static final Runnable DO_NOTHING = new Runnable() {
34    @Override public void run() {}
35  };
36
37  private final ExecutorService executor;
38
39  private volatile State state;
40
41  public AsyncService(ExecutorService executor) {
42    this.executor = executor;
43  }
44
45  public synchronized final Future<State> start() {
46    Preconditions.checkState(state != State.STOPPED,
47        "Cannot restart a service that has been stopped");
48
49    // Starts are idempotent.
50    if (state == State.STARTED) {
51      return new FutureTask<State>(DO_NOTHING, State.STARTED);
52    }
53
54    return executor.submit(new Callable<State>() {
55      public State call() {
56        onStart();
57        return state = State.STARTED;
58      }
59    });
60  }
61
62  /**
63   * Called back when this service must do its start work. Typically occurs
64   * in a background thread. The result of this method is returned to the
65   * original caller of {@link Service#start()} and can thus be used to
66   * return a status message after start completes (or fails as the case
67   * may be).
68   */
69  protected abstract void onStart();
70
71  public synchronized final Future<State> stop() {
72    Preconditions.checkState(state != null, "Must start this service before you stop it!");
73
74    // Likewise, stops are idempotent.
75    if (state == State.STOPPED) {
76      return new FutureTask<State>(DO_NOTHING, State.STOPPED);
77    }
78
79    return executor.submit(new Callable<State>() {
80      public State call() {
81        onStop();
82        return state = State.STOPPED;
83      }
84    });
85  }
86
87  /**
88   * Called back when this service must shutdown. Typically occurs
89   * in a background thread. The result of this method is returned to the
90   * original caller of {@link Service#stop()} and can thus be used to
91   * return a status message after stop completes (or fails as the case
92   * may be).
93   */
94  protected abstract void onStop();
95
96  public final State state() {
97    return state;
98  }
99}
100