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.
This commit is contained in:
Kun Zhang 2016-09-01 16:00:43 -07:00
parent 58d78dd0aa
commit c4f7f5c4fd
9 changed files with 85 additions and 29 deletions

View File

@ -14,6 +14,7 @@ buildscript {
def subprojects = [
project(':grpc-auth'),
project(':grpc-core'),
project(':grpc-context'),
project(':grpc-netty'),
project(':grpc-okhttp'),
project(':grpc-protobuf'),

14
context/build.gradle Normal file
View File

@ -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"
}

View File

@ -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.concurrent.TimeoutException;
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 class Context {
*/
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 @@ public class Context {
* 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 @@ public class Context {
* <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 @@ public class Context {
* 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 class Context {
*/
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 @@ public class Context {
// 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 @@ public class Context {
}
/**
* 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 @@ public class Context {
* @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 @@ public class Context {
return false;
}
@Nullable
@Override
public Throwable cancellationCause() {
if (isCancelled()) {
@ -778,7 +770,7 @@ public class Context {
}
Key(String name, T defaultValue) {
this.name = Preconditions.checkNotNull(name, "name");
this.name = checkNotNull(name, "name");
this.defaultValue = defaultValue;
}
@ -842,4 +834,25 @@ public class Context {
}
}
}
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";
}
}
}

View File

@ -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 @@ public final class Deadline implements Comparable<Deadline> {
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 @@ public final class Deadline implements Comparable<Deadline> {
* @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 @@ public final class Deadline implements Comparable<Deadline> {
return System.nanoTime();
}
}
private static <T> T checkNotNull(T reference, Object errorMessage) {
if (reference == null) {
throw new NullPointerException(String.valueOf(errorMessage));
}
return reference;
}
}

View File

@ -265,7 +265,7 @@ public class DeadlineTest {
assertEquals("12000 ns from now", d.toString());
}
static class FakeTicker extends Deadline.Ticker {
private static class FakeTicker extends Deadline.Ticker {
private long time;
@Override

View File

@ -7,7 +7,8 @@ description = 'gRPC: Core'
dependencies {
compile libraries.guava,
libraries.errorprone,
libraries.jsr305
libraries.jsr305,
project(':grpc-context')
testCompile project(':grpc-testing')
}

View File

@ -51,13 +51,14 @@ import org.junit.runner.RunWith;
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 @@ public class CallOptionsTest {
&& 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);
}
}
}

View File

@ -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-services"
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