• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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