All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glowroot.agent.shaded.grpc.stub.ServerCalls Maven / Gradle / Ivy

There is a newer version: 0.9.28
Show newest version
/*
 * 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 org.glowroot.agent.shaded.grpc.stub;

import org.glowroot.agent.shaded.grpc.ExperimentalApi;
import org.glowroot.agent.shaded.grpc.Metadata;
import org.glowroot.agent.shaded.grpc.MethodDescriptor;
import org.glowroot.agent.shaded.grpc.ServerCall;
import org.glowroot.agent.shaded.grpc.ServerCallHandler;
import org.glowroot.agent.shaded.grpc.Status;

/**
 * Utility functions for adapting {@link ServerCallHandler}s to application service implementation,
 * meant to be used by the generated code.
 */
@ExperimentalApi
public 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(
          MethodDescriptor methodDescriptor,
          final ServerCall call,
          Metadata headers) {
        final ResponseObserver responseObserver = new ResponseObserver(call);
        // We expect only 1 request, but we ask for 2 requests here so that if a misbehaving client
        // sends more than 1 requests, we will catch it in onMessage() and emit INVALID_ARGUMENT.
        call.request(2);
        return new EmptyServerCallListener() {
          ReqT request;
          @Override
          public void onMessage(ReqT request) {
            if (this.request == null) {
              // We delay calling method.invoke() until onHalfClose(), because application may call
              // close(OK) inside invoke(), while close(OK) is not allowed before onHalfClose().
              this.request = request;
            } else {
              call.close(
                  Status.INVALID_ARGUMENT.withDescription(
                      "More than one request messages for unary call or server streaming call"),
                  new Metadata());
            }
          }

          @Override
          public void onHalfClose() {
            if (request != null) {
              method.invoke(request, responseObserver);
            } else {
              call.close(Status.INVALID_ARGUMENT.withDescription("Half-closed without a request"),
                  new Metadata());
            }
          }

          @Override
          public void onCancel() {
            responseObserver.cancelled = true;
          }
        };
      }
    };
  }

  /**
   * 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(
          MethodDescriptor methodDescriptor,
          final ServerCall call,
          Metadata headers) {
        call.request(1);
        final ResponseObserver responseObserver = new ResponseObserver(call);
        final StreamObserver requestObserver = method.invoke(responseObserver);
        return new EmptyServerCallListener() {
          boolean halfClosed = false;

          @Override
          public void onMessage(ReqT request) {
            requestObserver.onNext(request);

            // Request delivery of the next inbound message.
            call.request(1);
          }

          @Override
          public void onHalfClose() {
            halfClosed = true;
            requestObserver.onCompleted();
          }

          @Override
          public void onCancel() {
            if (!halfClosed) {
              requestObserver.onError(Status.CANCELLED.asException());
            }
            responseObserver.cancelled = true;
          }
        };
      }
    };
  }

  private static interface UnaryRequestMethod {
    void invoke(ReqT request, StreamObserver responseObserver);
  }

  private static interface StreamingRequestMethod {
    StreamObserver invoke(StreamObserver responseObserver);
  }

  private static class ResponseObserver implements StreamObserver {
    final ServerCall call;
    volatile boolean cancelled;
    private boolean sentHeaders;

    ResponseObserver(ServerCall call) {
      this.call = call;
    }

    @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) {
      call.close(Status.fromThrowable(t), new Metadata());
    }

    @Override
    public void onCompleted() {
      if (cancelled) {
        throw Status.CANCELLED.asRuntimeException();
      } else {
        call.close(Status.OK, new Metadata());
      }
    }
  }

  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() {
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy