core: split Context into a separate grpc-context artifact.

The Context API is not particularly gRPC-specific, and will be used by
Census as its context propagation mechanism.

Removed all dependencies to make it easy for other libraries to depend
on.
diff --git a/all/build.gradle b/all/build.gradle
index a78d440..535d0e7 100644
--- a/all/build.gradle
+++ b/all/build.gradle
@@ -14,6 +14,7 @@
 def subprojects = [
   project(':grpc-auth'),
   project(':grpc-core'),
+  project(':grpc-context'),
   project(':grpc-netty'),
   project(':grpc-okhttp'),
   project(':grpc-protobuf'),
diff --git a/context/build.gradle b/context/build.gradle
new file mode 100644
index 0000000..0566f6a
--- /dev/null
+++ b/context/build.gradle
@@ -0,0 +1,14 @@
+plugins {
+    id "be.insaneprogramming.gradle.animalsniffer" version "1.4.0"
+}
+
+description = 'gRPC: Context'
+
+dependencies {
+    testCompile project(':grpc-testing')
+}
+
+// Configure the animal sniffer plugin
+animalsniffer {
+    signature = "org.codehaus.mojo.signature:java16:+@signature"
+}
diff --git a/core/src/main/java/io/grpc/Context.java b/context/src/main/java/io/grpc/Context.java
similarity index 96%
rename from core/src/main/java/io/grpc/Context.java
rename to context/src/main/java/io/grpc/Context.java
index 7ddb644..27a7367 100644
--- a/core/src/main/java/io/grpc/Context.java
+++ b/context/src/main/java/io/grpc/Context.java
@@ -31,9 +31,6 @@
 
 package io.grpc;
 
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.MoreExecutors;
-
 import java.util.ArrayList;
 import java.util.concurrent.Callable;
 import java.util.concurrent.Executor;
@@ -44,8 +41,6 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import javax.annotation.Nullable;
-
 /**
  * A context propagation mechanism which can carry scoped-values across API boundaries and between
  * threads. Examples of state propagated via context include:
@@ -275,8 +270,8 @@
    */
   public CancellableContext withDeadline(Deadline deadline,
       ScheduledExecutorService scheduler) {
-    Preconditions.checkNotNull(deadline, "deadline");
-    Preconditions.checkNotNull(scheduler, "scheduler");
+    checkNotNull(deadline, "deadline");
+    checkNotNull(scheduler, "scheduler");
     return new CancellableContext(this, deadline, scheduler);
   }
 
@@ -349,7 +344,7 @@
    * will still be bound.
    */
   public void detach(Context toAttach) {
-    Preconditions.checkNotNull(toAttach, "toAttach");
+    checkNotNull(toAttach, "toAttach");
     if (toAttach.attach() != this) {
       // Log a severe message instead of throwing an exception as the context to attach is assumed
       // to be the correct one and the unbalanced state represents a coding mistake in a lower
@@ -383,7 +378,6 @@
    * <p>The cancellation cause is provided for informational purposes only and implementations
    * should generally assume that it has already been handled and logged properly.
    */
-  @Nullable
   public Throwable cancellationCause() {
     if (parent == null || !cascadesCancellation) {
       return null;
@@ -396,7 +390,6 @@
    * A context may have an associated {@link Deadline} at which it will be automatically cancelled.
    * @return A {@link io.grpc.Deadline} or {@code null} if no deadline is set.
    */
-  @Nullable
   public Deadline getDeadline() {
     return DEADLINE_KEY.get(this);
   }
@@ -406,8 +399,8 @@
    */
   public void addListener(final CancellationListener cancellationListener,
                           final Executor executor) {
-    Preconditions.checkNotNull(cancellationListener, "cancellationListener");
-    Preconditions.checkNotNull(executor, "executor");
+    checkNotNull(cancellationListener, "cancellationListener");
+    checkNotNull(executor, "executor");
     if (canBeCancelled) {
       ExecutableListener executableListener =
           new ExecutableListener(executor, cancellationListener);
@@ -420,7 +413,7 @@
             // we can cascade listener notification.
             listeners = new ArrayList<ExecutableListener>();
             listeners.add(executableListener);
-            parent.addListener(parentListener, MoreExecutors.directExecutor());
+            parent.addListener(parentListener, DirectExecutor.INSTANCE);
           } else {
             listeners.add(executableListener);
           }
@@ -689,13 +682,13 @@
     }
 
     /**
-     * Cancel this context and optionally provide a cause for the cancellation. This
-     * will trigger notification of listeners.
+     * Cancel this context and optionally provide a cause (can be {@code null}) for the
+     * cancellation. This will trigger notification of listeners.
      *
      * @return {@code true} if this context cancelled the context and notified listeners,
      *    {@code false} if the context was already cancelled.
      */
-    public boolean cancel(@Nullable Throwable cause) {
+    public boolean cancel(Throwable cause) {
       boolean triggeredCancel = false;
       synchronized (this) {
         if (!cancelled) {
@@ -721,7 +714,7 @@
      * @param toAttach context to make current.
      * @param cause of cancellation, can be {@code null}.
      */
-    public void detachAndCancel(Context toAttach, @Nullable Throwable cause) {
+    public void detachAndCancel(Context toAttach, Throwable cause) {
       try {
         detach(toAttach);
       } finally {
@@ -745,7 +738,6 @@
       return false;
     }
 
-    @Nullable
     @Override
     public Throwable cancellationCause() {
       if (isCancelled()) {
@@ -778,7 +770,7 @@
     }
 
     Key(String name, T defaultValue) {
-      this.name = Preconditions.checkNotNull(name, "name");
+      this.name = checkNotNull(name, "name");
       this.defaultValue = defaultValue;
     }
 
@@ -842,4 +834,25 @@
       }
     }
   }
+
+  private static <T> T checkNotNull(T reference, Object errorMessage) {
+    if (reference == null) {
+      throw new NullPointerException(String.valueOf(errorMessage));
+    }
+    return reference;
+  }
+
+  private enum DirectExecutor implements Executor {
+    INSTANCE;
+
+    @Override
+    public void execute(Runnable command) {
+      command.run();
+    }
+
+    @Override
+    public String toString() {
+      return "Context.DirectExecutor";
+    }
+  }
 }
diff --git a/core/src/main/java/io/grpc/Deadline.java b/context/src/main/java/io/grpc/Deadline.java
similarity index 94%
rename from core/src/main/java/io/grpc/Deadline.java
rename to context/src/main/java/io/grpc/Deadline.java
index 7062cbb..c3ab53e 100644
--- a/core/src/main/java/io/grpc/Deadline.java
+++ b/context/src/main/java/io/grpc/Deadline.java
@@ -31,9 +31,6 @@
 
 package io.grpc;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
-
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
@@ -58,9 +55,9 @@
     return after(duration, units, SYSTEM_TICKER);
   }
 
-  @VisibleForTesting
+  // For testing
   static Deadline after(long duration, TimeUnit units, Ticker ticker) {
-    Preconditions.checkNotNull(units, "units");
+    checkNotNull(units, "units");
     return new Deadline(ticker, units.toNanos(duration), true);
   }
 
@@ -146,8 +143,8 @@
    * @return {@link ScheduledFuture} which can be used to cancel execution of the task
    */
   public ScheduledFuture<?> runOnExpiration(Runnable task, ScheduledExecutorService scheduler) {
-    Preconditions.checkNotNull(task, "task");
-    Preconditions.checkNotNull(scheduler, "scheduler");
+    checkNotNull(task, "task");
+    checkNotNull(scheduler, "scheduler");
     return scheduler.schedule(task, deadlineNanos - ticker.read(), TimeUnit.NANOSECONDS);
   }
 
@@ -179,4 +176,11 @@
       return System.nanoTime();
     }
   }
+
+  private static <T> T checkNotNull(T reference, Object errorMessage) {
+    if (reference == null) {
+      throw new NullPointerException(String.valueOf(errorMessage));
+    }
+    return reference;
+  }
 }
diff --git a/core/src/test/java/io/grpc/ContextTest.java b/context/src/test/java/io/grpc/ContextTest.java
similarity index 100%
rename from core/src/test/java/io/grpc/ContextTest.java
rename to context/src/test/java/io/grpc/ContextTest.java
diff --git a/core/src/test/java/io/grpc/DeadlineTest.java b/context/src/test/java/io/grpc/DeadlineTest.java
similarity index 99%
rename from core/src/test/java/io/grpc/DeadlineTest.java
rename to context/src/test/java/io/grpc/DeadlineTest.java
index 2df9959..f85edf1 100644
--- a/core/src/test/java/io/grpc/DeadlineTest.java
+++ b/context/src/test/java/io/grpc/DeadlineTest.java
@@ -265,7 +265,7 @@
     assertEquals("12000 ns from now", d.toString());
   }
 
-  static class FakeTicker extends Deadline.Ticker {
+  private static class FakeTicker extends Deadline.Ticker {
     private long time;
 
     @Override
diff --git a/core/build.gradle b/core/build.gradle
index b03e06c..6d6147c 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -7,7 +7,8 @@
 dependencies {
     compile libraries.guava,
             libraries.errorprone,
-            libraries.jsr305
+            libraries.jsr305,
+            project(':grpc-context')
     testCompile project(':grpc-testing')
 }
 
diff --git a/core/src/test/java/io/grpc/CallOptionsTest.java b/core/src/test/java/io/grpc/CallOptionsTest.java
index 31609b2..baa3cdb 100644
--- a/core/src/test/java/io/grpc/CallOptionsTest.java
+++ b/core/src/test/java/io/grpc/CallOptionsTest.java
@@ -51,13 +51,14 @@
 import org.junit.runners.JUnit4;
 
 import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
 
 /** Unit tests for {@link CallOptions}. */
 @RunWith(JUnit4.class)
 public class CallOptionsTest {
   private String sampleAuthority = "authority";
   private String sampleCompressor = "compressor";
-  private Deadline.Ticker ticker = new DeadlineTest.FakeTicker();
+  private Deadline.Ticker ticker = new FakeTicker();
   private Deadline sampleDeadline = Deadline.after(1, NANOSECONDS, ticker);
   private Key<String> sampleKey = Attributes.Key.of("sample");
   private Attributes sampleAffinity = Attributes.newBuilder().set(sampleKey, "blah").build();
@@ -233,4 +234,24 @@
         && Objects.equal(o1.getAffinity(), o2.getAffinity())
         && Objects.equal(o1.getCredentials(), o2.getCredentials());
   }
+
+  private static class FakeTicker extends Deadline.Ticker {
+    private long time;
+
+    @Override
+    public long read() {
+      return time;
+    }
+
+    public void reset(long time) {
+      this.time = time;
+    }
+
+    public void increment(long period, TimeUnit unit) {
+      if (period < 0) {
+        throw new IllegalArgumentException();
+      }
+      this.time += unit.toNanos(period);
+    }
+  }
 }
diff --git a/settings.gradle b/settings.gradle
index 6c7034a..d9ea440 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,5 +1,6 @@
 rootProject.name = "grpc"
 include ":grpc-core"
+include ":grpc-context"
 include ":grpc-stub"
 include ":grpc-auth"
 include ":grpc-okhttp"
@@ -16,6 +17,7 @@
 include ":grpc-thrift"
 
 project(':grpc-core').projectDir = "$rootDir/core" as File
+project(':grpc-context').projectDir = "$rootDir/context" as File
 project(':grpc-stub').projectDir = "$rootDir/stub" as File
 project(':grpc-auth').projectDir = "$rootDir/auth" as File
 project(':grpc-okhttp').projectDir = "$rootDir/okhttp" as File