1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 """Contains metaclasses used to create protocol service and service stub
32 classes from ServiceDescriptor objects at runtime.
33
34 The GeneratedServiceType and GeneratedServiceStubType metaclasses are used to
35 inject all useful functionality into the classes output by the protocol
36 compiler at compile-time.
37 """
38
39 __author__ = 'petar@google.com (Petar Petrov)'
40
41
43
44 """Metaclass for service classes created at runtime from ServiceDescriptors.
45
46 Implementations for all methods described in the Service class are added here
47 by this class. We also create properties to allow getting/setting all fields
48 in the protocol message.
49
50 The protocol compiler currently uses this metaclass to create protocol service
51 classes at runtime. Clients can also manually create their own classes at
52 runtime, as in this example:
53
54 mydescriptor = ServiceDescriptor(.....)
55 class MyProtoService(service.Service):
56 __metaclass__ = GeneratedServiceType
57 DESCRIPTOR = mydescriptor
58 myservice_instance = MyProtoService()
59 ...
60 """
61
62 _DESCRIPTOR_KEY = 'DESCRIPTOR'
63
64 - def __init__(cls, name, bases, dictionary):
65 """Creates a message service class.
66
67 Args:
68 name: Name of the class (ignored, but required by the metaclass
69 protocol).
70 bases: Base classes of the class being constructed.
71 dictionary: The class dictionary of the class being constructed.
72 dictionary[_DESCRIPTOR_KEY] must contain a ServiceDescriptor object
73 describing this protocol service type.
74 """
75
76
77 if GeneratedServiceType._DESCRIPTOR_KEY not in dictionary:
78 return
79 descriptor = dictionary[GeneratedServiceType._DESCRIPTOR_KEY]
80 service_builder = _ServiceBuilder(descriptor)
81 service_builder.BuildService(cls)
82
83
85
86 """Metaclass for service stubs created at runtime from ServiceDescriptors.
87
88 This class has similar responsibilities as GeneratedServiceType, except that
89 it creates the service stub classes.
90 """
91
92 _DESCRIPTOR_KEY = 'DESCRIPTOR'
93
94 - def __init__(cls, name, bases, dictionary):
112
113
115
116 """This class constructs a protocol service class using a service descriptor.
117
118 Given a service descriptor, this class constructs a class that represents
119 the specified service descriptor. One service builder instance constructs
120 exactly one service class. That means all instances of that class share the
121 same builder.
122 """
123
124 - def __init__(self, service_descriptor):
125 """Initializes an instance of the service class builder.
126
127 Args:
128 service_descriptor: ServiceDescriptor to use when constructing the
129 service class.
130 """
131 self.descriptor = service_descriptor
132
134 """Constructs the service class.
135
136 Args:
137 cls: The class that will be constructed.
138 """
139
140
141
142
143 def _WrapCallMethod(srvc, method_descriptor,
144 rpc_controller, request, callback):
145 return self._CallMethod(srvc, method_descriptor,
146 rpc_controller, request, callback)
147 self.cls = cls
148 cls.CallMethod = _WrapCallMethod
149 cls.GetDescriptor = staticmethod(lambda: self.descriptor)
150 cls.GetDescriptor.__doc__ = "Returns the service descriptor."
151 cls.GetRequestClass = self._GetRequestClass
152 cls.GetResponseClass = self._GetResponseClass
153 for method in self.descriptor.methods:
154 setattr(cls, method.name, self._GenerateNonImplementedMethod(method))
155
156 - def _CallMethod(self, srvc, method_descriptor,
157 rpc_controller, request, callback):
158 """Calls the method described by a given method descriptor.
159
160 Args:
161 srvc: Instance of the service for which this method is called.
162 method_descriptor: Descriptor that represent the method to call.
163 rpc_controller: RPC controller to use for this method's execution.
164 request: Request protocol message.
165 callback: A callback to invoke after the method has completed.
166 """
167 if method_descriptor.containing_service != self.descriptor:
168 raise RuntimeError(
169 'CallMethod() given method descriptor for wrong service type.')
170 method = getattr(srvc, method_descriptor.name)
171 return method(rpc_controller, request, callback)
172
174 """Returns the class of the request protocol message.
175
176 Args:
177 method_descriptor: Descriptor of the method for which to return the
178 request protocol message class.
179
180 Returns:
181 A class that represents the input protocol message of the specified
182 method.
183 """
184 if method_descriptor.containing_service != self.descriptor:
185 raise RuntimeError(
186 'GetRequestClass() given method descriptor for wrong service type.')
187 return method_descriptor.input_type._concrete_class
188
190 """Returns the class of the response protocol message.
191
192 Args:
193 method_descriptor: Descriptor of the method for which to return the
194 response protocol message class.
195
196 Returns:
197 A class that represents the output protocol message of the specified
198 method.
199 """
200 if method_descriptor.containing_service != self.descriptor:
201 raise RuntimeError(
202 'GetResponseClass() given method descriptor for wrong service type.')
203 return method_descriptor.output_type._concrete_class
204
206 """Generates and returns a method that can be set for a service methods.
207
208 Args:
209 method: Descriptor of the service method for which a method is to be
210 generated.
211
212 Returns:
213 A method that can be added to the service class.
214 """
215 return lambda inst, rpc_controller, request, callback: (
216 self._NonImplementedMethod(method.name, rpc_controller, callback))
217
219 """The body of all methods in the generated service class.
220
221 Args:
222 method_name: Name of the method being executed.
223 rpc_controller: RPC controller used to execute this method.
224 callback: A callback which will be invoked when the method finishes.
225 """
226 rpc_controller.SetFailed('Method %s not implemented.' % method_name)
227 callback(None)
228
229
231
232 """Constructs a protocol service stub class using a service descriptor.
233
234 Given a service descriptor, this class constructs a suitable stub class.
235 A stub is just a type-safe wrapper around an RpcChannel which emulates a
236 local implementation of the service.
237
238 One service stub builder instance constructs exactly one class. It means all
239 instances of that class share the same service stub builder.
240 """
241
242 - def __init__(self, service_descriptor):
243 """Initializes an instance of the service stub class builder.
244
245 Args:
246 service_descriptor: ServiceDescriptor to use when constructing the
247 stub class.
248 """
249 self.descriptor = service_descriptor
250
252 """Constructs the stub class.
253
254 Args:
255 cls: The class that will be constructed.
256 """
257
258 def _ServiceStubInit(stub, rpc_channel):
259 stub.rpc_channel = rpc_channel
260 self.cls = cls
261 cls.__init__ = _ServiceStubInit
262 for method in self.descriptor.methods:
263 setattr(cls, method.name, self._GenerateStubMethod(method))
264
266 return (lambda inst, rpc_controller, request, callback=None:
267 self._StubMethod(inst, method, rpc_controller, request, callback))
268
269 - def _StubMethod(self, stub, method_descriptor,
270 rpc_controller, request, callback):
271 """The body of all service methods in the generated stub class.
272
273 Args:
274 stub: Stub instance.
275 method_descriptor: Descriptor of the invoked method.
276 rpc_controller: Rpc controller to execute the method.
277 request: Request protocol message.
278 callback: A callback to execute when the method finishes.
279 Returns:
280 Response message (in case of blocking call).
281 """
282 return stub.rpc_channel.CallMethod(
283 method_descriptor, rpc_controller, request,
284 method_descriptor.output_type._concrete_class, callback)
285