nl.topicus.jdbc.shaded.io.grpc.stub.ServerCalls Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spanner-jdbc Show documentation
Show all versions of spanner-jdbc Show documentation
JDBC Driver for Google Cloud Spanner
/*
* Copyright 2014, Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package nl.topicus.jdbc.shaded.io.grpc.stub;
import static nl.topicus.jdbc.shaded.com.google.nl.topicus.jdbc.shaded.com.on.base.Preconditions.checkNotNull;
import nl.topicus.jdbc.shaded.io.grpc.Metadata;
import nl.topicus.jdbc.shaded.io.grpc.MethodDescriptor;
import nl.topicus.jdbc.shaded.io.grpc.ServerCall;
import nl.topicus.jdbc.shaded.io.grpc.ServerCallHandler;
import nl.topicus.jdbc.shaded.io.grpc.Status;
/**
* Utility functions for adapting {@link ServerCallHandler}s to application service implementation,
* meant to be used by the generated code.
*/
public final class ServerCalls {
private ServerCalls() {
}
/**
* Creates a {@code ServerCallHandler} for a unary call method of the service.
*
* @param method an adaptor to the actual method on the service implementation.
*/
public static ServerCallHandler asyncUnaryCall(
final UnaryMethod method) {
return asyncUnaryRequestCall(method);
}
/**
* Creates a {@code ServerCallHandler} for a server streaming method of the service.
*
* @param method an adaptor to the actual method on the service implementation.
*/
public static ServerCallHandler asyncServerStreamingCall(
final ServerStreamingMethod method) {
return asyncUnaryRequestCall(method);
}
/**
* Creates a {@code ServerCallHandler} for a client streaming method of the service.
*
* @param method an adaptor to the actual method on the service implementation.
*/
public static ServerCallHandler asyncClientStreamingCall(
final ClientStreamingMethod method) {
return asyncStreamingRequestCall(method);
}
/**
* Creates a {@code ServerCallHandler} for a bidi streaming method of the service.
*
* @param method an adaptor to the actual method on the service implementation.
*/
public static ServerCallHandler asyncBidiStreamingCall(
final BidiStreamingMethod method) {
return asyncStreamingRequestCall(method);
}
/**
* Adaptor to a unary call method.
*/
public static interface UnaryMethod extends UnaryRequestMethod {
}
/**
* Adaptor to a server streaming method.
*/
public static interface ServerStreamingMethod
extends UnaryRequestMethod {
}
/**
* Adaptor to a client streaming method.
*/
public static interface ClientStreamingMethod
extends StreamingRequestMethod {
}
/**
* Adaptor to a bi-directional streaming method.
*/
public static interface BidiStreamingMethod
extends StreamingRequestMethod {
}
/**
* Creates a {@code ServerCallHandler} for a unary request call method of the service.
*
* @param method an adaptor to the actual method on the service implementation.
*/
private static ServerCallHandler asyncUnaryRequestCall(
final UnaryRequestMethod method) {
return new ServerCallHandler() {
@Override
public ServerCall.Listener startCall(
final ServerCall call,
Metadata headers) {
final ServerCallStreamObserverImpl responseObserver =
new ServerCallStreamObserverImpl(call);
// We expect only 1 request, but we ask for 2 requests here so that if a misbehaving client
// sends more than 1 requests, ServerCall will catch it. Note that disabling auto
// inbound flow control has no effect on unary calls.
call.request(2);
return new EmptyServerCallListener() {
ReqT request;
@Override
public void onMessage(ReqT request) {
// We delay calling method.invoke() until onHalfClose() to make sure the client
// half-closes.
this.request = request;
}
@Override
public void onHalfClose() {
if (request != null) {
method.invoke(request, responseObserver);
responseObserver.freeze();
if (call.isReady()) {
// Since we are calling invoke in halfClose we have missed the onReady
// event from the transport so recover it here.
onReady();
}
} else {
call.close(Status.INTERNAL.withDescription("Half-closed without a request"),
new Metadata());
}
}
@Override
public void onCancel() {
responseObserver.cancelled = true;
if (responseObserver.onCancelHandler != null) {
responseObserver.onCancelHandler.run();
}
}
@Override
public void onReady() {
if (responseObserver.onReadyHandler != null) {
responseObserver.onReadyHandler.run();
}
}
};
}
};
}
/**
* Creates a {@code ServerCallHandler} for a streaming request call method of the service.
*
* @param method an adaptor to the actual method on the service implementation.
*/
private static ServerCallHandler asyncStreamingRequestCall(
final StreamingRequestMethod method) {
return new ServerCallHandler() {
@Override
public ServerCall.Listener startCall(
final ServerCall call,
Metadata headers) {
final ServerCallStreamObserverImpl responseObserver =
new ServerCallStreamObserverImpl(call);
final StreamObserver requestObserver = method.invoke(responseObserver);
responseObserver.freeze();
if (responseObserver.autoFlowControlEnabled) {
call.request(1);
}
return new EmptyServerCallListener() {
boolean halfClosed = false;
@Override
public void onMessage(ReqT request) {
requestObserver.onNext(request);
// Request delivery of the next inbound message.
if (responseObserver.autoFlowControlEnabled) {
call.request(1);
}
}
@Override
public void onHalfClose() {
halfClosed = true;
requestObserver.onCompleted();
}
@Override
public void onCancel() {
responseObserver.cancelled = true;
if (responseObserver.onCancelHandler != null) {
responseObserver.onCancelHandler.run();
}
if (!halfClosed) {
requestObserver.onError(Status.CANCELLED.asException());
}
}
@Override
public void onReady() {
if (responseObserver.onReadyHandler != null) {
responseObserver.onReadyHandler.run();
}
}
};
}
};
}
private static interface UnaryRequestMethod {
void invoke(ReqT request, StreamObserver responseObserver);
}
private static interface StreamingRequestMethod {
StreamObserver invoke(StreamObserver responseObserver);
}
private static final class ServerCallStreamObserverImpl
extends ServerCallStreamObserver {
final ServerCall call;
volatile boolean cancelled;
private boolean frozen;
private boolean autoFlowControlEnabled = true;
private boolean sentHeaders;
private Runnable onReadyHandler;
private Runnable onCancelHandler;
ServerCallStreamObserverImpl(ServerCall call) {
this.call = call;
}
private void freeze() {
this.frozen = true;
}
@Override
public void setMessageCompression(boolean enable) {
call.setMessageCompression(enable);
}
@Override
public void setCompression(String nl.topicus.jdbc.shaded.com.ression) {
call.setCompression(nl.topicus.jdbc.shaded.com.ression);
}
@Override
public void onNext(RespT response) {
if (cancelled) {
throw Status.CANCELLED.asRuntimeException();
}
if (!sentHeaders) {
call.sendHeaders(new Metadata());
sentHeaders = true;
}
call.sendMessage(response);
}
@Override
public void onError(Throwable t) {
Metadata metadata = Status.trailersFromThrowable(t);
if (metadata == null) {
metadata = new Metadata();
}
call.close(Status.fromThrowable(t), metadata);
}
@Override
public void onCompleted() {
if (cancelled) {
throw Status.CANCELLED.asRuntimeException();
} else {
call.close(Status.OK, new Metadata());
}
}
@Override
public boolean isReady() {
return call.isReady();
}
@Override
public void setOnReadyHandler(Runnable r) {
if (frozen) {
throw new IllegalStateException("Cannot alter onReadyHandler after initialization");
}
this.onReadyHandler = r;
}
@Override
public boolean isCancelled() {
return call.isCancelled();
}
@Override
public void setOnCancelHandler(Runnable onCancelHandler) {
if (frozen) {
throw new IllegalStateException("Cannot alter onCancelHandler after initialization");
}
this.onCancelHandler = onCancelHandler;
}
@Override
public void disableAutoInboundFlowControl() {
if (frozen) {
throw new IllegalStateException("Cannot disable auto flow control after initialization");
} else {
autoFlowControlEnabled = false;
}
}
@Override
public void request(int count) {
call.request(count);
}
}
private static class EmptyServerCallListener extends ServerCall.Listener {
@Override
public void onMessage(ReqT request) {
}
@Override
public void onHalfClose() {
}
@Override
public void onCancel() {
}
@Override
public void onComplete() {
}
}
/**
* Sets unimplemented status for method on given response stream for unary call.
*
* @param methodDescriptor of method for which error will be thrown.
* @param responseObserver on which error will be set.
*/
public static void asyncUnimplementedUnaryCall(MethodDescriptor, ?> methodDescriptor,
StreamObserver> responseObserver) {
checkNotNull(methodDescriptor, "methodDescriptor");
checkNotNull(responseObserver, "responseObserver");
responseObserver.onError(Status.UNIMPLEMENTED
.withDescription(String.format("Method %s is unimplemented",
methodDescriptor.getFullMethodName()))
.asException());
}
/**
* Sets unimplemented status for streaming call.
*
* @param methodDescriptor of method for which error will be thrown.
* @param responseObserver on which error will be set.
*/
public static StreamObserver asyncUnimplementedStreamingCall(
MethodDescriptor, ?> methodDescriptor, StreamObserver> responseObserver) {
// NB: For streaming call we want to do the same as for unary call. Fail-fast by setting error
// on responseObserver and then return no-op observer.
asyncUnimplementedUnaryCall(methodDescriptor, responseObserver);
return new NoopStreamObserver();
}
/**
* No-op implementation of StreamObserver. Used in abstract stubs for default implementations of
* methods which throws UNIMPLEMENTED error and tests.
*/
static class NoopStreamObserver implements StreamObserver {
@Override
public void onNext(V value) {
}
@Override
public void onError(Throwable t) {
}
@Override
public void onCompleted() {
}
}
}