17e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# Protocol Buffers - Google's data interchange format
27e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# Copyright 2008 Google Inc.  All rights reserved.
37e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# http://code.google.com/p/protobuf/
47e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang#
57e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# Redistribution and use in source and binary forms, with or without
67e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# modification, are permitted provided that the following conditions are
77e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# met:
87e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang#
97e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang#     * Redistributions of source code must retain the above copyright
107e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# notice, this list of conditions and the following disclaimer.
117e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang#     * Redistributions in binary form must reproduce the above
127e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# copyright notice, this list of conditions and the following disclaimer
137e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# in the documentation and/or other materials provided with the
147e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# distribution.
157e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang#     * Neither the name of Google Inc. nor the names of its
167e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# contributors may be used to endorse or promote products derived from
177e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# this software without specific prior written permission.
187e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang#
197e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
207e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
217e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
227e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
237e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
247e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
257e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
267e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
277e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
287e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
297e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
307e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
317e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang"""Contains metaclasses used to create protocol service and service stub
327e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangclasses from ServiceDescriptor objects at runtime.
337e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
347e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing WangThe GeneratedServiceType and GeneratedServiceStubType metaclasses are used to
357e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wanginject all useful functionality into the classes output by the protocol
367e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangcompiler at compile-time.
377e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang"""
387e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
397e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang__author__ = 'petar@google.com (Petar Petrov)'
407e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
417e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
427e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangclass GeneratedServiceType(type):
437e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
447e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  """Metaclass for service classes created at runtime from ServiceDescriptors.
457e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
467e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  Implementations for all methods described in the Service class are added here
477e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  by this class. We also create properties to allow getting/setting all fields
487e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  in the protocol message.
497e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
507e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  The protocol compiler currently uses this metaclass to create protocol service
517e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  classes at runtime. Clients can also manually create their own classes at
527e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  runtime, as in this example:
537e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
547e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  mydescriptor = ServiceDescriptor(.....)
557e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  class MyProtoService(service.Service):
567e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    __metaclass__ = GeneratedServiceType
577e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    DESCRIPTOR = mydescriptor
587e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  myservice_instance = MyProtoService()
597e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  ...
607e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  """
617e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
627e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  _DESCRIPTOR_KEY = 'DESCRIPTOR'
637e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
647e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  def __init__(cls, name, bases, dictionary):
657e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """Creates a message service class.
667e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
677e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Args:
687e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      name: Name of the class (ignored, but required by the metaclass
697e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang        protocol).
707e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      bases: Base classes of the class being constructed.
717e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      dictionary: The class dictionary of the class being constructed.
727e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang        dictionary[_DESCRIPTOR_KEY] must contain a ServiceDescriptor object
737e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang        describing this protocol service type.
747e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """
757e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    # Don't do anything if this class doesn't have a descriptor. This happens
767e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    # when a service class is subclassed.
777e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    if GeneratedServiceType._DESCRIPTOR_KEY not in dictionary:
787e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      return
797e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    descriptor = dictionary[GeneratedServiceType._DESCRIPTOR_KEY]
807e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    service_builder = _ServiceBuilder(descriptor)
817e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    service_builder.BuildService(cls)
827e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
837e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
847e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangclass GeneratedServiceStubType(GeneratedServiceType):
857e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
867e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  """Metaclass for service stubs created at runtime from ServiceDescriptors.
877e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
887e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  This class has similar responsibilities as GeneratedServiceType, except that
897e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  it creates the service stub classes.
907e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  """
917e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
927e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  _DESCRIPTOR_KEY = 'DESCRIPTOR'
937e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
947e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  def __init__(cls, name, bases, dictionary):
957e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """Creates a message service stub class.
967e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
977e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Args:
987e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      name: Name of the class (ignored, here).
997e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      bases: Base classes of the class being constructed.
1007e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      dictionary: The class dictionary of the class being constructed.
1017e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang        dictionary[_DESCRIPTOR_KEY] must contain a ServiceDescriptor object
1027e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang        describing this protocol service type.
1037e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """
1047e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    super(GeneratedServiceStubType, cls).__init__(name, bases, dictionary)
1057e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    # Don't do anything if this class doesn't have a descriptor. This happens
1067e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    # when a service stub is subclassed.
1077e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    if GeneratedServiceStubType._DESCRIPTOR_KEY not in dictionary:
1087e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      return
1097e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    descriptor = dictionary[GeneratedServiceStubType._DESCRIPTOR_KEY]
1107e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    service_stub_builder = _ServiceStubBuilder(descriptor)
1117e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    service_stub_builder.BuildServiceStub(cls)
1127e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1137e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1147e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangclass _ServiceBuilder(object):
1157e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1167e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  """This class constructs a protocol service class using a service descriptor.
1177e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1187e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  Given a service descriptor, this class constructs a class that represents
1197e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  the specified service descriptor. One service builder instance constructs
1207e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  exactly one service class. That means all instances of that class share the
1217e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  same builder.
1227e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  """
1237e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1247e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  def __init__(self, service_descriptor):
1257e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """Initializes an instance of the service class builder.
1267e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1277e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Args:
1287e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      service_descriptor: ServiceDescriptor to use when constructing the
1297e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang        service class.
1307e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """
1317e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    self.descriptor = service_descriptor
1327e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1337e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  def BuildService(self, cls):
1347e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """Constructs the service class.
1357e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1367e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Args:
1377e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      cls: The class that will be constructed.
1387e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """
1397e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1407e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    # CallMethod needs to operate with an instance of the Service class. This
1417e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    # internal wrapper function exists only to be able to pass the service
1427e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    # instance to the method that does the real CallMethod work.
1437e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    def _WrapCallMethod(srvc, method_descriptor,
1447e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang                        rpc_controller, request, callback):
1457e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      return self._CallMethod(srvc, method_descriptor,
1467e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang                       rpc_controller, request, callback)
1477e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    self.cls = cls
1487e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    cls.CallMethod = _WrapCallMethod
1497e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    cls.GetDescriptor = staticmethod(lambda: self.descriptor)
1507e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    cls.GetDescriptor.__doc__ = "Returns the service descriptor."
1517e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    cls.GetRequestClass = self._GetRequestClass
1527e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    cls.GetResponseClass = self._GetResponseClass
1537e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    for method in self.descriptor.methods:
1547e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      setattr(cls, method.name, self._GenerateNonImplementedMethod(method))
1557e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1567e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  def _CallMethod(self, srvc, method_descriptor,
1577e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang                  rpc_controller, request, callback):
1587e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """Calls the method described by a given method descriptor.
1597e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1607e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Args:
1617e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      srvc: Instance of the service for which this method is called.
1627e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      method_descriptor: Descriptor that represent the method to call.
1637e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      rpc_controller: RPC controller to use for this method's execution.
1647e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      request: Request protocol message.
1657e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      callback: A callback to invoke after the method has completed.
1667e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """
1677e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    if method_descriptor.containing_service != self.descriptor:
1687e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      raise RuntimeError(
1697e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang          'CallMethod() given method descriptor for wrong service type.')
1707e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    method = getattr(srvc, method_descriptor.name)
1717e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    return method(rpc_controller, request, callback)
1727e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1737e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  def _GetRequestClass(self, method_descriptor):
1747e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """Returns the class of the request protocol message.
1757e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1767e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Args:
1777e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      method_descriptor: Descriptor of the method for which to return the
1787e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang        request protocol message class.
1797e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1807e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Returns:
1817e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      A class that represents the input protocol message of the specified
1827e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      method.
1837e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """
1847e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    if method_descriptor.containing_service != self.descriptor:
1857e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      raise RuntimeError(
1867e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang          'GetRequestClass() given method descriptor for wrong service type.')
1877e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    return method_descriptor.input_type._concrete_class
1887e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1897e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  def _GetResponseClass(self, method_descriptor):
1907e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """Returns the class of the response protocol message.
1917e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1927e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Args:
1937e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      method_descriptor: Descriptor of the method for which to return the
1947e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang        response protocol message class.
1957e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
1967e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Returns:
1977e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      A class that represents the output protocol message of the specified
1987e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      method.
1997e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """
2007e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    if method_descriptor.containing_service != self.descriptor:
2017e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      raise RuntimeError(
2027e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang          'GetResponseClass() given method descriptor for wrong service type.')
2037e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    return method_descriptor.output_type._concrete_class
2047e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2057e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  def _GenerateNonImplementedMethod(self, method):
2067e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """Generates and returns a method that can be set for a service methods.
2077e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2087e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Args:
2097e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      method: Descriptor of the service method for which a method is to be
2107e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang        generated.
2117e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2127e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Returns:
2137e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      A method that can be added to the service class.
2147e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """
2157e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    return lambda inst, rpc_controller, request, callback: (
2167e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang        self._NonImplementedMethod(method.name, rpc_controller, callback))
2177e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2187e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  def _NonImplementedMethod(self, method_name, rpc_controller, callback):
2197e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """The body of all methods in the generated service class.
2207e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2217e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Args:
2227e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      method_name: Name of the method being executed.
2237e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      rpc_controller: RPC controller used to execute this method.
2247e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      callback: A callback which will be invoked when the method finishes.
2257e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """
2267e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    rpc_controller.SetFailed('Method %s not implemented.' % method_name)
2277e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    callback(None)
2287e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2297e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2307e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wangclass _ServiceStubBuilder(object):
2317e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2327e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  """Constructs a protocol service stub class using a service descriptor.
2337e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2347e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  Given a service descriptor, this class constructs a suitable stub class.
2357e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  A stub is just a type-safe wrapper around an RpcChannel which emulates a
2367e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  local implementation of the service.
2377e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2387e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  One service stub builder instance constructs exactly one class. It means all
2397e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  instances of that class share the same service stub builder.
2407e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  """
2417e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2427e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  def __init__(self, service_descriptor):
2437e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """Initializes an instance of the service stub class builder.
2447e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2457e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Args:
2467e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      service_descriptor: ServiceDescriptor to use when constructing the
2477e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang        stub class.
2487e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """
2497e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    self.descriptor = service_descriptor
2507e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2517e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  def BuildServiceStub(self, cls):
2527e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """Constructs the stub class.
2537e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2547e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Args:
2557e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      cls: The class that will be constructed.
2567e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """
2577e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2587e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    def _ServiceStubInit(stub, rpc_channel):
2597e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      stub.rpc_channel = rpc_channel
2607e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    self.cls = cls
2617e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    cls.__init__ = _ServiceStubInit
2627e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    for method in self.descriptor.methods:
2637e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      setattr(cls, method.name, self._GenerateStubMethod(method))
2647e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2657e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  def _GenerateStubMethod(self, method):
2667e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    return (lambda inst, rpc_controller, request, callback=None:
2677e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang        self._StubMethod(inst, method, rpc_controller, request, callback))
2687e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2697e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang  def _StubMethod(self, stub, method_descriptor,
2707e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang                  rpc_controller, request, callback):
2717e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """The body of all service methods in the generated stub class.
2727e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang
2737e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Args:
2747e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      stub: Stub instance.
2757e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      method_descriptor: Descriptor of the invoked method.
2767e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      rpc_controller: Rpc controller to execute the method.
2777e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      request: Request protocol message.
2787e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      callback: A callback to execute when the method finishes.
2797e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    Returns:
2807e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang      Response message (in case of blocking call).
2817e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    """
2827e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang    return stub.rpc_channel.CallMethod(
2837e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang        method_descriptor, rpc_controller, request,
2847e7f2e9122af6c7e7e7d4ba205fdf46d50b95eefYing Wang        method_descriptor.output_type._concrete_class, callback)
285