mirror of https://github.com/grpc/grpc-java.git
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:
parent
58d78dd0aa
commit
c4f7f5c4fd
|
|
@ -14,6 +14,7 @@ buildscript {
|
||||||
def subprojects = [
|
def subprojects = [
|
||||||
project(':grpc-auth'),
|
project(':grpc-auth'),
|
||||||
project(':grpc-core'),
|
project(':grpc-core'),
|
||||||
|
project(':grpc-context'),
|
||||||
project(':grpc-netty'),
|
project(':grpc-netty'),
|
||||||
project(':grpc-okhttp'),
|
project(':grpc-okhttp'),
|
||||||
project(':grpc-protobuf'),
|
project(':grpc-protobuf'),
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
@ -31,9 +31,6 @@
|
||||||
|
|
||||||
package io.grpc;
|
package io.grpc;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
@ -44,8 +41,6 @@ import java.util.concurrent.TimeoutException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A context propagation mechanism which can carry scoped-values across API boundaries and between
|
* A context propagation mechanism which can carry scoped-values across API boundaries and between
|
||||||
* threads. Examples of state propagated via context include:
|
* threads. Examples of state propagated via context include:
|
||||||
|
|
@ -275,8 +270,8 @@ public class Context {
|
||||||
*/
|
*/
|
||||||
public CancellableContext withDeadline(Deadline deadline,
|
public CancellableContext withDeadline(Deadline deadline,
|
||||||
ScheduledExecutorService scheduler) {
|
ScheduledExecutorService scheduler) {
|
||||||
Preconditions.checkNotNull(deadline, "deadline");
|
checkNotNull(deadline, "deadline");
|
||||||
Preconditions.checkNotNull(scheduler, "scheduler");
|
checkNotNull(scheduler, "scheduler");
|
||||||
return new CancellableContext(this, deadline, scheduler);
|
return new CancellableContext(this, deadline, scheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -349,7 +344,7 @@ public class Context {
|
||||||
* will still be bound.
|
* will still be bound.
|
||||||
*/
|
*/
|
||||||
public void detach(Context toAttach) {
|
public void detach(Context toAttach) {
|
||||||
Preconditions.checkNotNull(toAttach, "toAttach");
|
checkNotNull(toAttach, "toAttach");
|
||||||
if (toAttach.attach() != this) {
|
if (toAttach.attach() != this) {
|
||||||
// Log a severe message instead of throwing an exception as the context to attach is assumed
|
// 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
|
// 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
|
* <p>The cancellation cause is provided for informational purposes only and implementations
|
||||||
* should generally assume that it has already been handled and logged properly.
|
* should generally assume that it has already been handled and logged properly.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
|
||||||
public Throwable cancellationCause() {
|
public Throwable cancellationCause() {
|
||||||
if (parent == null || !cascadesCancellation) {
|
if (parent == null || !cascadesCancellation) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -396,7 +390,6 @@ public class Context {
|
||||||
* A context may have an associated {@link Deadline} at which it will be automatically cancelled.
|
* 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.
|
* @return A {@link io.grpc.Deadline} or {@code null} if no deadline is set.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
|
||||||
public Deadline getDeadline() {
|
public Deadline getDeadline() {
|
||||||
return DEADLINE_KEY.get(this);
|
return DEADLINE_KEY.get(this);
|
||||||
}
|
}
|
||||||
|
|
@ -406,8 +399,8 @@ public class Context {
|
||||||
*/
|
*/
|
||||||
public void addListener(final CancellationListener cancellationListener,
|
public void addListener(final CancellationListener cancellationListener,
|
||||||
final Executor executor) {
|
final Executor executor) {
|
||||||
Preconditions.checkNotNull(cancellationListener, "cancellationListener");
|
checkNotNull(cancellationListener, "cancellationListener");
|
||||||
Preconditions.checkNotNull(executor, "executor");
|
checkNotNull(executor, "executor");
|
||||||
if (canBeCancelled) {
|
if (canBeCancelled) {
|
||||||
ExecutableListener executableListener =
|
ExecutableListener executableListener =
|
||||||
new ExecutableListener(executor, cancellationListener);
|
new ExecutableListener(executor, cancellationListener);
|
||||||
|
|
@ -420,7 +413,7 @@ public class Context {
|
||||||
// we can cascade listener notification.
|
// we can cascade listener notification.
|
||||||
listeners = new ArrayList<ExecutableListener>();
|
listeners = new ArrayList<ExecutableListener>();
|
||||||
listeners.add(executableListener);
|
listeners.add(executableListener);
|
||||||
parent.addListener(parentListener, MoreExecutors.directExecutor());
|
parent.addListener(parentListener, DirectExecutor.INSTANCE);
|
||||||
} else {
|
} else {
|
||||||
listeners.add(executableListener);
|
listeners.add(executableListener);
|
||||||
}
|
}
|
||||||
|
|
@ -689,13 +682,13 @@ public class Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel this context and optionally provide a cause for the cancellation. This
|
* Cancel this context and optionally provide a cause (can be {@code null}) for the
|
||||||
* will trigger notification of listeners.
|
* cancellation. This will trigger notification of listeners.
|
||||||
*
|
*
|
||||||
* @return {@code true} if this context cancelled the context and notified listeners,
|
* @return {@code true} if this context cancelled the context and notified listeners,
|
||||||
* {@code false} if the context was already cancelled.
|
* {@code false} if the context was already cancelled.
|
||||||
*/
|
*/
|
||||||
public boolean cancel(@Nullable Throwable cause) {
|
public boolean cancel(Throwable cause) {
|
||||||
boolean triggeredCancel = false;
|
boolean triggeredCancel = false;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (!cancelled) {
|
if (!cancelled) {
|
||||||
|
|
@ -721,7 +714,7 @@ public class Context {
|
||||||
* @param toAttach context to make current.
|
* @param toAttach context to make current.
|
||||||
* @param cause of cancellation, can be {@code null}.
|
* @param cause of cancellation, can be {@code null}.
|
||||||
*/
|
*/
|
||||||
public void detachAndCancel(Context toAttach, @Nullable Throwable cause) {
|
public void detachAndCancel(Context toAttach, Throwable cause) {
|
||||||
try {
|
try {
|
||||||
detach(toAttach);
|
detach(toAttach);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -745,7 +738,6 @@ public class Context {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
@Override
|
||||||
public Throwable cancellationCause() {
|
public Throwable cancellationCause() {
|
||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
|
|
@ -778,7 +770,7 @@ public class Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
Key(String name, T defaultValue) {
|
Key(String name, T defaultValue) {
|
||||||
this.name = Preconditions.checkNotNull(name, "name");
|
this.name = checkNotNull(name, "name");
|
||||||
this.defaultValue = defaultValue;
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -31,9 +31,6 @@
|
||||||
|
|
||||||
package io.grpc;
|
package io.grpc;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import com.google.common.base.Preconditions;
|
|
||||||
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
@ -58,9 +55,9 @@ public final class Deadline implements Comparable<Deadline> {
|
||||||
return after(duration, units, SYSTEM_TICKER);
|
return after(duration, units, SYSTEM_TICKER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
// For testing
|
||||||
static Deadline after(long duration, TimeUnit units, Ticker ticker) {
|
static Deadline after(long duration, TimeUnit units, Ticker ticker) {
|
||||||
Preconditions.checkNotNull(units, "units");
|
checkNotNull(units, "units");
|
||||||
return new Deadline(ticker, units.toNanos(duration), true);
|
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
|
* @return {@link ScheduledFuture} which can be used to cancel execution of the task
|
||||||
*/
|
*/
|
||||||
public ScheduledFuture<?> runOnExpiration(Runnable task, ScheduledExecutorService scheduler) {
|
public ScheduledFuture<?> runOnExpiration(Runnable task, ScheduledExecutorService scheduler) {
|
||||||
Preconditions.checkNotNull(task, "task");
|
checkNotNull(task, "task");
|
||||||
Preconditions.checkNotNull(scheduler, "scheduler");
|
checkNotNull(scheduler, "scheduler");
|
||||||
return scheduler.schedule(task, deadlineNanos - ticker.read(), TimeUnit.NANOSECONDS);
|
return scheduler.schedule(task, deadlineNanos - ticker.read(), TimeUnit.NANOSECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,4 +176,11 @@ public final class Deadline implements Comparable<Deadline> {
|
||||||
return System.nanoTime();
|
return System.nanoTime();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <T> T checkNotNull(T reference, Object errorMessage) {
|
||||||
|
if (reference == null) {
|
||||||
|
throw new NullPointerException(String.valueOf(errorMessage));
|
||||||
|
}
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -265,7 +265,7 @@ public class DeadlineTest {
|
||||||
assertEquals("12000 ns from now", d.toString());
|
assertEquals("12000 ns from now", d.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
static class FakeTicker extends Deadline.Ticker {
|
private static class FakeTicker extends Deadline.Ticker {
|
||||||
private long time;
|
private long time;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -7,7 +7,8 @@ description = 'gRPC: Core'
|
||||||
dependencies {
|
dependencies {
|
||||||
compile libraries.guava,
|
compile libraries.guava,
|
||||||
libraries.errorprone,
|
libraries.errorprone,
|
||||||
libraries.jsr305
|
libraries.jsr305,
|
||||||
|
project(':grpc-context')
|
||||||
testCompile project(':grpc-testing')
|
testCompile project(':grpc-testing')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,13 +51,14 @@ import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/** Unit tests for {@link CallOptions}. */
|
/** Unit tests for {@link CallOptions}. */
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class CallOptionsTest {
|
public class CallOptionsTest {
|
||||||
private String sampleAuthority = "authority";
|
private String sampleAuthority = "authority";
|
||||||
private String sampleCompressor = "compressor";
|
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 Deadline sampleDeadline = Deadline.after(1, NANOSECONDS, ticker);
|
||||||
private Key<String> sampleKey = Attributes.Key.of("sample");
|
private Key<String> sampleKey = Attributes.Key.of("sample");
|
||||||
private Attributes sampleAffinity = Attributes.newBuilder().set(sampleKey, "blah").build();
|
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.getAffinity(), o2.getAffinity())
|
||||||
&& Objects.equal(o1.getCredentials(), o2.getCredentials());
|
&& 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
rootProject.name = "grpc"
|
rootProject.name = "grpc"
|
||||||
include ":grpc-core"
|
include ":grpc-core"
|
||||||
|
include ":grpc-context"
|
||||||
include ":grpc-stub"
|
include ":grpc-stub"
|
||||||
include ":grpc-auth"
|
include ":grpc-auth"
|
||||||
include ":grpc-okhttp"
|
include ":grpc-okhttp"
|
||||||
|
|
@ -16,6 +17,7 @@ include ":grpc-services"
|
||||||
include ":grpc-thrift"
|
include ":grpc-thrift"
|
||||||
|
|
||||||
project(':grpc-core').projectDir = "$rootDir/core" as File
|
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-stub').projectDir = "$rootDir/stub" as File
|
||||||
project(':grpc-auth').projectDir = "$rootDir/auth" as File
|
project(':grpc-auth').projectDir = "$rootDir/auth" as File
|
||||||
project(':grpc-okhttp').projectDir = "$rootDir/okhttp" as File
|
project(':grpc-okhttp').projectDir = "$rootDir/okhttp" as File
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue