332a04c294fdb2a6296b43ad86a76798b61b37b7
[platform/upstream/grpc.git] / include / grpcpp / impl / codegen / service_type.h
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 #ifndef GRPCPP_IMPL_CODEGEN_SERVICE_TYPE_H
20 #define GRPCPP_IMPL_CODEGEN_SERVICE_TYPE_H
21
22 #include <grpcpp/impl/codegen/config.h>
23 #include <grpcpp/impl/codegen/core_codegen_interface.h>
24 #include <grpcpp/impl/codegen/rpc_service_method.h>
25 #include <grpcpp/impl/codegen/serialization_traits.h>
26 #include <grpcpp/impl/codegen/server_interface.h>
27 #include <grpcpp/impl/codegen/status.h>
28
29 namespace grpc {
30
31 class CompletionQueue;
32 class Server;
33 class ServerInterface;
34 class ServerCompletionQueue;
35 class ServerContext;
36
37 namespace internal {
38 class Call;
39 class ServerAsyncStreamingInterface {
40  public:
41   virtual ~ServerAsyncStreamingInterface() {}
42
43   /// Request notification of the sending of initial metadata to the client.
44   /// Completion will be notified by \a tag on the associated completion
45   /// queue. This call is optional, but if it is used, it cannot be used
46   /// concurrently with or after the \a Finish method.
47   ///
48   /// \param[in] tag Tag identifying this request.
49   virtual void SendInitialMetadata(void* tag) = 0;
50
51  private:
52   friend class ::grpc::ServerInterface;
53   virtual void BindCall(Call* call) = 0;
54 };
55 }  // namespace internal
56
57 /// Desriptor of an RPC service and its various RPC methods
58 class Service {
59  public:
60   Service() : server_(nullptr) {}
61   virtual ~Service() {}
62
63   bool has_async_methods() const {
64     for (auto it = methods_.begin(); it != methods_.end(); ++it) {
65       if (*it && (*it)->handler() == nullptr) {
66         return true;
67       }
68     }
69     return false;
70   }
71
72   bool has_synchronous_methods() const {
73     for (auto it = methods_.begin(); it != methods_.end(); ++it) {
74       if (*it &&
75           (*it)->api_type() == internal::RpcServiceMethod::ApiType::SYNC) {
76         return true;
77       }
78     }
79     return false;
80   }
81
82   bool has_callback_methods() const {
83     for (auto it = methods_.begin(); it != methods_.end(); ++it) {
84       if (*it && ((*it)->api_type() ==
85                       internal::RpcServiceMethod::ApiType::CALL_BACK ||
86                   (*it)->api_type() ==
87                       internal::RpcServiceMethod::ApiType::RAW_CALL_BACK)) {
88         return true;
89       }
90     }
91     return false;
92   }
93
94   bool has_generic_methods() const {
95     for (auto it = methods_.begin(); it != methods_.end(); ++it) {
96       if (it->get() == nullptr) {
97         return true;
98       }
99     }
100     return false;
101   }
102
103  protected:
104   // TODO(vjpai): Promote experimental contents once callback API is accepted
105   class experimental_type {
106    public:
107     explicit experimental_type(Service* service) : service_(service) {}
108
109     void MarkMethodCallback(int index, internal::MethodHandler* handler) {
110       // This does not have to be a hard error, however no one has approached us
111       // with a use case yet. Please file an issue if you believe you have one.
112       size_t idx = static_cast<size_t>(index);
113       GPR_CODEGEN_ASSERT(
114           service_->methods_[idx].get() != nullptr &&
115           "Cannot mark the method as 'callback' because it has already been "
116           "marked as 'generic'.");
117       service_->methods_[idx]->SetHandler(handler);
118       service_->methods_[idx]->SetServerApiType(
119           internal::RpcServiceMethod::ApiType::CALL_BACK);
120     }
121
122     void MarkMethodRawCallback(int index, internal::MethodHandler* handler) {
123       // This does not have to be a hard error, however no one has approached us
124       // with a use case yet. Please file an issue if you believe you have one.
125       size_t idx = static_cast<size_t>(index);
126       GPR_CODEGEN_ASSERT(
127           service_->methods_[idx].get() != nullptr &&
128           "Cannot mark the method as 'raw callback' because it has already "
129           "been marked as 'generic'.");
130       service_->methods_[idx]->SetHandler(handler);
131       service_->methods_[idx]->SetServerApiType(
132           internal::RpcServiceMethod::ApiType::RAW_CALL_BACK);
133     }
134
135    private:
136     Service* service_;
137   };
138
139   experimental_type experimental() { return experimental_type(this); }
140
141   template <class Message>
142   void RequestAsyncUnary(int index, ServerContext* context, Message* request,
143                          internal::ServerAsyncStreamingInterface* stream,
144                          CompletionQueue* call_cq,
145                          ServerCompletionQueue* notification_cq, void* tag) {
146     // Typecast the index to size_t for indexing into a vector
147     // while preserving the API that existed before a compiler
148     // warning was first seen (grpc/grpc#11664)
149     size_t idx = static_cast<size_t>(index);
150     server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
151                               notification_cq, tag, request);
152   }
153   void RequestAsyncClientStreaming(
154       int index, ServerContext* context,
155       internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
156       ServerCompletionQueue* notification_cq, void* tag) {
157     size_t idx = static_cast<size_t>(index);
158     server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
159                               notification_cq, tag);
160   }
161   template <class Message>
162   void RequestAsyncServerStreaming(
163       int index, ServerContext* context, Message* request,
164       internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
165       ServerCompletionQueue* notification_cq, void* tag) {
166     size_t idx = static_cast<size_t>(index);
167     server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
168                               notification_cq, tag, request);
169   }
170   void RequestAsyncBidiStreaming(
171       int index, ServerContext* context,
172       internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq,
173       ServerCompletionQueue* notification_cq, void* tag) {
174     size_t idx = static_cast<size_t>(index);
175     server_->RequestAsyncCall(methods_[idx].get(), context, stream, call_cq,
176                               notification_cq, tag);
177   }
178
179   void AddMethod(internal::RpcServiceMethod* method) {
180     methods_.emplace_back(method);
181   }
182
183   void MarkMethodAsync(int index) {
184     // This does not have to be a hard error, however no one has approached us
185     // with a use case yet. Please file an issue if you believe you have one.
186     size_t idx = static_cast<size_t>(index);
187     GPR_CODEGEN_ASSERT(
188         methods_[idx].get() != nullptr &&
189         "Cannot mark the method as 'async' because it has already been "
190         "marked as 'generic'.");
191     methods_[idx]->SetServerApiType(internal::RpcServiceMethod::ApiType::ASYNC);
192   }
193
194   void MarkMethodRaw(int index) {
195     // This does not have to be a hard error, however no one has approached us
196     // with a use case yet. Please file an issue if you believe you have one.
197     size_t idx = static_cast<size_t>(index);
198     GPR_CODEGEN_ASSERT(methods_[idx].get() != nullptr &&
199                        "Cannot mark the method as 'raw' because it has already "
200                        "been marked as 'generic'.");
201     methods_[idx]->SetServerApiType(internal::RpcServiceMethod::ApiType::RAW);
202   }
203
204   void MarkMethodGeneric(int index) {
205     // This does not have to be a hard error, however no one has approached us
206     // with a use case yet. Please file an issue if you believe you have one.
207     size_t idx = static_cast<size_t>(index);
208     GPR_CODEGEN_ASSERT(
209         methods_[idx]->handler() != nullptr &&
210         "Cannot mark the method as 'generic' because it has already been "
211         "marked as 'async' or 'raw'.");
212     methods_[idx].reset();
213   }
214
215   void MarkMethodStreamed(int index, internal::MethodHandler* streamed_method) {
216     // This does not have to be a hard error, however no one has approached us
217     // with a use case yet. Please file an issue if you believe you have one.
218     size_t idx = static_cast<size_t>(index);
219     GPR_CODEGEN_ASSERT(methods_[idx] && methods_[idx]->handler() &&
220                        "Cannot mark an async or generic method Streamed");
221     methods_[idx]->SetHandler(streamed_method);
222
223     // From the server's point of view, streamed unary is a special
224     // case of BIDI_STREAMING that has 1 read and 1 write, in that order,
225     // and split server-side streaming is BIDI_STREAMING with 1 read and
226     // any number of writes, in that order.
227     methods_[idx]->SetMethodType(internal::RpcMethod::BIDI_STREAMING);
228   }
229
230  private:
231   friend class Server;
232   friend class ServerInterface;
233   ServerInterface* server_;
234   std::vector<std::unique_ptr<internal::RpcServiceMethod>> methods_;
235 };
236
237 }  // namespace grpc
238
239 #endif  // GRPCPP_IMPL_CODEGEN_SERVICE_TYPE_H