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 @Nullable private final String serviceName; 45 private final Marshaller<ReqT> requestMarshaller; 46 private final Marshaller<RespT> responseMarshaller; 47 private final @Nullable Object schemaDescriptor; 48 private final boolean idempotent; 49 private final boolean safe; 50 private final boolean sampledToLocalTracing; 51 52 // Must be set to InternalKnownTransport.values().length 53 // Not referenced to break the dependency. 54 private final AtomicReferenceArray<Object> rawMethodNames = new AtomicReferenceArray<>(2); 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 with 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} for {@code UNARY} and {@code SERVER_STREAMING}, which do not permit the 110 * client to stream. 111 * 112 * @since 1.0.0 113 */ clientSendsOneMessage()114 public final boolean clientSendsOneMessage() { 115 return this == UNARY || this == SERVER_STREAMING; 116 } 117 118 /** 119 * Returns {@code true} for {@code UNARY} and {@code CLIENT_STREAMING}, which do not permit the 120 * server to stream. 121 * 122 * @since 1.0.0 123 */ serverSendsOneMessage()124 public final boolean serverSendsOneMessage() { 125 return this == UNARY || this == CLIENT_STREAMING; 126 } 127 } 128 129 /** 130 * A typed abstraction over message serialization and deserialization, a.k.a. marshalling and 131 * unmarshalling. 132 * 133 * <p>Stub implementations will define implementations of this interface for each of the request 134 * and response messages provided by a service. 135 * 136 * @param <T> type of serializable message 137 * @since 1.0.0 138 */ 139 public interface Marshaller<T> { 140 /** 141 * Given a message, produce an {@link InputStream} for it so that it can be written to the wire. 142 * Where possible implementations should produce streams that are {@link io.grpc.KnownLength} 143 * to improve transport efficiency. 144 * 145 * @param value to serialize. 146 * @return serialized value as stream of bytes. 147 */ stream(T value)148 public InputStream stream(T value); 149 150 /** 151 * Given an {@link InputStream} parse it into an instance of the declared type so that it can be 152 * passed to application code. 153 * 154 * @param stream of bytes for serialized value 155 * @return parsed value 156 */ parse(InputStream stream)157 public T parse(InputStream stream); 158 } 159 160 /** 161 * A marshaller that supports retrieving it's type parameter {@code T} at runtime. 162 * 163 * @since 1.1.0 164 */ 165 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2222") 166 public interface ReflectableMarshaller<T> extends Marshaller<T> { 167 /** 168 * Returns the {@code Class} that this marshaller serializes and deserializes. If inheritance is 169 * allowed, this is the base class or interface for all supported classes. 170 * 171 * @return non-{@code null} base class for all objects produced and consumed by this marshaller 172 */ getMessageClass()173 public Class<T> getMessageClass(); 174 } 175 176 /** 177 * A marshaller that uses a fixed instance of the type it produces. 178 * 179 * @since 1.1.0 180 */ 181 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2222") 182 public interface PrototypeMarshaller<T> extends ReflectableMarshaller<T> { 183 /** 184 * An instance of the expected message type, typically used as a schema and helper for producing 185 * other message instances. The {@code null} value may be a special value for the marshaller 186 * (like the equivalent of {@link Void}), so it is a valid return value. {@code null} does 187 * <em>not</em> mean "unsupported" or "unknown". 188 * 189 * <p>It is generally expected this would return the same instance each invocation, but it is 190 * not a requirement. 191 */ 192 @Nullable getMessagePrototype()193 public T getMessagePrototype(); 194 } 195 196 /** 197 * Creates a new {@code MethodDescriptor}. 198 * 199 * @param type the call type of this method 200 * @param fullMethodName the fully qualified name of this method 201 * @param requestMarshaller the marshaller used to encode and decode requests 202 * @param responseMarshaller the marshaller used to encode and decode responses 203 * @since 1.0.0 204 * @deprecated use {@link #newBuilder()}. 205 */ 206 @Deprecated create( MethodType type, String fullMethodName, Marshaller<RequestT> requestMarshaller, Marshaller<ResponseT> responseMarshaller)207 public static <RequestT, ResponseT> MethodDescriptor<RequestT, ResponseT> create( 208 MethodType type, String fullMethodName, 209 Marshaller<RequestT> requestMarshaller, 210 Marshaller<ResponseT> responseMarshaller) { 211 return new MethodDescriptor<>( 212 type, fullMethodName, requestMarshaller, responseMarshaller, null, false, false, false); 213 } 214 MethodDescriptor( MethodType type, String fullMethodName, Marshaller<ReqT> requestMarshaller, Marshaller<RespT> responseMarshaller, Object schemaDescriptor, boolean idempotent, boolean safe, boolean sampledToLocalTracing)215 private MethodDescriptor( 216 MethodType type, 217 String fullMethodName, 218 Marshaller<ReqT> requestMarshaller, 219 Marshaller<RespT> responseMarshaller, 220 Object schemaDescriptor, 221 boolean idempotent, 222 boolean safe, 223 boolean sampledToLocalTracing) { 224 assert !safe || idempotent : "safe should imply idempotent"; 225 this.type = Preconditions.checkNotNull(type, "type"); 226 this.fullMethodName = Preconditions.checkNotNull(fullMethodName, "fullMethodName"); 227 this.serviceName = extractFullServiceName(fullMethodName); 228 this.requestMarshaller = Preconditions.checkNotNull(requestMarshaller, "requestMarshaller"); 229 this.responseMarshaller = Preconditions.checkNotNull(responseMarshaller, "responseMarshaller"); 230 this.schemaDescriptor = schemaDescriptor; 231 this.idempotent = idempotent; 232 this.safe = safe; 233 this.sampledToLocalTracing = sampledToLocalTracing; 234 } 235 236 /** 237 * The call type of the method. 238 * 239 * @since 1.0.0 240 */ getType()241 public MethodType getType() { 242 return type; 243 } 244 245 /** 246 * The fully qualified name of the method. 247 * 248 * @since 1.0.0 249 */ getFullMethodName()250 public String getFullMethodName() { 251 return fullMethodName; 252 } 253 254 /** 255 * A convenience method for {@code extractFullServiceName(getFullMethodName())}. 256 * 257 * @since 1.21.0 258 */ 259 @Nullable 260 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/5635") getServiceName()261 public String getServiceName() { 262 return serviceName; 263 } 264 265 /** 266 * A convenience method for {@code extractBareMethodName(getFullMethodName())}. 267 * 268 * @since 1.33.0 269 */ 270 @Nullable 271 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/5635") getBareMethodName()272 public String getBareMethodName() { 273 return extractBareMethodName(fullMethodName); 274 } 275 276 /** 277 * Parse a response payload from the given {@link InputStream}. 278 * 279 * @param input stream containing response message to parse. 280 * @return parsed response message object. 281 * @since 1.0.0 282 */ parseResponse(InputStream input)283 public RespT parseResponse(InputStream input) { 284 return responseMarshaller.parse(input); 285 } 286 287 /** 288 * Convert a request message to an {@link InputStream}. 289 * The returned InputStream should be closed by the caller. 290 * 291 * @param requestMessage to serialize using the request {@link Marshaller}. 292 * @return serialized request message. 293 * @since 1.0.0 294 */ streamRequest(ReqT requestMessage)295 public InputStream streamRequest(ReqT requestMessage) { 296 return requestMarshaller.stream(requestMessage); 297 } 298 299 /** 300 * Parse an incoming request message. 301 * 302 * @param input the serialized message as a byte stream. 303 * @return a parsed instance of the message. 304 * @since 1.0.0 305 */ parseRequest(InputStream input)306 public ReqT parseRequest(InputStream input) { 307 return requestMarshaller.parse(input); 308 } 309 310 /** 311 * Serialize an outgoing response message. 312 * The returned InputStream should be closed by the caller. 313 * 314 * @param response the response message to serialize. 315 * @return the serialized message as a byte stream. 316 * @since 1.0.0 317 */ streamResponse(RespT response)318 public InputStream streamResponse(RespT response) { 319 return responseMarshaller.stream(response); 320 } 321 322 /** 323 * Returns the marshaller for the request type. Allows introspection of the request marshaller. 324 * 325 * @since 1.1.0 326 */ 327 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2592") getRequestMarshaller()328 public Marshaller<ReqT> getRequestMarshaller() { 329 return requestMarshaller; 330 } 331 332 /** 333 * Returns the marshaller for the response type. Allows introspection of the response marshaller. 334 * 335 * @since 1.1.0 336 */ 337 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2592") getResponseMarshaller()338 public Marshaller<RespT> getResponseMarshaller() { 339 return responseMarshaller; 340 } 341 342 /** 343 * Returns the schema descriptor for this method. A schema descriptor is an object that is not 344 * used by gRPC core but includes information related to the service method. The type of the 345 * object is specific to the consumer, so both the code setting the schema descriptor and the code 346 * calling {@link #getSchemaDescriptor()} must coordinate. For example, protobuf generated code 347 * sets this value, in order to be consumed by the server reflection service. See also: 348 * {@code io.grpc.protobuf.ProtoMethodDescriptorSupplier}. 349 * 350 * @since 1.7.0 351 */ getSchemaDescriptor()352 public @Nullable Object getSchemaDescriptor() { 353 return schemaDescriptor; 354 } 355 356 /** 357 * Returns whether this method is idempotent. 358 * 359 * @since 1.0.0 360 */ isIdempotent()361 public boolean isIdempotent() { 362 return idempotent; 363 } 364 365 /** 366 * Returns whether this method is safe. 367 * 368 * <p>A safe request does nothing except retrieval so it has no side effects on the server side. 369 * 370 * @since 1.1.0 371 */ isSafe()372 public boolean isSafe() { 373 return safe; 374 } 375 376 /** 377 * Returns whether RPCs for this method may be sampled into the local tracing store. 378 */ isSampledToLocalTracing()379 public boolean isSampledToLocalTracing() { 380 return sampledToLocalTracing; 381 } 382 383 /** 384 * Generate the fully qualified method name. This matches the name 385 * 386 * @param fullServiceName the fully qualified service name that is prefixed with the package name 387 * @param methodName the short method name 388 * @since 1.0.0 389 */ generateFullMethodName(String fullServiceName, String methodName)390 public static String generateFullMethodName(String fullServiceName, String methodName) { 391 return checkNotNull(fullServiceName, "fullServiceName") 392 + "/" 393 + checkNotNull(methodName, "methodName"); 394 } 395 396 /** 397 * Extract the fully qualified service name out of a fully qualified method name. May return 398 * {@code null} if the input is malformed, but you cannot rely on it for the validity of the 399 * input. 400 * 401 * @since 1.0.0 402 */ 403 @Nullable extractFullServiceName(String fullMethodName)404 public static String extractFullServiceName(String fullMethodName) { 405 int index = checkNotNull(fullMethodName, "fullMethodName").lastIndexOf('/'); 406 if (index == -1) { 407 return null; 408 } 409 return fullMethodName.substring(0, index); 410 } 411 412 /** 413 * Extract the method name out of a fully qualified method name. May return {@code null} 414 * if the input is malformed, but you cannot rely on it for the validity of the input. 415 * 416 * @since 1.33.0 417 */ 418 @Nullable 419 @ExperimentalApi("https://github.com/grpc/grpc-java/issues/5635") extractBareMethodName(String fullMethodName)420 public static String extractBareMethodName(String fullMethodName) { 421 int index = checkNotNull(fullMethodName, "fullMethodName").lastIndexOf('/'); 422 if (index == -1) { 423 return null; 424 } 425 return fullMethodName.substring(index + 1); 426 } 427 428 /** 429 * Creates a new builder for a {@link MethodDescriptor}. 430 * 431 * @since 1.1.0 432 */ 433 @CheckReturnValue newBuilder()434 public static <ReqT, RespT> Builder<ReqT, RespT> newBuilder() { 435 return newBuilder(null, null); 436 } 437 438 /** 439 * Creates a new builder for a {@link MethodDescriptor}. 440 * 441 * @since 1.1.0 442 */ 443 @CheckReturnValue newBuilder( Marshaller<ReqT> requestMarshaller, Marshaller<RespT> responseMarshaller)444 public static <ReqT, RespT> Builder<ReqT, RespT> newBuilder( 445 Marshaller<ReqT> requestMarshaller, Marshaller<RespT> responseMarshaller) { 446 return new Builder<ReqT, RespT>() 447 .setRequestMarshaller(requestMarshaller) 448 .setResponseMarshaller(responseMarshaller); 449 } 450 451 /** 452 * Turns this descriptor into a builder. 453 * 454 * @since 1.1.0 455 */ 456 @CheckReturnValue toBuilder()457 public Builder<ReqT, RespT> toBuilder() { 458 return toBuilder(requestMarshaller, responseMarshaller); 459 } 460 461 /** 462 * Turns this descriptor into a builder, replacing the request and response marshallers. 463 * 464 * @since 1.1.0 465 */ 466 @CheckReturnValue toBuilder( Marshaller<NewReqT> requestMarshaller, Marshaller<NewRespT> responseMarshaller)467 public <NewReqT, NewRespT> Builder<NewReqT, NewRespT> toBuilder( 468 Marshaller<NewReqT> requestMarshaller, Marshaller<NewRespT> responseMarshaller) { 469 return MethodDescriptor.<NewReqT, NewRespT>newBuilder() 470 .setRequestMarshaller(requestMarshaller) 471 .setResponseMarshaller(responseMarshaller) 472 .setType(type) 473 .setFullMethodName(fullMethodName) 474 .setIdempotent(idempotent) 475 .setSafe(safe) 476 .setSampledToLocalTracing(sampledToLocalTracing) 477 .setSchemaDescriptor(schemaDescriptor); 478 } 479 480 /** 481 * A builder for a {@link MethodDescriptor}. 482 * 483 * @since 1.1.0 484 */ 485 public static final class Builder<ReqT, RespT> { 486 487 private Marshaller<ReqT> requestMarshaller; 488 private Marshaller<RespT> responseMarshaller; 489 private MethodType type; 490 private String fullMethodName; 491 private boolean idempotent; 492 private boolean safe; 493 private Object schemaDescriptor; 494 private boolean sampledToLocalTracing; 495 Builder()496 private Builder() {} 497 498 /** 499 * Sets the request marshaller. 500 * 501 * @param requestMarshaller the marshaller to use. 502 * @since 1.1.0 503 */ setRequestMarshaller(Marshaller<ReqT> requestMarshaller)504 public Builder<ReqT, RespT> setRequestMarshaller(Marshaller<ReqT> requestMarshaller) { 505 this.requestMarshaller = requestMarshaller; 506 return this; 507 } 508 509 /** 510 * Sets the response marshaller. 511 * 512 * @param responseMarshaller the marshaller to use. 513 * @since 1.1.0 514 */ setResponseMarshaller(Marshaller<RespT> responseMarshaller)515 public Builder<ReqT, RespT> setResponseMarshaller(Marshaller<RespT> responseMarshaller) { 516 this.responseMarshaller = responseMarshaller; 517 return this; 518 } 519 520 /** 521 * Sets the method type. 522 * 523 * @param type the type of the method. 524 * @since 1.1.0 525 */ setType(MethodType type)526 public Builder<ReqT, RespT> setType(MethodType type) { 527 this.type = type; 528 return this; 529 } 530 531 /** 532 * Sets the fully qualified (service and method) method name. 533 * 534 * @see MethodDescriptor#generateFullMethodName 535 * @since 1.1.0 536 */ setFullMethodName(String fullMethodName)537 public Builder<ReqT, RespT> setFullMethodName(String fullMethodName) { 538 this.fullMethodName = fullMethodName; 539 return this; 540 } 541 542 /** 543 * Sets the schema descriptor for this builder. A schema descriptor is an object that is not 544 * used by gRPC core but includes information related to the methods. The type of the object 545 * is specific to the consumer, so both the code calling this and the code calling 546 * {@link MethodDescriptor#getSchemaDescriptor()} must coordinate. 547 * 548 * @param schemaDescriptor an object that describes the service structure. Should be immutable. 549 * @since 1.7.0 550 */ setSchemaDescriptor(@ullable Object schemaDescriptor)551 public Builder<ReqT, RespT> setSchemaDescriptor(@Nullable Object schemaDescriptor) { 552 this.schemaDescriptor = schemaDescriptor; 553 return this; 554 } 555 556 /** 557 * Sets whether the method is idempotent. If true, calling this method more than once doesn't 558 * have additional side effects. If {@code false}, method is also not safe. Note that implies 559 * calling {@code builder.setIdempotent(false).setIdempotent(true)} will leave {@code 560 * isSafe() == false}. 561 * 562 * @since 1.1.0 563 */ setIdempotent(boolean idempotent)564 public Builder<ReqT, RespT> setIdempotent(boolean idempotent) { 565 this.idempotent = idempotent; 566 if (!idempotent) { 567 this.safe = false; 568 } 569 return this; 570 } 571 572 /** 573 * Sets whether this method is safe. If true, calling this method any number of times doesn't 574 * have side effects. If {@code true}, method is also idempotent. Note that implies calling 575 * {@code builder.setSafe(true).setSafe(false)} will leave {@code isIdempotent() == true}. 576 * 577 * @since 1.1.0 578 */ setSafe(boolean safe)579 public Builder<ReqT, RespT> setSafe(boolean safe) { 580 this.safe = safe; 581 if (safe) { 582 this.idempotent = true; 583 } 584 return this; 585 } 586 587 /** 588 * Sets whether RPCs for this method may be sampled into the local tracing store. If true, 589 * sampled traces of this method may be kept in memory by tracing libraries. 590 * 591 * @since 1.8.0 592 */ setSampledToLocalTracing(boolean value)593 public Builder<ReqT, RespT> setSampledToLocalTracing(boolean value) { 594 this.sampledToLocalTracing = value; 595 return this; 596 } 597 598 /** 599 * Builds the method descriptor. 600 * 601 * @since 1.1.0 602 */ 603 @CheckReturnValue build()604 public MethodDescriptor<ReqT, RespT> build() { 605 return new MethodDescriptor<>( 606 type, 607 fullMethodName, 608 requestMarshaller, 609 responseMarshaller, 610 schemaDescriptor, 611 idempotent, 612 safe, 613 sampledToLocalTracing); 614 } 615 } 616 617 @Override toString()618 public String toString() { 619 return MoreObjects.toStringHelper(this) 620 .add("fullMethodName", fullMethodName) 621 .add("type", type) 622 .add("idempotent", idempotent) 623 .add("safe", safe) 624 .add("sampledToLocalTracing", sampledToLocalTracing) 625 .add("requestMarshaller", requestMarshaller) 626 .add("responseMarshaller", responseMarshaller) 627 .add("schemaDescriptor", schemaDescriptor) 628 .omitNullValues() 629 .toString(); 630 } 631 } 632