1 /* 2 * Copyright 2017 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 21 import com.google.common.base.MoreObjects; 22 import javax.annotation.concurrent.ThreadSafe; 23 24 /** 25 * {@link StreamTracer} for the client-side. 26 */ 27 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2861") 28 @ThreadSafe 29 public abstract class ClientStreamTracer extends StreamTracer { 30 /** 31 * The call was delayed due to waiting for name resolution result. 32 */ 33 public static final CallOptions.Key<Boolean> NAME_RESOLUTION_DELAYED = 34 CallOptions.Key.createWithDefault("io.grpc.ClientStreamTracer.NAME_RESOLUTION_DELAYED", 35 false); 36 37 /** 38 * The stream is being created on a ready transport. 39 * 40 * @param headers the mutable initial metadata. Modifications to it will be sent to the socket but 41 * not be seen by client interceptors and the application. 42 * 43 * @since 1.40.0 44 */ streamCreated(@rpc.TransportAttr Attributes transportAttrs, Metadata headers)45 public void streamCreated(@Grpc.TransportAttr Attributes transportAttrs, Metadata headers) { 46 } 47 48 /** 49 * Name resolution is completed and the connection starts getting established. This method is only 50 * invoked on the streams that encounter such delay. 51 * 52 * </p>gRPC buffers the client call if the remote address and configurations, e.g. timeouts and 53 * retry policy, are not ready. Asynchronously gRPC internally does the name resolution to get 54 * this information. The streams that are processed immediately on ready transports by the time 55 * the RPC comes do not go through the pending process, thus this callback will not be invoked. 56 */ createPendingStream()57 public void createPendingStream() { 58 } 59 60 /** 61 * Headers has been sent to the socket. 62 */ outboundHeaders()63 public void outboundHeaders() { 64 } 65 66 /** 67 * Headers has been received from the server. 68 */ inboundHeaders()69 public void inboundHeaders() { 70 } 71 72 /** 73 * Trailing metadata has been received from the server. 74 * 75 * @param trailers the mutable trailing metadata. Modifications to it will be seen by 76 * interceptors and the application. 77 * @since 1.17.0 78 */ inboundTrailers(Metadata trailers)79 public void inboundTrailers(Metadata trailers) { 80 } 81 82 /** 83 * Factory class for {@link ClientStreamTracer}. 84 */ 85 public abstract static class Factory { 86 /** 87 * Creates a {@link ClientStreamTracer} for a new client stream. This is called inside the 88 * transport when it's creating the stream. 89 * 90 * @param info information about the stream 91 * @param headers the mutable headers of the stream. It can be safely mutated within this 92 * method. Changes made to it will be sent by the stream. It should not be saved 93 * because it is not safe for read or write after the method returns. 94 * 95 * @since 1.20.0 96 */ newClientStreamTracer(StreamInfo info, Metadata headers)97 public ClientStreamTracer newClientStreamTracer(StreamInfo info, Metadata headers) { 98 throw new UnsupportedOperationException("Not implemented"); 99 } 100 } 101 102 /** 103 * Information about a stream. 104 * 105 * <p>Note this class doesn't override {@code equals()} and {@code hashCode}, as is the case for 106 * {@link CallOptions}. 107 * 108 * @since 1.20.0 109 */ 110 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2861") 111 public static final class StreamInfo { 112 private final CallOptions callOptions; 113 private final int previousAttempts; 114 private final boolean isTransparentRetry; 115 StreamInfo( CallOptions callOptions, int previousAttempts, boolean isTransparentRetry)116 StreamInfo( 117 CallOptions callOptions, int previousAttempts, boolean isTransparentRetry) { 118 this.callOptions = checkNotNull(callOptions, "callOptions"); 119 this.previousAttempts = previousAttempts; 120 this.isTransparentRetry = isTransparentRetry; 121 } 122 123 /** 124 * Returns the effective CallOptions of the call. 125 */ getCallOptions()126 public CallOptions getCallOptions() { 127 return callOptions; 128 } 129 130 /** 131 * Returns the number of preceding attempts for the RPC. 132 * 133 * @since 1.40.0 134 */ getPreviousAttempts()135 public int getPreviousAttempts() { 136 return previousAttempts; 137 } 138 139 /** 140 * Whether the stream is a transparent retry. 141 * 142 * @since 1.40.0 143 */ isTransparentRetry()144 public boolean isTransparentRetry() { 145 return isTransparentRetry; 146 } 147 148 /** 149 * Converts this StreamInfo into a new Builder. 150 * 151 * @since 1.21.0 152 */ toBuilder()153 public Builder toBuilder() { 154 return new Builder() 155 .setCallOptions(callOptions) 156 .setPreviousAttempts(previousAttempts) 157 .setIsTransparentRetry(isTransparentRetry); 158 } 159 160 /** 161 * Creates an empty Builder. 162 * 163 * @since 1.21.0 164 */ newBuilder()165 public static Builder newBuilder() { 166 return new Builder(); 167 } 168 169 @Override toString()170 public String toString() { 171 return MoreObjects.toStringHelper(this) 172 .add("callOptions", callOptions) 173 .add("previousAttempts", previousAttempts) 174 .add("isTransparentRetry", isTransparentRetry) 175 .toString(); 176 } 177 178 /** 179 * Builds {@link StreamInfo} objects. 180 * 181 * @since 1.21.0 182 */ 183 public static final class Builder { 184 private CallOptions callOptions = CallOptions.DEFAULT; 185 private int previousAttempts; 186 private boolean isTransparentRetry; 187 Builder()188 Builder() { 189 } 190 191 /** 192 * Sets the effective CallOptions of the call. This field is optional. 193 */ setCallOptions(CallOptions callOptions)194 public Builder setCallOptions(CallOptions callOptions) { 195 this.callOptions = checkNotNull(callOptions, "callOptions cannot be null"); 196 return this; 197 } 198 199 /** 200 * Set the number of preceding attempts of the RPC. 201 * 202 * @since 1.40.0 203 */ setPreviousAttempts(int previousAttempts)204 public Builder setPreviousAttempts(int previousAttempts) { 205 this.previousAttempts = previousAttempts; 206 return this; 207 } 208 209 /** 210 * Sets whether the stream is a transparent retry. 211 * 212 * @since 1.40.0 213 */ setIsTransparentRetry(boolean isTransparentRetry)214 public Builder setIsTransparentRetry(boolean isTransparentRetry) { 215 this.isTransparentRetry = isTransparentRetry; 216 return this; 217 } 218 219 /** 220 * Builds a new StreamInfo. 221 */ build()222 public StreamInfo build() { 223 return new StreamInfo(callOptions, previousAttempts, isTransparentRetry); 224 } 225 } 226 } 227 } 228