You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@twill.apache.org by ch...@apache.org on 2015/05/06 05:55:26 UTC

[2/4] incubator-twill git commit: (TWILL-69) Removed guava dependencies from twill-api and twill-common modules

(TWILL-69) Removed guava dependencies from twill-api and twill-common modules

Following changes are backward incompatible:
- TwillController no longer extends from Guava Service
  - No more start() method. stopAndWait() becomes terminate()
- TwillRunnerService no longer extends from Guava Service
  - Only has the blocking start() and stop() for start and stop.
- Classes moved from twill-common to twill-core, hence no long public
  - o.a.t.common.Services
  - o.a.t.common.ServiceListenerAdapter
  - o.a.t.common.CompositeService
  - o.a.t.common.DefaultResourceReport

Modified all unit-tests and examples to use the new API


Project: http://git-wip-us.apache.org/repos/asf/incubator-twill/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-twill/commit/0d217b6d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-twill/tree/0d217b6d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-twill/diff/0d217b6d

Branch: refs/heads/feature/TWILL-69
Commit: 0d217b6d499a901c2a62a5856a042130378be8ca
Parents: ae24a04
Author: Terence Yim <ch...@apache.org>
Authored: Mon May 4 19:23:37 2015 -0700
Committer: Terence Yim <ch...@apache.org>
Committed: Tue May 5 13:48:33 2015 -0700

----------------------------------------------------------------------
 pom.xml                                         |   2 +
 twill-api/pom.xml                               |   4 -
 .../apache/twill/api/AbstractTwillRunnable.java |   8 +-
 .../main/java/org/apache/twill/api/Command.java |  52 ++++---
 .../java/org/apache/twill/api/EventHandler.java |   8 +-
 .../main/java/org/apache/twill/api/Hosts.java   |  15 +-
 .../main/java/org/apache/twill/api/Racks.java   |  16 +-
 .../org/apache/twill/api/ServiceController.java |  67 +++++---
 .../org/apache/twill/api/TwillController.java   |   7 +-
 .../twill/api/TwillRunnableSpecification.java   |   6 +-
 .../apache/twill/api/TwillRunnerService.java    |  20 ++-
 .../apache/twill/api/TwillSpecification.java    |  79 +++++-----
 .../apache/twill/api/logging/LogHandler.java    |   5 +-
 .../twill/api/logging/PrinterLogHandler.java    |   8 +-
 .../DefaultEventHandlerSpecification.java       |   5 +-
 .../twill/internal/DefaultResourceReport.java   | 151 -------------------
 .../internal/DefaultRuntimeSpecification.java   |   5 +-
 .../DefaultTwillRunnableSpecification.java      |   7 +-
 .../internal/DefaultTwillSpecification.java     |  46 +++---
 .../java/org/apache/twill/internal/RunIds.java  |   5 +-
 twill-common/pom.xml                            |   4 -
 .../apache/twill/common/CompositeService.java   | 109 -------------
 .../twill/common/ServiceListenerAdapter.java    |  50 ------
 .../java/org/apache/twill/common/Services.java  | 140 -----------------
 .../java/org/apache/twill/common/Threads.java   |  32 ++--
 .../apache/twill/filesystem/LocalLocation.java  |  16 +-
 .../twill/filesystem/LocationFactories.java     |   6 +-
 .../twill/common/CompositeServiceTest.java      | 145 ------------------
 .../org/apache/twill/common/ServicesTest.java   | 106 -------------
 .../AbstractExecutionServiceController.java     |  68 ++++++++-
 .../apache/twill/internal/CompositeService.java | 109 +++++++++++++
 .../twill/internal/DefaultResourceReport.java   | 151 +++++++++++++++++++
 .../twill/internal/ServiceListenerAdapter.java  |  50 ++++++
 .../org/apache/twill/internal/Services.java     | 141 +++++++++++++++++
 .../internal/TwillContainerController.java      |   3 +-
 .../twill/internal/logging/KafkaAppender.java   |   2 +-
 .../twill/internal/CompositeServiceTest.java    | 145 ++++++++++++++++++
 .../apache/twill/internal/ControllerTest.java   |  35 ++---
 .../org/apache/twill/internal/ServicesTest.java | 106 +++++++++++++
 .../apache/twill/kafka/client/KafkaTest.java    |   2 +-
 .../twill/discovery/ZKDiscoveryServiceTest.java |   5 +-
 .../twill/example/yarn/BundledJarExample.java   |  15 +-
 .../apache/twill/example/yarn/HelloWorld.java   |  15 +-
 .../java/org/apache/twill/test/Java8Test.java   |   5 +-
 .../org/apache/twill/internal/ServiceMain.java  |   4 -
 .../internal/appmaster/RunningContainers.java   |   6 +-
 .../twill/yarn/YarnTwillRunnerService.java      |  58 ++++---
 .../org/apache/twill/yarn/BaseYarnTest.java     |   2 +-
 .../apache/twill/yarn/ContainerSizeTestRun.java |   7 +-
 .../org/apache/twill/yarn/DebugTestRun.java     |  17 +--
 .../twill/yarn/DistributeShellTestRun.java      |  12 +-
 .../apache/twill/yarn/EchoServerTestRun.java    |  11 +-
 .../twill/yarn/FailureRestartTestRun.java       |   3 +-
 .../twill/yarn/InitializeFailTestRun.java       |   3 +-
 .../org/apache/twill/yarn/LocalFileTestRun.java |   2 +-
 .../apache/twill/yarn/LogHandlerTestRun.java    |   5 +-
 .../twill/yarn/PlacementPolicyTestRun.java      |  17 ++-
 .../twill/yarn/ProvisionTimeoutTestRun.java     |   3 +-
 .../twill/yarn/ResourceReportTestRun.java       |  19 ++-
 .../twill/yarn/ServiceDiscoveryTestRun.java     |  11 +-
 .../apache/twill/yarn/SessionExpireTestRun.java |  15 +-
 .../org/apache/twill/yarn/SocketServer.java     |   6 -
 .../apache/twill/yarn/TaskCompletedTestRun.java |  20 +--
 .../org/apache/twill/yarn/YarnTestUtils.java    |  20 +--
 64 files changed, 1158 insertions(+), 1059 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 9f923c3..e079273 100644
--- a/pom.xml
+++ b/pom.xml
@@ -278,6 +278,7 @@
                             <exclude>**/README</exclude>
                             <exclude>src/test/resources/header.txt</exclude>
                             <exclude>**/zookeeper.out</exclude>
+                            <exclude>twill-java8-test/target/**</exclude>
                         </excludes>
                     </configuration>
                     <executions>
@@ -748,6 +749,7 @@
                 <groupId>com.google.code.findbugs</groupId>
                 <artifactId>jsr305</artifactId>
                 <version>${findbugs.jsr305.version}</version>
+                <optional>true</optional>
             </dependency>
             <dependency>
                 <groupId>com.google.code.gson</groupId>

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/pom.xml
----------------------------------------------------------------------
diff --git a/twill-api/pom.xml b/twill-api/pom.xml
index 1354d7a..f36444e 100644
--- a/twill-api/pom.xml
+++ b/twill-api/pom.xml
@@ -43,10 +43,6 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-        </dependency>
-        <dependency>
             <groupId>com.google.code.findbugs</groupId>
             <artifactId>jsr305</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/api/AbstractTwillRunnable.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/AbstractTwillRunnable.java b/twill-api/src/main/java/org/apache/twill/api/AbstractTwillRunnable.java
index 614099d..a17c578 100644
--- a/twill-api/src/main/java/org/apache/twill/api/AbstractTwillRunnable.java
+++ b/twill-api/src/main/java/org/apache/twill/api/AbstractTwillRunnable.java
@@ -17,8 +17,8 @@
  */
 package org.apache.twill.api;
 
-import com.google.common.collect.ImmutableMap;
-
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -30,11 +30,11 @@ public abstract class AbstractTwillRunnable implements TwillRunnable {
   private TwillContext context;
 
   protected AbstractTwillRunnable() {
-    this.args = ImmutableMap.of();
+    this(Collections.<String, String>emptyMap());
   }
 
   protected AbstractTwillRunnable(Map<String, String> args) {
-    this.args = ImmutableMap.copyOf(args);
+    this.args = Collections.unmodifiableMap(new HashMap<String, String>(args));
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/api/Command.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/Command.java b/twill-api/src/main/java/org/apache/twill/api/Command.java
index b23b3a8..5200aeb 100644
--- a/twill-api/src/main/java/org/apache/twill/api/Command.java
+++ b/twill-api/src/main/java/org/apache/twill/api/Command.java
@@ -17,10 +17,8 @@
  */
 package org.apache.twill.api;
 
-import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
-
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -35,13 +33,15 @@ public interface Command {
   /**
    * Builder for creating {@link Command} object.
    */
-  static final class Builder {
+  final class Builder {
 
     private final String command;
-    private final ImmutableMap.Builder<String, String> options = ImmutableMap.builder();
+    private final Map<String, String> options = new HashMap<String, String>();
 
     public static Builder of(String command) {
-      Preconditions.checkArgument(command != null, "Command cannot be null.");
+      if (command == null) {
+        throw new IllegalArgumentException("Command cannot be null.");
+      }
       return new Builder(command);
     }
 
@@ -56,7 +56,7 @@ public interface Command {
     }
 
     public Command build() {
-      return new SimpleCommand(command, options.build());
+      return new SimpleCommand(command, Collections.unmodifiableMap(new HashMap<String, String>(options)));
     }
 
     private Builder(String command) {
@@ -86,28 +86,32 @@ public interface Command {
       }
 
       @Override
-      public int hashCode() {
-        return Objects.hashCode(command, options);
+      public boolean equals(Object o) {
+        if (this == o) {
+          return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+          return false;
+        }
+
+        SimpleCommand that = (SimpleCommand) o;
+        return command.equals(that.command) && options.equals(that.options);
+
       }
 
       @Override
-      public String toString() {
-        return Objects.toStringHelper(Command.class)
-          .add("command", command)
-          .add("options", options)
-          .toString();
+      public int hashCode() {
+        int result = command.hashCode();
+        result = 31 * result + options.hashCode();
+        return result;
       }
 
       @Override
-      public boolean equals(Object obj) {
-        if (obj == this) {
-          return true;
-        }
-        if (!(obj instanceof Command)) {
-          return false;
-        }
-        Command other = (Command) obj;
-        return command.equals(other.getCommand()) && options.equals(other.getOptions());
+      public String toString() {
+        return "SimpleCommand{" +
+          "command='" + command + '\'' +
+          ", options=" + options +
+          '}';
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/api/EventHandler.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/EventHandler.java b/twill-api/src/main/java/org/apache/twill/api/EventHandler.java
index ede5b65..a19c0b3 100644
--- a/twill-api/src/main/java/org/apache/twill/api/EventHandler.java
+++ b/twill-api/src/main/java/org/apache/twill/api/EventHandler.java
@@ -17,8 +17,7 @@
  */
 package org.apache.twill.api;
 
-import com.google.common.collect.ImmutableMap;
-
+import java.util.Collections;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
@@ -117,7 +116,8 @@ public abstract class EventHandler {
 
   /**
    * Invoked by the application to initialize this EventHandler instance.
-   * @param context
+   *
+   * @param context context object for accessing the event handler execution context.
    */
   public void initialize(EventHandlerContext context) {
     this.context = context;
@@ -141,6 +141,6 @@ public abstract class EventHandler {
    * Returns set of configurations available at runtime for access.
    */
   protected Map<String, String> getConfigs() {
-    return ImmutableMap.of();
+    return Collections.emptyMap();
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/api/Hosts.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/Hosts.java b/twill-api/src/main/java/org/apache/twill/api/Hosts.java
index 90a27ad..89e4df4 100644
--- a/twill-api/src/main/java/org/apache/twill/api/Hosts.java
+++ b/twill-api/src/main/java/org/apache/twill/api/Hosts.java
@@ -17,9 +17,9 @@
  */
 package org.apache.twill.api;
 
-import com.google.common.collect.ImmutableSet;
-
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Set;
 
 /**
@@ -30,14 +30,15 @@ public class Hosts {
   private final Set<String> hosts;
 
   public Hosts(Set<String> hosts) {
-    this.hosts = ImmutableSet.copyOf(hosts);
+    this.hosts = Collections.unmodifiableSet(new HashSet<String>(hosts));
   }
 
   public Hosts(String host, String...moreHosts) {
-    this.hosts = ImmutableSet.<String>builder()
-      .add(host)
-      .addAll(Arrays.asList(moreHosts))
-      .build();
+    Set<String> hosts = new HashSet<String>();
+    hosts.add(host);
+    hosts.addAll(Arrays.asList(moreHosts));
+
+    this.hosts = Collections.unmodifiableSet(hosts);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/api/Racks.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/Racks.java b/twill-api/src/main/java/org/apache/twill/api/Racks.java
index 04eedd0..1235293 100644
--- a/twill-api/src/main/java/org/apache/twill/api/Racks.java
+++ b/twill-api/src/main/java/org/apache/twill/api/Racks.java
@@ -17,9 +17,9 @@
  */
 package org.apache.twill.api;
 
-import com.google.common.collect.ImmutableSet;
-
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Set;
 
 /**
@@ -30,14 +30,16 @@ public class Racks {
   private final Set<String> racks;
 
   public Racks(Set<String> racks) {
-    this.racks = ImmutableSet.copyOf(racks);
+    this.racks = Collections.unmodifiableSet(new HashSet<String>(racks));
   }
 
   public Racks(String rack, String...moreRacks) {
-    this.racks = ImmutableSet.<String>builder()
-      .add(rack)
-      .addAll(Arrays.asList(moreRacks))
-      .build();
+    Set<String> racks = new HashSet<String>();
+    racks.add(rack);
+    racks.addAll(Arrays.asList(moreRacks));
+
+    this.racks = Collections.unmodifiableSet(racks);
+
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/api/ServiceController.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/ServiceController.java b/twill-api/src/main/java/org/apache/twill/api/ServiceController.java
index 0ea64f9..1ea86b2 100644
--- a/twill-api/src/main/java/org/apache/twill/api/ServiceController.java
+++ b/twill-api/src/main/java/org/apache/twill/api/ServiceController.java
@@ -17,15 +17,16 @@
  */
 package org.apache.twill.api;
 
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.Service;
-
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
  * This interface is for controlling a remote running service.
  */
-public interface ServiceController extends Service {
+public interface ServiceController {
 
   /**
    * Returns the {@link RunId} of the running application.
@@ -35,19 +36,30 @@ public interface ServiceController extends Service {
   /**
    * Sends a user command to the running application.
    * @param command The command to send.
-   * @return A {@link ListenableFuture} that will be completed when the command is successfully processed
+   * @return A {@link Future} that will be completed when the command is successfully processed
    *         by the target application.
    */
-  ListenableFuture<Command> sendCommand(Command command);
+  Future<Command> sendCommand(Command command);
 
   /**
    * Sends a user command to the given runnable of the running application.
    * @param runnableName Name of the {@link TwillRunnable}.
    * @param command The command to send.
-   * @return A {@link ListenableFuture} that will be completed when the command is successfully processed
+   * @return A {@link Future} that will be completed when the command is successfully processed
    *         by the target runnable.
    */
-  ListenableFuture<Command> sendCommand(String runnableName, Command command);
+  Future<Command> sendCommand(String runnableName, Command command);
+
+  /**
+   * Requests to terminate the running service. The service will be given chance to shutdown gracefully.
+   * This method returns immediately and caller can get the termination state through the future returned.
+   * Calling this method multiple times is allowed and a {@link Future} representing the termination state
+   * will be returned.
+   *
+   * @return a {@link Future} that represents the termination of the service. The future result will be
+   * this {@link ServiceController}. If the service terminated due to exception, the future will carry the exception.
+   */
+  Future<? extends ServiceController> terminate();
 
   /**
    * Requests to forcefully kill a running service.
@@ -55,16 +67,35 @@ public interface ServiceController extends Service {
   void kill();
 
   /**
-   * Registers a {@link Listener} to be {@linkplain Executor#execute executed} on the given
-   * executor.  The listener will have the corresponding transition method called whenever the
-   * service changes state. When added, the current state of the service will be reflected through
-   * callback to the listener. Methods on the listener is guaranteed to be called no more than once.
+   * Attaches a {@link Runnable} that will get executed when the service is running.
+   *
+   * @param runnable the {@link Runnable} to be executed when the service is running.
+   * @param executor the executor in which the runnable will be executed with.
+   */
+  void onRunning(Runnable runnable, Executor executor);
+
+  /**
+   * Attaches a {@link Runnable} that will get executed when the serivce is terminated.
+   *
+   * @param runnable the {@link Runnable} to be executed when the service is terminated.
+   * @param executor the executor in which the runnable will be executed with.
+   */
+  void onTerminated(Runnable runnable, Executor executor);
+
+  /**
+   * Waits for termination of the remote service.
+   *
+   * @throws ExecutionException if the service terminated due to exception.
+   */
+  void awaitTerminated() throws ExecutionException;
+
+  /**
+   * Waits for termination of the remote service for no more than the given timeout limit.
    *
-   * @param listener the listener to run when the service changes state is complete
-   * @param executor the executor in which the the listeners callback methods will be run. For fast,
-   *     lightweight listeners that would be safe to execute in any thread, consider
-   *     {@link com.google.common.util.concurrent.MoreExecutors#sameThreadExecutor}.
+   * @param timeout the maximum time to wait
+   * @param timeoutUnit the time unit of the timeout
+   * @throws TimeoutException if the service is not terminated within the given time.
+   * @throws ExecutionException if the service terminated due to exception.
    */
-  @Override
-  void addListener(Listener listener, Executor executor);
+  void awaitTerminated(long timeout, TimeUnit timeoutUnit) throws TimeoutException, ExecutionException;
 }

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/api/TwillController.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/TwillController.java b/twill-api/src/main/java/org/apache/twill/api/TwillController.java
index 7c5089d..65b9b2d 100644
--- a/twill-api/src/main/java/org/apache/twill/api/TwillController.java
+++ b/twill-api/src/main/java/org/apache/twill/api/TwillController.java
@@ -17,11 +17,12 @@
  */
 package org.apache.twill.api;
 
-import com.google.common.util.concurrent.ListenableFuture;
 import org.apache.twill.api.logging.LogHandler;
 import org.apache.twill.discovery.Discoverable;
 import org.apache.twill.discovery.ServiceDiscovered;
 
+import java.util.concurrent.Future;
+
 /**
  * For controlling a running application.
  */
@@ -46,11 +47,11 @@ public interface TwillController extends ServiceController {
    *
    * @param runnable The name of the runnable.
    * @param newCount Number of instances for the given runnable.
-   * @return A {@link ListenableFuture} that will be completed when the number running instances has been
+   * @return A {@link Future} that will be completed when the number running instances has been
    *         successfully changed. The future will carry the new count as the result. If there is any error
    *         while changing instances, it'll be reflected in the future.
    */
-  ListenableFuture<Integer> changeInstances(String runnable, int newCount);
+  Future<Integer> changeInstances(String runnable, int newCount);
 
   /**
    * Get a snapshot of the resources used by the application, broken down by each runnable.

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/api/TwillRunnableSpecification.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/TwillRunnableSpecification.java b/twill-api/src/main/java/org/apache/twill/api/TwillRunnableSpecification.java
index d161f9d..fe85d0b 100644
--- a/twill-api/src/main/java/org/apache/twill/api/TwillRunnableSpecification.java
+++ b/twill-api/src/main/java/org/apache/twill/api/TwillRunnableSpecification.java
@@ -17,9 +17,9 @@
  */
 package org.apache.twill.api;
 
-import com.google.common.collect.ImmutableMap;
 import org.apache.twill.internal.DefaultTwillRunnableSpecification;
 
+import java.util.Collections;
 import java.util.Map;
 
 /**
@@ -36,7 +36,7 @@ public interface TwillRunnableSpecification {
   /**
    * Builder for constructing {@link TwillRunnableSpecification}.
    */
-  static final class Builder {
+  final class Builder {
 
     private String name;
     private Map<String, String> args;
@@ -59,7 +59,7 @@ public interface TwillRunnableSpecification {
       }
 
       public AfterConfigs noConfigs() {
-        Builder.this.args = ImmutableMap.of();
+        Builder.this.args = Collections.emptyMap();
         return new AfterConfigs();
       }
     }

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/api/TwillRunnerService.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/TwillRunnerService.java b/twill-api/src/main/java/org/apache/twill/api/TwillRunnerService.java
index 76ec136..77d2c42 100644
--- a/twill-api/src/main/java/org/apache/twill/api/TwillRunnerService.java
+++ b/twill-api/src/main/java/org/apache/twill/api/TwillRunnerService.java
@@ -17,13 +17,25 @@
  */
 package org.apache.twill.api;
 
-import com.google.common.util.concurrent.Service;
-
 /**
- * A {@link TwillRunner} that extends {@link Service} to provide lifecycle management functions.
+ * A {@link TwillRunner} that provides lifecycle management functions.
  * The {@link #start()} method needs to be called before calling any other method of this interface.
  * When done with this service, call {@link #stop()} to release any resources that it holds.
  */
-public interface TwillRunnerService extends TwillRunner, Service {
+public interface TwillRunnerService extends TwillRunner {
+
+  /**
+   * Starts the service. Calling this method on a already started instance has no effect.
+   * A service that is stopped cannot be started again.
+   *
+   * @throws RuntimeException if the service failed to start.
+   */
+  void start();
 
+  /**
+   * Stops the service. Calling this method on a already stopped instance has no effect.
+   *
+   * @throws RuntimeException if the service failed to start.
+   */
+  void stop();
 }

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/api/TwillSpecification.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/TwillSpecification.java b/twill-api/src/main/java/org/apache/twill/api/TwillSpecification.java
index ed37190..a689529 100644
--- a/twill-api/src/main/java/org/apache/twill/api/TwillSpecification.java
+++ b/twill-api/src/main/java/org/apache/twill/api/TwillSpecification.java
@@ -17,12 +17,6 @@
  */
 package org.apache.twill.api;
 
-import com.google.common.base.Function;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
 import org.apache.twill.internal.DefaultLocalFile;
 import org.apache.twill.internal.DefaultRuntimeSpecification;
 import org.apache.twill.internal.DefaultTwillRunnableSpecification;
@@ -30,7 +24,11 @@ import org.apache.twill.internal.DefaultTwillSpecification;
 
 import java.io.File;
 import java.net.URI;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -129,12 +127,12 @@ public interface TwillSpecification {
   /**
    * Builder for constructing instance of {@link TwillSpecification}.
    */
-  static final class Builder {
+  final class Builder {
 
     private String name;
-    private Map<String, RuntimeSpecification> runnables = Maps.newHashMap();
-    private List<Order> orders = Lists.newArrayList();
-    private List<PlacementPolicy> placementPolicies = Lists.newArrayList();
+    private Map<String, RuntimeSpecification> runnables = new HashMap<String, RuntimeSpecification>();
+    private List<Order> orders = new ArrayList<Order>();
+    private List<PlacementPolicy> placementPolicies = new ArrayList<PlacementPolicy>();
     private EventHandlerSpecification eventHandler;
 
     public static NameSetter with() {
@@ -200,9 +198,9 @@ public interface TwillSpecification {
                                            final ResourceSpecification resourceSpec) {
         final TwillRunnableSpecification spec = new DefaultTwillRunnableSpecification(
                                             runnable.getClass().getName(), name, runnable.configure().getConfigs());
-        return new RuntimeSpecificationAdder(new Function<Collection<LocalFile>, RunnableSetter>() {
+        return new RuntimeSpecificationAdder(new LocalFileCompleter() {
           @Override
-          public RunnableSetter apply(Collection<LocalFile> files) {
+          public RunnableSetter complete(Collection<LocalFile> files) {
             runnables.put(spec.getName(), new DefaultRuntimeSpecification(spec.getName(), spec, resourceSpec, files));
             return RunnableSetter.this;
           }
@@ -226,13 +224,20 @@ public interface TwillSpecification {
     }
 
     /**
+     * Internal interface for completing addition of {@link LocalFile} to a runnable.
+     */
+    private interface LocalFileCompleter {
+      RunnableSetter complete(Collection<LocalFile> files);
+    }
+
+    /**
      * For setting runtime specific settings.
      */
     public final class RuntimeSpecificationAdder {
 
-      private final Function<Collection<LocalFile>, RunnableSetter> completer;
+      private final LocalFileCompleter completer;
 
-      RuntimeSpecificationAdder(Function<Collection<LocalFile>, RunnableSetter> completer) {
+      RuntimeSpecificationAdder(LocalFileCompleter completer) {
         this.completer = completer;
       }
 
@@ -241,7 +246,7 @@ public interface TwillSpecification {
       }
 
       public RunnableSetter noLocalFiles() {
-        return completer.apply(ImmutableList.<LocalFile>of());
+        return completer.complete(Collections.<LocalFile>emptyList());
       }
     }
 
@@ -261,10 +266,10 @@ public interface TwillSpecification {
 
     public final class MoreFile implements LocalFileAdder {
 
-      private final Function<Collection<LocalFile>, RunnableSetter> completer;
-      private final List<LocalFile> files = Lists.newArrayList();
+      private final LocalFileCompleter completer;
+      private final List<LocalFile> files = new ArrayList<LocalFile>();
 
-      public MoreFile(Function<Collection<LocalFile>, RunnableSetter> completer) {
+      public MoreFile(LocalFileCompleter completer) {
         this.completer = completer;
       }
 
@@ -301,7 +306,7 @@ public interface TwillSpecification {
       }
 
       public RunnableSetter apply() {
-        return completer.apply(files);
+        return completer.complete(files);
       }
     }
 
@@ -387,16 +392,16 @@ public interface TwillSpecification {
 
       private PlacementPolicySetter addPlacementPolicy(PlacementPolicy.Type type, Hosts hosts, Racks racks,
                                                        String runnableName, String...runnableNames) {
-        Preconditions.checkArgument(runnableName != null, "Name cannot be null.");
-        Preconditions.checkArgument(runnables.containsKey(runnableName), "Runnable not exists.");
-        Preconditions.checkArgument(!contains(runnableName),
-                                    "Runnable (" + runnableName + ") cannot belong to more than one Placement Policy");
-        Set<String> runnableNamesSet = Sets.newHashSet(runnableName);
+        checkArgument(runnableName != null, "Name cannot be null.");
+        checkArgument(runnables.containsKey(runnableName), "Runnable not exists.");
+        checkArgument(!contains(runnableName),
+                      "Runnable (" + runnableName + ") cannot belong to more than one Placement Policy");
+        Set<String> runnableNamesSet = new HashSet<String>(Collections.singleton(runnableName));
         for (String name : runnableNames) {
-          Preconditions.checkArgument(name != null, "Name cannot be null.");
-          Preconditions.checkArgument(runnables.containsKey(name), "Runnable not exists.");
-          Preconditions.checkArgument(!contains(name),
-                                      "Runnable (" + name + ") cannot belong to more than one Placement Policy");
+          checkArgument(name != null, "Name cannot be null.");
+          checkArgument(runnables.containsKey(name), "Runnable not exists.");
+          checkArgument(!contains(name),
+                        "Runnable (" + name + ") cannot belong to more than one Placement Policy");
           runnableNamesSet.add(name);
         }
         placementPolicies.add(
@@ -468,7 +473,7 @@ public interface TwillSpecification {
       @Override
       public TwillSpecification build() {
         // Set to track with runnable hasn't been assigned an order.
-        Set<String> runnableNames = Sets.newHashSet(runnables.keySet());
+        Set<String> runnableNames = new HashSet<String>(runnables.keySet());
         for (Order order : orders) {
           runnableNames.removeAll(order.getNames());
         }
@@ -479,13 +484,13 @@ public interface TwillSpecification {
       }
 
       private void addOrder(final Order.Type type, String name, String...names) {
-        Preconditions.checkArgument(name != null, "Name cannot be null.");
-        Preconditions.checkArgument(runnables.containsKey(name), "Runnable not exists.");
+        checkArgument(name != null, "Name cannot be null.");
+        checkArgument(runnables.containsKey(name), "Runnable not exists.");
 
-        Set<String> runnableNames = Sets.newHashSet(name);
+        Set<String> runnableNames = new HashSet<String>(Collections.singleton(name));
         for (String runnableName : names) {
-          Preconditions.checkArgument(name != null, "Name cannot be null.");
-          Preconditions.checkArgument(runnables.containsKey(name), "Runnable not exists.");
+          checkArgument(name != null, "Name cannot be null.");
+          checkArgument(runnables.containsKey(name), "Runnable not exists.");
           runnableNames.add(runnableName);
         }
 
@@ -493,6 +498,12 @@ public interface TwillSpecification {
       }
     }
 
+    private void checkArgument(boolean condition, String msgFormat, Object...args) {
+      if (!condition) {
+        throw new IllegalArgumentException(String.format(msgFormat, args));
+      }
+    }
+
     private Builder() {}
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/api/logging/LogHandler.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/logging/LogHandler.java b/twill-api/src/main/java/org/apache/twill/api/logging/LogHandler.java
index afded19..70cb25d 100644
--- a/twill-api/src/main/java/org/apache/twill/api/logging/LogHandler.java
+++ b/twill-api/src/main/java/org/apache/twill/api/logging/LogHandler.java
@@ -18,9 +18,12 @@
 package org.apache.twill.api.logging;
 
 /**
- *
+ * Represents class that can receive logs from the application.
  */
 public interface LogHandler {
 
+  /**
+   * Invokes when there is new {@link LogEntry} received from the application.
+   */
   void onLog(LogEntry logEntry);
 }

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/api/logging/PrinterLogHandler.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/api/logging/PrinterLogHandler.java b/twill-api/src/main/java/org/apache/twill/api/logging/PrinterLogHandler.java
index c6d6501..ef3c828 100644
--- a/twill-api/src/main/java/org/apache/twill/api/logging/PrinterLogHandler.java
+++ b/twill-api/src/main/java/org/apache/twill/api/logging/PrinterLogHandler.java
@@ -17,20 +17,22 @@
  */
 package org.apache.twill.api.logging;
 
-import com.google.common.base.Splitter;
-
 import java.io.PrintWriter;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.Formatter;
 import java.util.TimeZone;
+import java.util.regex.Pattern;
 
 /**
  * A {@link LogHandler} that prints the {@link LogEntry} through a {@link PrintWriter}.
  */
 public final class PrinterLogHandler implements LogHandler {
 
+  // A regex for splitting string by ".".
+  private static final Pattern DOT_SPLIT = Pattern.compile("\\.");
+
   private static final ThreadLocal<DateFormat> DATE_FORMAT = new ThreadLocal<DateFormat>() {
     @Override
     protected DateFormat initialValue() {
@@ -99,7 +101,7 @@ public final class PrinterLogHandler implements LogHandler {
   private String getShortenLoggerName(String loggerName) {
     StringBuilder builder = new StringBuilder();
     String previous = null;
-    for (String part : Splitter.on('.').split(loggerName)) {
+    for (String part : DOT_SPLIT.split(loggerName)) {
       if (previous != null) {
         builder.append(previous.charAt(0)).append('.');
       }

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/internal/DefaultEventHandlerSpecification.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/DefaultEventHandlerSpecification.java b/twill-api/src/main/java/org/apache/twill/internal/DefaultEventHandlerSpecification.java
index 83e7c38..e848315 100644
--- a/twill-api/src/main/java/org/apache/twill/internal/DefaultEventHandlerSpecification.java
+++ b/twill-api/src/main/java/org/apache/twill/internal/DefaultEventHandlerSpecification.java
@@ -17,10 +17,11 @@
  */
 package org.apache.twill.internal;
 
-import com.google.common.collect.ImmutableMap;
 import org.apache.twill.api.EventHandler;
 import org.apache.twill.api.EventHandlerSpecification;
 
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -39,7 +40,7 @@ public class DefaultEventHandlerSpecification implements EventHandlerSpecificati
   public DefaultEventHandlerSpecification(EventHandler eventHandler) {
     EventHandlerSpecification spec = eventHandler.configure();
     this.className = eventHandler.getClass().getName();
-    this.configs = ImmutableMap.copyOf(spec.getConfigs());
+    this.configs = Collections.unmodifiableMap(new HashMap<String, String>(spec.getConfigs()));
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/internal/DefaultResourceReport.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/DefaultResourceReport.java b/twill-api/src/main/java/org/apache/twill/internal/DefaultResourceReport.java
deleted file mode 100644
index 767ee45..0000000
--- a/twill-api/src/main/java/org/apache/twill/internal/DefaultResourceReport.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.twill.internal;
-
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Multimaps;
-import com.google.common.collect.SetMultimap;
-import org.apache.twill.api.ResourceReport;
-import org.apache.twill.api.TwillRunResources;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Implementation of {@link org.apache.twill.api.ResourceReport} with some
- * additional methods for maintaining the report.
- */
-public final class DefaultResourceReport implements ResourceReport {
-  private final SetMultimap<String, TwillRunResources> usedResources;
-  private final TwillRunResources appMasterResources;
-  private final String applicationId;
-  private final AtomicReference<List<String>> services;
-
-  public DefaultResourceReport(String applicationId, TwillRunResources masterResources) {
-    this(applicationId, masterResources, ImmutableMap.<String, Collection<TwillRunResources>>of());
-  }
-
-  public DefaultResourceReport(String applicationId, TwillRunResources masterResources,
-                               Map<String, Collection<TwillRunResources>> resources) {
-    this(applicationId, masterResources, resources, ImmutableList.<String>of());
-  }
-
-  public DefaultResourceReport(String applicationId, TwillRunResources masterResources,
-                               Map<String, Collection<TwillRunResources>> resources, List<String> services) {
-    this.applicationId = applicationId;
-    this.appMasterResources = masterResources;
-    this.usedResources = HashMultimap.create();
-    for (Map.Entry<String, Collection<TwillRunResources>> entry : resources.entrySet()) {
-      this.usedResources.putAll(entry.getKey(), entry.getValue());
-    }
-    this.services = new AtomicReference<List<String>>(services);
-  }
-
-  /**
-   * Add resources used by an instance of the runnable.
-   *
-   * @param runnableName name of runnable.
-   * @param resources resources to add.
-   */
-  public void addRunResources(String runnableName, TwillRunResources resources) {
-    usedResources.put(runnableName, resources);
-  }
-
-  /**
-   * Remove the resource corresponding to the given runnable and container.
-   *
-   * @param runnableName name of runnable.
-   * @param containerId container id of the runnable.
-   */
-  public void removeRunnableResources(String runnableName, String containerId) {
-    TwillRunResources toRemove = null;
-    // could be faster if usedResources was a Table, but that makes returning the
-    // report a little more complex, and this does not need to be terribly fast.
-    for (TwillRunResources resources : usedResources.get(runnableName)) {
-      if (resources.getContainerId().equals(containerId)) {
-        toRemove = resources;
-        break;
-      }
-    }
-    usedResources.remove(runnableName, toRemove);
-  }
-
-  /**
-   * Get all the run resources being used by all instances of the specified runnable.
-   *
-   * @param runnableName the runnable name.
-   * @return resources being used by all instances of the runnable.
-   */
-  @Override
-  public Collection<TwillRunResources> getRunnableResources(String runnableName) {
-    return usedResources.get(runnableName);
-  }
-
-  /**
-   * Get all the run resources being used across all runnables.
-   *
-   * @return all run resources used by all instances of all runnables.
-   */
-  @Override
-  public Map<String, Collection<TwillRunResources>> getResources() {
-    return Multimaps.unmodifiableSetMultimap(usedResources).asMap();
-  }
-
-  /**
-   * Get the resources application master is using.
-   *
-   * @return resources being used by the application master.
-   */
-  @Override
-  public TwillRunResources getAppMasterResources() {
-    return appMasterResources;
-  }
-
-  /**
-   * Get the id of the application master.
-   *
-   * @return id of the application master.
-   */
-  @Override
-  public String getApplicationId() {
-    return applicationId;
-  }
-
-  /**
-   * Set the list of services of the application master.
-   *
-   * @param services list of services to set.
-   */
-  public void setServices(List<String> services) {
-    this.services.set(ImmutableList.copyOf(services));
-  }
-
-  /**
-   * Get the list of services of the application master.
-   *
-   * @return list of services of the application master.
-   */
-  @Override
-  public List<String> getServices() {
-    return services.get();
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/internal/DefaultRuntimeSpecification.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/DefaultRuntimeSpecification.java b/twill-api/src/main/java/org/apache/twill/internal/DefaultRuntimeSpecification.java
index 9de81b1..6e7053c 100644
--- a/twill-api/src/main/java/org/apache/twill/internal/DefaultRuntimeSpecification.java
+++ b/twill-api/src/main/java/org/apache/twill/internal/DefaultRuntimeSpecification.java
@@ -17,13 +17,14 @@
  */
 package org.apache.twill.internal;
 
-import com.google.common.collect.ImmutableList;
 import org.apache.twill.api.LocalFile;
 import org.apache.twill.api.ResourceSpecification;
 import org.apache.twill.api.RuntimeSpecification;
 import org.apache.twill.api.TwillRunnableSpecification;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 
 /**
  * Straightforward implementation of {@link RuntimeSpecification}.
@@ -42,7 +43,7 @@ public final class DefaultRuntimeSpecification implements RuntimeSpecification {
     this.name = name;
     this.runnableSpec = runnableSpec;
     this.resourceSpec = resourceSpec;
-    this.localFiles = ImmutableList.copyOf(localFiles);
+    this.localFiles = Collections.unmodifiableList(new ArrayList<LocalFile>(localFiles));
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillRunnableSpecification.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillRunnableSpecification.java b/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillRunnableSpecification.java
index 0d2eb22..68daef2 100644
--- a/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillRunnableSpecification.java
+++ b/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillRunnableSpecification.java
@@ -17,9 +17,10 @@
  */
 package org.apache.twill.internal;
 
-import com.google.common.collect.ImmutableMap;
 import org.apache.twill.api.TwillRunnableSpecification;
 
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -34,13 +35,13 @@ public final class DefaultTwillRunnableSpecification implements TwillRunnableSpe
   public DefaultTwillRunnableSpecification(String className, String name, Map<String, String> arguments) {
     this.className = className;
     this.name = name;
-    this.arguments = ImmutableMap.copyOf(arguments);
+    this.arguments = Collections.unmodifiableMap(new HashMap<String, String>(arguments));
   }
 
   public DefaultTwillRunnableSpecification(String className, TwillRunnableSpecification other) {
     this.className = className;
     this.name = other.getName();
-    this.arguments = ImmutableMap.copyOf(other.getConfigs());
+    this.arguments = Collections.unmodifiableMap(new HashMap<String, String>(other.getConfigs()));
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillSpecification.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillSpecification.java b/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillSpecification.java
index 184afb3..0cb6688 100644
--- a/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillSpecification.java
+++ b/twill-api/src/main/java/org/apache/twill/internal/DefaultTwillSpecification.java
@@ -17,17 +17,16 @@
  */
 package org.apache.twill.internal;
 
-import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
 import org.apache.twill.api.EventHandlerSpecification;
 import org.apache.twill.api.Hosts;
 import org.apache.twill.api.Racks;
 import org.apache.twill.api.RuntimeSpecification;
 import org.apache.twill.api.TwillSpecification;
 
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -48,8 +47,8 @@ public final class DefaultTwillSpecification implements TwillSpecification {
                                    List<Order> orders, List<PlacementPolicy> placementPolicies,
                                    EventHandlerSpecification eventHandler) {
     this.name = name;
-    this.runnables = ImmutableMap.copyOf(runnables);
-    this.orders = ImmutableList.copyOf(orders);
+    this.runnables = Collections.unmodifiableMap(new HashMap<String, RuntimeSpecification>(runnables));
+    this.orders = Collections.unmodifiableList(new ArrayList<Order>(orders));
     this.placementPolicies = placementPolicies;
     this.eventHandler = eventHandler;
   }
@@ -88,8 +87,8 @@ public final class DefaultTwillSpecification implements TwillSpecification {
     private final Set<String> names;
     private final Type type;
 
-    public DefaultOrder(Iterable<String> names, Type type) {
-      this.names = ImmutableSet.copyOf(names);
+    public DefaultOrder(Set<String> names, Type type) {
+      this.names = Collections.unmodifiableSet(new HashSet<String>(names));
       this.type = type;
     }
 
@@ -105,10 +104,10 @@ public final class DefaultTwillSpecification implements TwillSpecification {
 
     @Override
     public String toString() {
-      return Objects.toStringHelper(this)
-        .add("names", names)
-        .add("type", type)
-        .toString();
+      return "DefaultOrder{" +
+        "names=" + names +
+        ", type=" + type +
+        '}';
     }
   }
 
@@ -122,17 +121,13 @@ public final class DefaultTwillSpecification implements TwillSpecification {
     private final Hosts hosts;
     private final Racks racks;
 
-    public DefaultPlacementPolicy(Iterable<String> names, Type type, Hosts hosts, Racks racks) {
-      this.names = ImmutableSet.copyOf(names);
+    public DefaultPlacementPolicy(Set<String> names, Type type, Hosts hosts, Racks racks) {
+      this.names = Collections.unmodifiableSet(new HashSet<String>(names));
       this.type = type;
       this.hosts = hosts;
       this.racks = racks;
     }
 
-    public DefaultPlacementPolicy(Iterable<String> names, Type type) {
-      this(names, type, null, null);
-    }
-
     /**
      * @return Set of {@link org.apache.twill.api.TwillRunnable} names that belongs to this placement policy.
      */
@@ -171,17 +166,14 @@ public final class DefaultTwillSpecification implements TwillSpecification {
       return this.racks.get();
     }
 
-    /**
-     * @return String representation of Placement Policy
-     */
     @Override
     public String toString() {
-      return Objects.toStringHelper(this)
-        .add("names", names)
-        .add("type", type)
-        .add("hosts", hosts)
-        .add("racks", racks)
-        .toString();
+      return "DefaultPlacementPolicy{" +
+        "hosts=" + hosts +
+        ", names=" + names +
+        ", type=" + type +
+        ", racks=" + racks +
+        '}';
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-api/src/main/java/org/apache/twill/internal/RunIds.java
----------------------------------------------------------------------
diff --git a/twill-api/src/main/java/org/apache/twill/internal/RunIds.java b/twill-api/src/main/java/org/apache/twill/internal/RunIds.java
index b7641f3..4d071d1 100644
--- a/twill-api/src/main/java/org/apache/twill/internal/RunIds.java
+++ b/twill-api/src/main/java/org/apache/twill/internal/RunIds.java
@@ -17,7 +17,6 @@
  */
 package org.apache.twill.internal;
 
-import com.google.common.base.Preconditions;
 import org.apache.twill.api.RunId;
 
 import java.util.UUID;
@@ -43,7 +42,9 @@ public final class RunIds {
     final String id;
 
     private RunIdImpl(String id) {
-      Preconditions.checkArgument(id != null, "RunId cannot be null.");
+      if (id == null) {
+        throw new IllegalArgumentException("RunId cannot be null.");
+      }
       this.id = id;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-common/pom.xml
----------------------------------------------------------------------
diff --git a/twill-common/pom.xml b/twill-common/pom.xml
index bfc6e0c..0d1f338 100644
--- a/twill-common/pom.xml
+++ b/twill-common/pom.xml
@@ -31,10 +31,6 @@
 
     <dependencies>
         <dependency>
-            <groupId>com.google.guava</groupId>
-            <artifactId>guava</artifactId>
-        </dependency>
-        <dependency>
             <groupId>com.google.code.findbugs</groupId>
             <artifactId>jsr305</artifactId>
         </dependency>

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-common/src/main/java/org/apache/twill/common/CompositeService.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/common/CompositeService.java b/twill-common/src/main/java/org/apache/twill/common/CompositeService.java
deleted file mode 100644
index 2817988..0000000
--- a/twill-common/src/main/java/org/apache/twill/common/CompositeService.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.twill.common;
-
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.util.concurrent.AbstractIdleService;
-import com.google.common.util.concurrent.Service;
-import com.google.common.util.concurrent.UncheckedExecutionException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.Iterator;
-
-/**
- * A {@link Service} that starts/stops list of services in order.
- */
-public final class CompositeService extends AbstractIdleService {
-
-  private static final Logger LOG = LoggerFactory.getLogger(CompositeService.class);
-  private final Deque<Service> services;
-
-  public CompositeService(Service...services) {
-    this(ImmutableList.copyOf(services));
-  }
-
-  public CompositeService(Iterable<? extends Service> services) {
-    this.services = new ArrayDeque<Service>();
-    Iterables.addAll(this.services, services);
-  }
-
-  @Override
-  protected void startUp() throws Exception {
-    Throwable failureCause = null;
-
-    for (Service service : services) {
-      try {
-        service.startAndWait();
-      } catch (UncheckedExecutionException e) {
-        failureCause = e.getCause();
-        break;
-      }
-    }
-
-    if (failureCause != null) {
-      // Stop all running services and then throw the failure exception
-      try {
-        stopAll();
-      } catch (Throwable t) {
-        // Ignore the stop error. Just log.
-        LOG.warn("Failed when stopping all services on start failure", t);
-      }
-
-      Throwables.propagateIfPossible(failureCause, Exception.class);
-      throw new RuntimeException(failureCause);
-    }
-  }
-
-  @Override
-  protected void shutDown() throws Exception {
-    stopAll();
-  }
-
-  private void stopAll() throws Exception {
-    Throwable failureCause = null;
-
-    // Stop services in reverse order.
-    Iterator<Service> itor = services.descendingIterator();
-    while (itor.hasNext()) {
-      Service service = itor.next();
-      try {
-        if (service.isRunning() || service.state() == State.STARTING) {
-          service.stopAndWait();
-        }
-      } catch (UncheckedExecutionException e) {
-        // Just catch as we want all services stopped
-        if (failureCause == null) {
-          failureCause = e.getCause();
-        } else {
-          // Log for sub-sequence service shutdown error, as only the first failure cause will be thrown.
-          LOG.warn("Failed to stop service {}", service, e);
-        }
-      }
-    }
-
-    if (failureCause != null) {
-      Throwables.propagateIfPossible(failureCause, Exception.class);
-      throw new RuntimeException(failureCause);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-common/src/main/java/org/apache/twill/common/ServiceListenerAdapter.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/common/ServiceListenerAdapter.java b/twill-common/src/main/java/org/apache/twill/common/ServiceListenerAdapter.java
deleted file mode 100644
index 527ba7d..0000000
--- a/twill-common/src/main/java/org/apache/twill/common/ServiceListenerAdapter.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.twill.common;
-
-import com.google.common.util.concurrent.Service;
-
-/**
- * An adapter for implementing {@link Service.Listener} with all method default to no-op.
- */
-public abstract class ServiceListenerAdapter implements Service.Listener {
-  @Override
-  public void starting() {
-    // No-op
-  }
-
-  @Override
-  public void running() {
-    // No-op
-  }
-
-  @Override
-  public void stopping(Service.State from) {
-    // No-op
-  }
-
-  @Override
-  public void terminated(Service.State from) {
-    // No-op
-  }
-
-  @Override
-  public void failed(Service.State from, Throwable failure) {
-    // No-op
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-common/src/main/java/org/apache/twill/common/Services.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/common/Services.java b/twill-common/src/main/java/org/apache/twill/common/Services.java
deleted file mode 100644
index 7e294f0..0000000
--- a/twill-common/src/main/java/org/apache/twill/common/Services.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.twill.common;
-
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.Service;
-import com.google.common.util.concurrent.SettableFuture;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Utility methods for help dealing with {@link Service}.
- */
-public final class Services {
-
-  /**
-   * Starts a list of {@link Service} one by one. Starting of next Service is triggered from the callback listener
-   * thread of the previous Service.
-   *
-   * @param firstService First service to start.
-   * @param moreServices The rest services to start.
-   * @return A {@link ListenableFuture} that will be completed when all services are started, with the
-   *         result carries the completed {@link ListenableFuture} of each corresponding service in the
-   *         same order as they are passed to this method.
-   */
-  public static ListenableFuture<List<ListenableFuture<Service.State>>> chainStart(Service firstService,
-                                                                                   Service...moreServices) {
-    return doChain(true, firstService, moreServices);
-  }
-
-  /**
-   * Stops a list of {@link Service} one by one. It behaves the same as
-   * {@link #chainStart(com.google.common.util.concurrent.Service, com.google.common.util.concurrent.Service...)}
-   * except {@link com.google.common.util.concurrent.Service#stop()} is called instead of start.
-   *
-   * @param firstService First service to stop.
-   * @param moreServices The rest services to stop.
-   * @return A {@link ListenableFuture} that will be completed when all services are stopped.
-   * @see #chainStart(com.google.common.util.concurrent.Service, com.google.common.util.concurrent.Service...)
-   */
-  public static ListenableFuture<List<ListenableFuture<Service.State>>> chainStop(Service firstService,
-                                                                                  Service...moreServices) {
-    return doChain(false, firstService, moreServices);
-  }
-
-  /**
-   * Returns a {@link ListenableFuture} that will be completed when the given service is stopped. If the service
-   * stopped due to error, the failure cause would be reflected in the future.
-   *
-   * @param service The {@link Service} to block on.
-   * @return A {@link ListenableFuture} that will be completed when the service is stopped.
-   */
-  public static ListenableFuture<Service.State> getCompletionFuture(Service service) {
-    final SettableFuture<Service.State> resultFuture = SettableFuture.create();
-
-    service.addListener(new ServiceListenerAdapter() {
-      @Override
-      public void terminated(Service.State from) {
-        resultFuture.set(Service.State.TERMINATED);
-      }
-
-      @Override
-      public void failed(Service.State from, Throwable failure) {
-        resultFuture.setException(failure);
-      }
-    }, Threads.SAME_THREAD_EXECUTOR);
-
-    Service.State state = service.state();
-    if (state == Service.State.TERMINATED) {
-      return Futures.immediateFuture(state);
-    } else if (state == Service.State.FAILED) {
-      return Futures.immediateFailedFuture(new IllegalStateException("Service failed with unknown exception."));
-    }
-
-    return resultFuture;
-  }
-
-  /**
-   * Performs the actual logic of chain Service start/stop.
-   */
-  private static ListenableFuture<List<ListenableFuture<Service.State>>> doChain(boolean doStart,
-                                                                                 Service firstService,
-                                                                                 Service...moreServices) {
-    SettableFuture<List<ListenableFuture<Service.State>>> resultFuture = SettableFuture.create();
-    List<ListenableFuture<Service.State>> result = Lists.newArrayListWithCapacity(moreServices.length + 1);
-
-    ListenableFuture<Service.State> future = doStart ? firstService.start() : firstService.stop();
-    future.addListener(createChainListener(future, moreServices, new AtomicInteger(0), result, resultFuture, doStart),
-                       Threads.SAME_THREAD_EXECUTOR);
-    return resultFuture;
-  }
-
-  /**
-   * Returns a {@link Runnable} that can be used as a {@link ListenableFuture} listener to trigger
-   * further service action or completing the result future. Used by
-   * {@link #doChain(boolean, com.google.common.util.concurrent.Service, com.google.common.util.concurrent.Service...)}
-   */
-  private static Runnable createChainListener(final ListenableFuture<Service.State> future, final Service[] services,
-                                              final AtomicInteger idx,
-                                              final List<ListenableFuture<Service.State>> result,
-                                              final SettableFuture<List<ListenableFuture<Service.State>>> resultFuture,
-                                              final boolean doStart) {
-    return new Runnable() {
-
-      @Override
-      public void run() {
-        result.add(future);
-        int nextIdx = idx.getAndIncrement();
-        if (nextIdx == services.length) {
-          resultFuture.set(result);
-          return;
-        }
-        ListenableFuture<Service.State> actionFuture = doStart ? services[nextIdx].start() : services[nextIdx].stop();
-        actionFuture.addListener(createChainListener(actionFuture, services, idx, result, resultFuture, doStart),
-                                 Threads.SAME_THREAD_EXECUTOR);
-      }
-    };
-  }
-
-  private Services() {
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-common/src/main/java/org/apache/twill/common/Threads.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/common/Threads.java b/twill-common/src/main/java/org/apache/twill/common/Threads.java
index e33a677..8a90f7b 100644
--- a/twill-common/src/main/java/org/apache/twill/common/Threads.java
+++ b/twill-common/src/main/java/org/apache/twill/common/Threads.java
@@ -17,11 +17,9 @@
  */
 package org.apache.twill.common;
 
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-
 import java.util.concurrent.Executor;
 import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicLong;
 
 /**
  *
@@ -31,20 +29,32 @@ public final class Threads {
   /**
    * A executor that execute task from the submitter thread.
    */
-  public static final Executor SAME_THREAD_EXECUTOR = MoreExecutors.sameThreadExecutor();
+  public static final Executor SAME_THREAD_EXECUTOR = new Executor() {
+    @Override
+    public void execute(Runnable command) {
+      command.run();
+    }
+  };
 
   /**
    * Handy method to create {@link ThreadFactory} that creates daemon threads with the given name format.
    *
-   * @param nameFormat Name format for the thread names
+   * @param nameFormat Name format for the thread names. It should be a format string compatible
+   *                   with the {@link String#format(String, Object...)} that takes a single number as the format
+   *                   argument.
    * @return A {@link ThreadFactory}.
-   * @see ThreadFactoryBuilder
    */
-  public static ThreadFactory createDaemonThreadFactory(String nameFormat) {
-    return new ThreadFactoryBuilder()
-      .setDaemon(true)
-      .setNameFormat(nameFormat)
-      .build();
+  public static ThreadFactory createDaemonThreadFactory(final String nameFormat) {
+    final AtomicLong id = new AtomicLong(0);
+    return new ThreadFactory() {
+      @Override
+      public Thread newThread(Runnable r) {
+        Thread t = new Thread(r);
+        t.setDaemon(true);
+        t.setName(String.format(nameFormat, id.getAndIncrement()));
+        return t;
+      }
+    };
   }
 
   private Threads() {

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocation.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocation.java b/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocation.java
index 3b01e61..a560694 100644
--- a/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocation.java
+++ b/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocation.java
@@ -17,10 +17,6 @@
  */
 package org.apache.twill.filesystem;
 
-import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -29,8 +25,10 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URI;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Deque;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.UUID;
 
@@ -157,7 +155,7 @@ final class LocalLocation implements Location {
       return delete();
     }
 
-    Deque<File> stack = Lists.newLinkedList();
+    Deque<File> stack = new LinkedList<File>();
     stack.add(file);
     while (!stack.isEmpty()) {
       File f = stack.peekLast();
@@ -218,7 +216,7 @@ final class LocalLocation implements Location {
   @Override
   public List<Location> list() throws IOException {
     File[] files = file.listFiles();
-    ImmutableList.Builder<Location> result = ImmutableList.builder();
+    List<Location> result = new ArrayList<Location>();
     if (files != null) {
       for (File file : files) {
         result.add(new LocalLocation(locationFactory, file));
@@ -226,7 +224,7 @@ final class LocalLocation implements Location {
     } else if (!file.exists()) {
       throw new FileNotFoundException("File " + file + " does not exist.");
     }
-    return result.build();
+    return Collections.unmodifiableList(result);
   }
 
   @Override
@@ -243,8 +241,8 @@ final class LocalLocation implements Location {
       return false;
     }
 
-    LocalLocation other = (LocalLocation) o;
-    return Objects.equal(file, other.file);
+    LocalLocation that = (LocalLocation) o;
+    return file.equals(that.file);
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-common/src/main/java/org/apache/twill/filesystem/LocationFactories.java
----------------------------------------------------------------------
diff --git a/twill-common/src/main/java/org/apache/twill/filesystem/LocationFactories.java b/twill-common/src/main/java/org/apache/twill/filesystem/LocationFactories.java
index 751a632..3b21f5e 100644
--- a/twill-common/src/main/java/org/apache/twill/filesystem/LocationFactories.java
+++ b/twill-common/src/main/java/org/apache/twill/filesystem/LocationFactories.java
@@ -17,8 +17,6 @@
  */
 package org.apache.twill.filesystem;
 
-import com.google.common.base.Throwables;
-
 import java.io.IOException;
 import java.net.URI;
 
@@ -38,7 +36,7 @@ public final class LocationFactories {
           Location base = getDelegate().create(namespace);
           return base.append(path);
         } catch (IOException e) {
-          throw Throwables.propagate(e);
+          throw new RuntimeException(e);
         }
       }
 
@@ -51,7 +49,7 @@ public final class LocationFactories {
           Location base = getDelegate().create(namespace);
           return base.append(uri.getPath());
         } catch (IOException e) {
-          throw Throwables.propagate(e);
+          throw new RuntimeException(e);
         }
       }
 

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-common/src/test/java/org/apache/twill/common/CompositeServiceTest.java
----------------------------------------------------------------------
diff --git a/twill-common/src/test/java/org/apache/twill/common/CompositeServiceTest.java b/twill-common/src/test/java/org/apache/twill/common/CompositeServiceTest.java
deleted file mode 100644
index 1c45892..0000000
--- a/twill-common/src/test/java/org/apache/twill/common/CompositeServiceTest.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.twill.common;
-
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.base.Predicates;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.util.concurrent.AbstractIdleService;
-import com.google.common.util.concurrent.Service;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-/**
- * Tests for {@link CompositeService}.
- */
-public class CompositeServiceTest {
-
-  @Test
-  public void testOrder() throws InterruptedException, ExecutionException, TimeoutException {
-    List<Service> services = Lists.newArrayList();
-
-    // Start 10 services and check their start sequence is ordered.
-    Semaphore semaphore = new Semaphore(0);
-    for (int i = 0; i < 10; i++) {
-      services.add(new TestService(semaphore, i));
-    }
-
-    Service service = new CompositeService(services);
-    service.start().get(5, TimeUnit.SECONDS);
-
-    // There should be 10 permits after all 10 services started
-    Assert.assertTrue(semaphore.tryAcquire(10, 5, TimeUnit.SECONDS));
-
-    // Check all services are running
-    Assert.assertTrue(Iterables.all(services, serviceStatePredicate(Service.State.RUNNING)));
-
-    // Release 10 permits for the stop sequence to start
-    semaphore.release(10);
-    service.stop().get(5, TimeUnit.SECONDS);
-
-    // There should be no permit left after all 10 services stopped
-    Assert.assertFalse(semaphore.tryAcquire(10));
-
-    // Check all services are stopped
-    Assert.assertTrue(Iterables.all(services, serviceStatePredicate(Service.State.TERMINATED)));
-  }
-
-  @Test
-  public void testErrorStart() throws InterruptedException {
-    List<Service> services = Lists.newArrayList();
-
-    // Create 5 services. The forth one will got a start failure.
-    Semaphore semaphore = new Semaphore(0);
-    for (int i = 0; i < 5; i++) {
-      services.add(new TestService(semaphore, i, i == 3));
-    }
-
-    Service service = new CompositeService(services);
-    try {
-      service.start().get();
-      Assert.fail();
-    } catch (ExecutionException e) {
-      // Expected
-    }
-
-    // Verify all services are not in running state
-    Assert.assertTrue(Iterables.all(services, Predicates.not(serviceStatePredicate(Service.State.RUNNING))));
-
-    // There should be one service in error state
-    Assert.assertTrue(Iterables.removeIf(services, serviceStatePredicate(Service.State.FAILED)));
-
-    for (Service s : services) {
-      Assert.assertNotEquals(3, ((TestService) s).getOrder());
-    }
-  }
-
-  private Predicate<Service> serviceStatePredicate(final Service.State state) {
-    return new Predicate<Service>() {
-      @Override
-      public boolean apply(Service service) {
-        return service.state() == state;
-      }
-    };
-  }
-
-  private static final class TestService extends AbstractIdleService {
-
-    private final Semaphore semaphore;
-    private final int order;
-    private final boolean startFail;
-
-    private TestService(Semaphore semaphore, int order) {
-      this(semaphore, order, false);
-    }
-
-    private TestService(Semaphore semaphore, int order, boolean startFail) {
-      this.semaphore = semaphore;
-      this.order = order;
-      this.startFail = startFail;
-    }
-
-    public int getOrder() {
-      return order;
-    }
-
-    @Override
-    protected void startUp() throws Exception {
-      Preconditions.checkState(!startFail, "Fail to start service of order %s", order);
-
-      // Acquire all permits emitted by previous service
-      semaphore.acquire(order);
-      // Emit enough permits for next service
-      semaphore.release(order + 1);
-    }
-
-    @Override
-    protected void shutDown() throws Exception {
-      semaphore.acquire(order + 1);
-      semaphore.release(order);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-common/src/test/java/org/apache/twill/common/ServicesTest.java
----------------------------------------------------------------------
diff --git a/twill-common/src/test/java/org/apache/twill/common/ServicesTest.java b/twill-common/src/test/java/org/apache/twill/common/ServicesTest.java
deleted file mode 100644
index c0aa7ee..0000000
--- a/twill-common/src/test/java/org/apache/twill/common/ServicesTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.twill.common;
-
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.AbstractIdleService;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.Service;
-import org.junit.Assert;
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Unit test for {@link Services} methods.
- */
-public class ServicesTest {
-
-  private static final Logger LOG = LoggerFactory.getLogger(ServicesTest.class);
-
-  @Test
-  public void testChain() throws ExecutionException, InterruptedException {
-    AtomicBoolean transiting = new AtomicBoolean(false);
-    Service s1 = new DummyService("s1", transiting);
-    Service s2 = new DummyService("s2", transiting);
-    Service s3 = new DummyService("s3", transiting);
-
-    Futures.allAsList(Services.chainStart(s1, s2, s3).get()).get();
-    Futures.allAsList(Services.chainStop(s3, s2, s1).get()).get();
-  }
-
-  @Test
-  public void testCompletion() throws ExecutionException, InterruptedException {
-    Service service = new DummyService("s1", new AtomicBoolean());
-    ListenableFuture<Service.State> completion = Services.getCompletionFuture(service);
-
-    service.start();
-    service.stop();
-
-    completion.get();
-
-    AtomicBoolean transiting = new AtomicBoolean();
-    service = new DummyService("s2", transiting);
-    completion = Services.getCompletionFuture(service);
-
-    service.startAndWait();
-    transiting.set(true);
-    service.stop();
-
-    try {
-      completion.get();
-      Assert.assertTrue(false);
-    } catch (ExecutionException e) {
-      // Expected
-    }
-  }
-
-  private static final class DummyService extends AbstractIdleService {
-
-    private final String name;
-    private final AtomicBoolean transiting;
-
-    private DummyService(String name, AtomicBoolean transiting) {
-      this.name = name;
-      this.transiting = transiting;
-    }
-
-    @Override
-    protected void startUp() throws Exception {
-      Preconditions.checkState(transiting.compareAndSet(false, true));
-      LOG.info("Starting: " + name);
-      TimeUnit.MILLISECONDS.sleep(500);
-      LOG.info("Started: " + name);
-      Preconditions.checkState(transiting.compareAndSet(true, false));
-    }
-
-    @Override
-    protected void shutDown() throws Exception {
-      Preconditions.checkState(transiting.compareAndSet(false, true));
-      LOG.info("Stopping: " + name);
-      TimeUnit.MILLISECONDS.sleep(500);
-      LOG.info("Stopped: " + name);
-      Preconditions.checkState(transiting.compareAndSet(true, false));
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/0d217b6d/twill-core/src/main/java/org/apache/twill/internal/AbstractExecutionServiceController.java
----------------------------------------------------------------------
diff --git a/twill-core/src/main/java/org/apache/twill/internal/AbstractExecutionServiceController.java b/twill-core/src/main/java/org/apache/twill/internal/AbstractExecutionServiceController.java
index acb6b7b..580a88f 100644
--- a/twill-core/src/main/java/org/apache/twill/internal/AbstractExecutionServiceController.java
+++ b/twill-core/src/main/java/org/apache/twill/internal/AbstractExecutionServiceController.java
@@ -17,33 +17,53 @@
  */
 package org.apache.twill.internal;
 
+import com.google.common.base.Function;
 import com.google.common.util.concurrent.AbstractIdleService;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.Service;
+import com.google.common.util.concurrent.SettableFuture;
+import com.google.common.util.concurrent.Uninterruptibles;
 import org.apache.twill.api.RunId;
 import org.apache.twill.api.ServiceController;
 import org.apache.twill.common.Threads;
 
 import java.util.Queue;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * An abstract base class for implementing {@link ServiceController} that deal with Service state transition and
  * listener callback.
  */
-public abstract class AbstractExecutionServiceController implements ServiceController {
+public abstract class AbstractExecutionServiceController implements ServiceController, Service {
 
   private final RunId runId;
   private final ListenerExecutors listenerExecutors;
   private final Service serviceDelegate;
+  private final SettableFuture<State> terminationFuture;
 
   protected AbstractExecutionServiceController(RunId runId) {
     this.runId = runId;
     this.listenerExecutors = new ListenerExecutors();
     this.serviceDelegate = new ServiceDelegate();
+    this.terminationFuture = SettableFuture.create();
+    addListener(new ServiceListenerAdapter() {
+      @Override
+      public void failed(State from, Throwable failure) {
+        terminationFuture.setException(failure);
+      }
+
+      @Override
+      public void terminated(State from) {
+        terminationFuture.set(State.TERMINATED);
+      }
+    }, Threads.SAME_THREAD_EXECUTOR);
   }
 
   protected abstract void startUp();
@@ -56,6 +76,52 @@ public abstract class AbstractExecutionServiceController implements ServiceContr
   }
 
   @Override
+  public Future<? extends ServiceController> terminate() {
+    stop();
+
+    return Futures.transform(terminationFuture, new Function<State, ServiceController>() {
+      @Override
+      public ServiceController apply(State input) {
+        return AbstractExecutionServiceController.this;
+      }
+    });
+  }
+
+  @Override
+  public void onRunning(final Runnable runnable, Executor executor) {
+    addListener(new ServiceListenerAdapter() {
+      @Override
+      public void running() {
+        runnable.run();
+      }
+    }, executor);
+  }
+
+  @Override
+  public void onTerminated(final Runnable runnable, Executor executor) {
+    addListener(new ServiceListenerAdapter() {
+      @Override
+      public void failed(State from, Throwable failure) {
+        runnable.run();
+      }
+
+      @Override
+      public void terminated(State from) {
+        runnable.run();
+      }
+    }, executor);
+  }
+
+  @Override
+  public void awaitTerminated() throws ExecutionException {
+    Uninterruptibles.getUninterruptibly(terminationFuture);
+  }
+
+  @Override
+  public void awaitTerminated(long timeout, TimeUnit timeoutUnit) throws TimeoutException, ExecutionException {
+    Uninterruptibles.getUninterruptibly(terminationFuture, timeout, timeoutUnit);
+  }
+
   public final void addListener(Listener listener, Executor executor) {
     listenerExecutors.addListener(new ListenerExecutor(listener, executor));
   }