1 /* 2 * Copyright 2014 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 com.google.common.base.Preconditions; 23 import java.io.InputStream; 24 import java.util.concurrent.atomic.AtomicReferenceArray; 25 import javax.annotation.CheckReturnValue; 26 import javax.annotation.Nullable; 27 import javax.annotation.concurrent.Immutable; 28 29 /** 30 * Description of a remote method used by {@link Channel} to initiate a call. 31 * 32 * <p>Provides the name of the operation to execute as well as {@link Marshaller} instances 33 * used to parse and serialize request and response messages. 34 * 35 * <p>Can be constructed manually but will often be generated by stub code generators. 36 * 37 * @since 1.0.0 38 */ 39 @Immutable 40 public final class MethodDescriptor<ReqT, RespT> { 41 42 private final MethodType type; 43 private final String fullMethodName; 44 private final Marshaller<ReqT> requestMarshaller; 45 private final Marshaller<RespT> responseMarshaller; 46 private final @Nullable Object schemaDescriptor; 47 private final boolean idempotent; 48 private final boolean safe; 49 private final boolean sampledToLocalTracing; 50 51 // Must be set to InternalKnownTransport.values().length 52 // Not referenced to break the dependency. 53 private final AtomicReferenceArray<Object> rawMethodNames = new AtomicReferenceArray<Object>(1); 54 55 56 /** 57 * Gets the cached "raw" method name for this Method Descriptor. The raw name is transport 58 * specific, and should be set using {@link #setRawMethodName} by the transport. 59 * 60 * @param transportOrdinal the unique ID of the transport, given by 61 * {@link InternalKnownTransport#ordinal}. 62 * @return a transport specific representation of the method name. 63 */ getRawMethodName(int transportOrdinal)64 final Object getRawMethodName(int transportOrdinal) { 65 return rawMethodNames.get(transportOrdinal); 66 } 67 68 /** 69 * Safely, but weakly, sets the raw method name for this Method Descriptor. This should only be 70 * called by the transport. See {@link #getRawMethodName} for more detail. 71 */ setRawMethodName(int transportOrdinal, Object o)72 final void setRawMethodName(int transportOrdinal, Object o) { 73 rawMethodNames.lazySet(transportOrdinal, o); 74 } 75 76 /** 77 * The call type of a method. 78 * 79 * @since 1.0.0 80 */ 81 public enum MethodType { 82 /** 83 * One request message followed by one response message. 84 */ 85 UNARY, 86 87 /** 88 * Zero or more request messages followed by one response message. 89 */ 90 CLIENT_STREAMING, 91 92 /** 93 * One request message followed by zero or more response messages. 94 */ 95 SERVER_STREAMING, 96 97 /** 98 * Zero or more request and response messages arbitrarily interleaved in time. 99 */ 100 BIDI_STREAMING, 101 102 /** 103 * Cardinality and temporal relationships are not known. Implementations should not make 104 * buffering assumptions and should largely treat the same as {@link #BIDI_STREAMING}. 105 */ 106 UNKNOWN; 107 108 /** 109 * Returns {@code true} if the client will immediately send one request message to the server 110 * after calling {@link ClientCall#start(io.grpc.ClientCall.Listener, io.grpc.Metadata)} 111 * and then immediately half-close the stream by calling {@link io.grpc.ClientCall#halfClose()}. 112 * 113 * @since 1.0.0 114 */ clientSendsOneMessage()115 public final boolean clientSendsOneMessage() { 116 return this == UNARY || this == SERVER_STREAMING; 117 } 118 119 /** 120 * Returns {@code true} if the server will immediately send one response message to the client 121 * upon receipt of {@link io.grpc.ServerCall.Listener#onHalfClose()} and then immediately 122 * close the stream by calling {@link ServerCall#close(Status, io.grpc.Metadata)}. 123 * 124 * @since 1.0.0 125 */ serverSendsOneMessage()126 public final boolean serverSendsOneMessage() { 127 return this == UNARY || this == CLIENT_STREAMING; 128 } 129 } 130 131 /** 132 * A typed abstraction over message serialization and deserialization, a.k.a. marshalling and 133 * unmarshalling. 134 * 135 * <p>Stub implementations will define implementations of this interface for each of the request 136 * and response messages provided by a service. 137 * 138 * @param <T> type of serializable message 139 * @since 1.0.0 140 */ 141 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1777") 142 public interface Marshaller<T> { 143 /** 144 * Given a message, produce an {@link InputStream} for it so that it can be written to the wire. 145 * Where possible implementations should produce streams that are {@link io.grpc.KnownLength} 146 * to improve transport efficiency. 147 * 148 * @param value to serialize. 149 * @return serialized value as stream of bytes. 150 */ stream(T value)151 public InputStream stream(T value); 152 153 /** 154 * Given an {@link InputStream} parse it into an instance of the declared type so that it can be 155 * passed to application code. 156 * 157 * @param stream of bytes for serialized value 158 * @return parsed value 159 */ parse(InputStream stream)160 public T parse(InputStream stream); 161 } 162 163 /** 164 * A marshaller that supports retrieving it's type parameter {@code T} at runtime. 165 * 166 * @since 1.1.0 167 */ 168 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2222") 169 public interface ReflectableMarshaller<T> extends Marshaller<T> { 170 /** 171 * Returns the {@code Class} that this marshaller serializes and deserializes. If inheritance is 172 * allowed, this is the base class or interface for all supported classes. 173 * 174 * @return non-{@code null} base class for all objects produced and consumed by this marshaller 175 */ getMessageClass()176 public Class<T> getMessageClass(); 177 } 178 179 /** 180 * A marshaller that uses a fixed instance of the type it produces. 181 * 182 * @since 1.1.0 183 */ 184 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2222") 185 public interface PrototypeMarshaller<T> extends ReflectableMarshaller<T> { 186 /** 187 * An instance of the expected message type, typically used as a schema and helper for producing 188 * other message instances. The {@code null} value may be a special value for the marshaller 189 * (like the equivalent of {@link Void}), so it is a valid return value. {@code null} does 190 * <em>not</em> mean "unsupported" or "unknown". 191 * 192 * <p>It is generally expected this would return the same instance each invocation, but it is 193 * not a requirement. 194 */ 195 @Nullable getMessagePrototype()196 public T getMessagePrototype(); 197 } 198 199 /** 200 * Creates a new {@code MethodDescriptor}. 201 * 202 * @param type the call type of this method 203 * @param fullMethodName the fully qualified name of this method 204 * @param requestMarshaller the marshaller used to encode and decode requests 205 * @param responseMarshaller the marshaller used to encode and decode responses 206 * @since 1.0.0 207 * @deprecated use {@link #newBuilder()}. 208 */ 209 @Deprecated create( MethodType type, String fullMethodName, Marshaller<RequestT> requestMarshaller, Marshaller<ResponseT> responseMarshaller)210 public static <RequestT, ResponseT> MethodDescriptor<RequestT, ResponseT> create( 211 MethodType type, String fullMethodName, 212 Marshaller<RequestT> requestMarshaller, 213 Marshaller<ResponseT> responseMarshaller) { 214 return new MethodDescriptor<RequestT, ResponseT>( 215 type, fullMethodName, requestMarshaller, responseMarshaller, null, false, false, false); 216 } 217 MethodDescriptor( MethodType type, String fullMethodName, Marshaller<ReqT> requestMarshaller, Marshaller<RespT> responseMarshaller, Object schemaDescriptor, boolean idempotent, boolean safe, boolean sampledToLocalTracing)218 private MethodDescriptor( 219 MethodType type, 220 String fullMethodName, 221 Marshaller<ReqT> requestMarshaller, 222 Marshaller<RespT> responseMarshaller, 223 Object schemaDescriptor, 224 boolean idempotent, 225 boolean safe, 226 boolean sampledToLocalTracing) { 227 228 this.type = Preconditions.checkNotNull(type, "type"); 229 this.fullMethodName = Preconditions.checkNotNull(fullMethodName, "fullMethodName"); 230 this.requestMarshaller = Preconditions.checkNotNull(requestMarshaller, "requestMarshaller"); 231 this.responseMarshaller = Preconditions.checkNotNull(responseMarshaller, "responseMarshaller"); 232 this.schemaDescriptor = schemaDescriptor; 233 this.idempotent = idempotent; 234 this.safe = safe; 235 this.sampledToLocalTracing = sampledToLocalTracing; 236 Preconditions.checkArgument(!safe || type == MethodType.UNARY, 237 "Only unary methods can be specified safe"); 238 } 239 240 /** 241 * The call type of the method. 242 * 243 * @since 1.0.0 244 */ getType()245 public MethodType getType() { 246 return type; 247 } 248 249 /** 250 * The fully qualified name of the method. 251 * 252 * @since 1.0.0 253 */ getFullMethodName()254 public String getFullMethodName() { 255 return fullMethodName; 256 } 257 258 /** 259 * Parse a response payload from the given {@link InputStream}. 260 * 261 * @param input stream containing response message to parse. 262 * @return parsed response message object. 263 * @since 1.0.0 264 */ parseResponse(InputStream input)265 public RespT parseResponse(InputStream input) { 266 return responseMarshaller.parse(input); 267 } 268 269 /** 270 * Convert a request message to an {@link InputStream}. 271 * The returned InputStream should be closed by the caller. 272 * 273 * @param requestMessage to serialize using the request {@link Marshaller}. 274 * @return serialized request message. 275 * @since 1.0.0 276 */ streamRequest(ReqT requestMessage)277 public InputStream streamRequest(ReqT requestMessage) { 278 return requestMarshaller.stream(requestMessage); 279 } 280 281 /** 282 * Parse an incoming request message. 283 * 284 * @param input the serialized message as a byte stream. 285 * @return a parsed instance of the message. 286 * @since 1.0.0 287 */ parseRequest(InputStream input)288 public ReqT parseRequest(InputStream input) { 289 return requestMarshaller.parse(input); 290 } 291 292 /** 293 * Serialize an outgoing response message. 294 * The returned InputStream should be closed by the caller. 295 * 296 * @param response the response message to serialize. 297 * @return the serialized message as a byte stream. 298 * @since 1.0.0 299 */ streamResponse(RespT response)300 public InputStream streamResponse(RespT response) { 301 return responseMarshaller.stream(response); 302 } 303 304 /** 305 * Returns the marshaller for the request type. Allows introspection of the request marshaller. 306 * 307 * @since 1.1.0 308 */ 309 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2592") getRequestMarshaller()310 public Marshaller<ReqT> getRequestMarshaller() { 311 return requestMarshaller; 312 } 313 314 /** 315 * Returns the marshaller for the response type. Allows introspection of the response marshaller. 316 * 317 * @since 1.1.0 318 */ 319 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2592") getResponseMarshaller()320 public Marshaller<RespT> getResponseMarshaller() { 321 return responseMarshaller; 322 } 323 324 /** 325 * Returns the schema descriptor for this method. A schema descriptor is an object that is not 326 * used by gRPC core but includes information related to the service method. The type of the 327 * object is specific to the consumer, so both the code setting the schema descriptor and the code 328 * calling {@link #getSchemaDescriptor()} must coordinate. For example, protobuf generated code 329 * sets this value, in order to be consumed by the server reflection service. See also: 330 * {@code io.grpc.protobuf.ProtoMethodDescriptorSupplier}. 331 * 332 * @since 1.7.0 333 */ getSchemaDescriptor()334 public @Nullable Object getSchemaDescriptor() { 335 return schemaDescriptor; 336 } 337 338 /** 339 * Returns whether this method is idempotent. 340 * 341 * @since 1.0.0 342 */ 343 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1775") isIdempotent()344 public boolean isIdempotent() { 345 return idempotent; 346 } 347 348 /** 349 * Returns whether this method is safe. 350 * 351 * <p>A safe request does nothing except retrieval so it has no side effects on the server side. 352 * 353 * @since 1.1.0 354 */ 355 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1775") isSafe()356 public boolean isSafe() { 357 return safe; 358 } 359 360 /** 361 * Returns whether RPCs for this method may be sampled into the local tracing store. 362 */ isSampledToLocalTracing()363 public boolean isSampledToLocalTracing() { 364 return sampledToLocalTracing; 365 } 366 367 /** 368 * Generate the fully qualified method name. This matches the the name 369 * 370 * @param fullServiceName the fully qualified service name that is prefixed with the package name 371 * @param methodName the short method name 372 * @since 1.0.0 373 */ generateFullMethodName(String fullServiceName, String methodName)374 public static String generateFullMethodName(String fullServiceName, String methodName) { 375 return checkNotNull(fullServiceName, "fullServiceName") 376 + "/" 377 + checkNotNull(methodName, "methodName"); 378 } 379 380 /** 381 * Extract the fully qualified service name out of a fully qualified method name. May return 382 * {@code null} if the input is malformed, but you cannot rely on it for the validity of the 383 * input. 384 * 385 * @since 1.0.0 386 */ 387 @Nullable extractFullServiceName(String fullMethodName)388 public static String extractFullServiceName(String fullMethodName) { 389 int index = checkNotNull(fullMethodName, "fullMethodName").lastIndexOf('/'); 390 if (index == -1) { 391 return null; 392 } 393 return fullMethodName.substring(0, index); 394 } 395 396 /** 397 * Creates a new builder for a {@link MethodDescriptor}. 398 * 399 * @since 1.1.0 400 */ 401 @CheckReturnValue newBuilder()402 public static <ReqT, RespT> Builder<ReqT, RespT> newBuilder() { 403 return newBuilder(null, null); 404 } 405 406 /** 407 * Creates a new builder for a {@link MethodDescriptor}. 408 * 409 * @since 1.1.0 410 */ 411 @CheckReturnValue newBuilder( Marshaller<ReqT> requestMarshaller, Marshaller<RespT> responseMarshaller)412 public static <ReqT, RespT> Builder<ReqT, RespT> newBuilder( 413 Marshaller<ReqT> requestMarshaller, Marshaller<RespT> responseMarshaller) { 414 return new Builder<ReqT, RespT>() 415 .setRequestMarshaller(requestMarshaller) 416 .setResponseMarshaller(responseMarshaller); 417 } 418 419 /** 420 * Turns this descriptor into a builder. 421 * 422 * @since 1.1.0 423 */ 424 @CheckReturnValue toBuilder()425 public Builder<ReqT, RespT> toBuilder() { 426 return toBuilder(requestMarshaller, responseMarshaller); 427 } 428 429 /** 430 * Turns this descriptor into a builder, replacing the request and response marshallers. 431 * 432 * @since 1.1.0 433 */ 434 @CheckReturnValue toBuilder( Marshaller<NewReqT> requestMarshaller, Marshaller<NewRespT> responseMarshaller)435 public <NewReqT, NewRespT> Builder<NewReqT, NewRespT> toBuilder( 436 Marshaller<NewReqT> requestMarshaller, Marshaller<NewRespT> responseMarshaller) { 437 return MethodDescriptor.<NewReqT, NewRespT>newBuilder() 438 .setRequestMarshaller(requestMarshaller) 439 .setResponseMarshaller(responseMarshaller) 440 .setType(type) 441 .setFullMethodName(fullMethodName) 442 .setIdempotent(idempotent) 443 .setSafe(safe) 444 .setSampledToLocalTracing(sampledToLocalTracing) 445 .setSchemaDescriptor(schemaDescriptor); 446 } 447 448 /** 449 * A builder for a {@link MethodDescriptor}. 450 * 451 * @since 1.1.0 452 */ 453 public static final class Builder<ReqT, RespT> { 454 455 private Marshaller<ReqT> requestMarshaller; 456 private Marshaller<RespT> responseMarshaller; 457 private MethodType type; 458 private String fullMethodName; 459 private boolean idempotent; 460 private boolean safe; 461 private Object schemaDescriptor; 462 private boolean sampledToLocalTracing; 463 Builder()464 private Builder() {} 465 466 /** 467 * Sets the request marshaller. 468 * 469 * @param requestMarshaller the marshaller to use. 470 * @since 1.1.0 471 */ setRequestMarshaller(Marshaller<ReqT> requestMarshaller)472 public Builder<ReqT, RespT> setRequestMarshaller(Marshaller<ReqT> requestMarshaller) { 473 this.requestMarshaller = requestMarshaller; 474 return this; 475 } 476 477 /** 478 * Sets the response marshaller. 479 * 480 * @param responseMarshaller the marshaller to use. 481 * @since 1.1.0 482 */ 483 @SuppressWarnings("unchecked") setResponseMarshaller(Marshaller<RespT> responseMarshaller)484 public Builder<ReqT, RespT> setResponseMarshaller(Marshaller<RespT> responseMarshaller) { 485 this.responseMarshaller = responseMarshaller; 486 return this; 487 } 488 489 /** 490 * Sets the method type. 491 * 492 * @param type the type of the method. 493 * @since 1.1.0 494 */ setType(MethodType type)495 public Builder<ReqT, RespT> setType(MethodType type) { 496 this.type = type; 497 return this; 498 } 499 500 /** 501 * Sets the fully qualified (service and method) method name. 502 * 503 * @see MethodDescriptor#generateFullMethodName 504 * @since 1.1.0 505 */ setFullMethodName(String fullMethodName)506 public Builder<ReqT, RespT> setFullMethodName(String fullMethodName) { 507 this.fullMethodName = fullMethodName; 508 return this; 509 } 510 511 /** 512 * Sets the schema descriptor for this builder. A schema descriptor is an object that is not 513 * used by gRPC core but includes information related to the methods. The type of the object 514 * is specific to the consumer, so both the code calling this and the code calling 515 * {@link MethodDescriptor#getSchemaDescriptor()} must coordinate. 516 * 517 * @param schemaDescriptor an object that describes the service structure. Should be immutable. 518 * @since 1.7.0 519 */ setSchemaDescriptor(@ullable Object schemaDescriptor)520 public Builder<ReqT, RespT> setSchemaDescriptor(@Nullable Object schemaDescriptor) { 521 this.schemaDescriptor = schemaDescriptor; 522 return this; 523 } 524 525 /** 526 * Sets whether the method is idempotent. If true, calling this method more than once doesn't 527 * have additional side effects. 528 * 529 * @since 1.1.0 530 */ 531 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1775") setIdempotent(boolean idempotent)532 public Builder<ReqT, RespT> setIdempotent(boolean idempotent) { 533 this.idempotent = idempotent; 534 return this; 535 } 536 537 /** 538 * Sets whether this method is safe. If true, calling this method any number of times doesn't 539 * have side effects. 540 * 541 * @since 1.1.0 542 */ 543 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1775") setSafe(boolean safe)544 public Builder<ReqT, RespT> setSafe(boolean safe) { 545 this.safe = safe; 546 return this; 547 } 548 549 /** 550 * Sets whether RPCs for this method may be sampled into the local tracing store. If true, 551 * sampled traces of this method may be kept in memory by tracing libraries. 552 * 553 * @since 1.8.0 554 */ setSampledToLocalTracing(boolean value)555 public Builder<ReqT, RespT> setSampledToLocalTracing(boolean value) { 556 this.sampledToLocalTracing = value; 557 return this; 558 } 559 560 /** 561 * Builds the method descriptor. 562 * 563 * @since 1.1.0 564 */ 565 @CheckReturnValue build()566 public MethodDescriptor<ReqT, RespT> build() { 567 return new MethodDescriptor<ReqT, RespT>( 568 type, 569 fullMethodName, 570 requestMarshaller, 571 responseMarshaller, 572 schemaDescriptor, 573 idempotent, 574 safe, 575 sampledToLocalTracing); 576 } 577 } 578 579 @Override toString()580 public String toString() { 581 return MoreObjects.toStringHelper(this) 582 .add("fullMethodName", fullMethodName) 583 .add("type", type) 584 .add("idempotent", idempotent) 585 .add("safe", safe) 586 .add("sampledToLocalTracing", sampledToLocalTracing) 587 .add("requestMarshaller", requestMarshaller) 588 .add("responseMarshaller", responseMarshaller) 589 .add("schemaDescriptor", schemaDescriptor) 590 .omitNullValues() 591 .toString(); 592 } 593 } 594