Skip to content

Instantly share code, notes, and snippets.

@nsivabalan
Last active October 28, 2020 20:23
Show Gist options
  • Save nsivabalan/008df807362bca42afbe662b386bf153 to your computer and use it in GitHub Desktop.
Save nsivabalan/008df807362bca42afbe662b386bf153 to your computer and use it in GitHub Desktop.
/**
* UberInterceptor interface is synonymous to {@link UberClientCall}. This class extends {@link
* UberClientCall} and lends way for developers for easy interceptor development. Every new grpc
* call by the client/application, will result in creating a new chain of interceptors and so each
* instance of an interceptor deals with only one grpc call in its lifetime. Any synchronization
* across different calls needs to be abstracted out to a different class and all interceptor copies
* will be accessing the a single instance of such class. For eg: Failover module.
*
* @param <ReqT> request msg of generic type RequestT.
* @param <RespT> response msg of generic type RequestT.
* @param <T> MethodInfo of generic type T.
*/
public class UberInterceptor<ReqT, RespT, T> extends UberClientCall<ReqT, RespT> {
private static final Logger LOGGER = Logger.getLogger(UberInterceptor.class.getName());
protected String identifier;
@Nullable protected UberInterceptor next;
@Nullable protected MethodInfo<T> methodInfo;
@Nullable protected UberInternalCallOptions uberInternalCallOptions;
@Nullable protected UberNetworkListener<RespT> prevListener;
public UberInterceptor(String identifier) {
super();
this.identifier = identifier;
}
// Will be used while chaining multiple interceptors.
public UberInterceptor(String identifier, UberInterceptor next) {
super();
this.identifier = identifier;
this.next = next;
}
/**
* Incase of client interceptors, chaining happens within the {@link UberNetworkingClient} and
* hence after the creation of interceptor. so, can't set next during instantiation.
*
* @param next next interceptor in the chain.
*/
public void setNext(UberInterceptor next) {
this.next = next;
}
/**
* This acts like the constructor which will be invoked to create a new instance on every new grpc
* call.
*
* @param methodInfo method Info of the grpc call of interest.
* @param callOptions instance of {@link UberInternalCallOptions} of the grpc call of interest.
* @return the {@link UberInterceptor} or the {@link UberClientCall} thus created.
*/
public UberInterceptor newCall(MethodInfo<T> methodInfo, UberInternalCallOptions callOptions) {
this.methodInfo = methodInfo;
this.uberInternalCallOptions = callOptions;
if (next != null) {
this.next = this.next.newCall(methodInfo, callOptions);
}
return this;
}
/**
* This method will be invoked by other methods in this abstract class when request headers are
* sent out. Any interceptor implementation can choose to override this method and add its own
* processing logic like adding/editing/removing headers.
*
* @param headers request headers to be sent out as part of this request.
*/
public void onRequestHeaders(UberCallHeaders headers) {}
/**
* This method will be invoked by other methods in this abstract class when request msgs are sent
* out. Any interceptor implementation can choose to override this method and add its own
* processing logic for request msg.
*
* @param message request msg being sent out as part of this request.
*/
public void onRequestMsg(ReqT message) {}
/**
* This method will be invoked by other methods in this abstract class when response headers are
* being received. Any interceptor implementation can choose to override this method and add its
* own processing logic like adding/editing/removing headers.
*
* @param headers request headers to be sent out as part of this request.
*/
public void onResponseHeaders(UberCallHeaders headers) {}
/**
* This method will be invoked by other methods in this abstract class when response msgs are
* received. Any interceptor implementation can choose to override this method and add its own
* processing logic for response msg.
*
* @param message response msg to be sent out as part of this request.
*/
public void onResponseMsg(RespT message) {}
/**
* This method will be invoked by other methods in this abstract class when request is complete.
* Any interceptor implementation can choose to override this method and add its own processing
* logic like failover handling, tracking stats, logging etc.
*
* @param status status object
* @param trailers trailing headers
*/
public void onComplete(UberRequestStatus status, UberCallHeaders trailers) {}
/**
* This will be first call made by the client to register a listener for response handling and to
* send out request headers.
*/
@Override
public void start(UberNetworkListener<RespT> responseListener, UberCallHeaders headers) {
this.prevListener = responseListener;
onRequestHeaders(headers);
if (next != null && methodInfo != null) {
next.start(
new InternalListener<>(
identifier, uberInternalCallOptions, methodInfo, prevListener, this),
headers);
}
}
/** Refer to https://grpc.github.io/grpc-java/javadoc/io/grpc/ClientCall.html for java docs. */
@Override
public void request(int numMessages) {
if (next != null) {
next.request(numMessages);
}
}
/** Refer to https://grpc.github.io/grpc-java/javadoc/io/grpc/ClientCall.html for java docs. */
@Override
public void cancel(@Nullable String message, @Nullable Throwable cause) {
if (next != null) {
next.cancel(message, cause);
}
}
/** Refer to https://grpc.github.io/grpc-java/javadoc/io/grpc/ClientCall.html for java docs. */
@Override
public void halfClose() {
if (next != null) {
next.halfClose();
}
}
/** Refer to https://grpc.github.io/grpc-java/javadoc/io/grpc/ClientCall.html for java docs. */
@Override
public void sendMessage(ReqT message) {
if (next != null && methodInfo != null) {
onRequestMsg(message);
next.sendMessage(message);
}
}
/** Refer to https://grpc.github.io/grpc-java/javadoc/io/grpc/ClientCall.html for java docs. */
@Override
public boolean isReady() {
if (next != null) {
return next.isReady();
}
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment