thirdparty/google_appengine/google/appengine/runtime/apiproxy.py
changeset 828 f5fd65cc3bf3
parent 109 620f9b141567
child 1278 a7766286a7be
equal deleted inserted replaced
827:88c186556a80 828:f5fd65cc3bf3
    24 
    24 
    25 
    25 
    26 import sys
    26 import sys
    27 from google.net.proto import ProtocolBuffer
    27 from google.net.proto import ProtocolBuffer
    28 from google.appengine import runtime
    28 from google.appengine import runtime
       
    29 from google.appengine.api import apiproxy_rpc
       
    30 from google3.apphosting.runtime import _apphosting_runtime___python__apiproxy
    29 from google.appengine.runtime import apiproxy_errors
    31 from google.appengine.runtime import apiproxy_errors
    30 from google3.apphosting.runtime import _apphosting_runtime___python__apiproxy
       
    31 
    32 
    32 OK                =  0
    33 OK                =  0
    33 RPC_FAILED        =  1
    34 RPC_FAILED        =  1
    34 CALL_NOT_FOUND    =  2
    35 CALL_NOT_FOUND    =  2
    35 ARGUMENT_ERROR    =  3
    36 ARGUMENT_ERROR    =  3
    72 
    73 
    73 
    74 
    74 
    75 
    75 }
    76 }
    76 
    77 
    77 class RPC(object):
    78 class RPC(apiproxy_rpc.RPC):
    78   """A RPC object, suitable for talking to remote services.
    79   """A RPC object, suitable for talking to remote services.
    79 
    80 
    80   Each instance of this object can be used only once, and should not be reused.
    81   Each instance of this object can be used only once, and should not be reused.
    81 
    82 
    82   Stores the data members and methods for making RPC calls via the APIProxy.
    83   Stores the data members and methods for making RPC calls via the APIProxy.
    83   """
    84   """
    84 
    85 
    85   IDLE = 0
    86   def __init__(self, *args, **kargs):
    86   RUNNING = 1
       
    87   FINISHING = 2
       
    88 
       
    89   def __init__(self, package=None, call=None, request=None, response=None,
       
    90                callback=None):
       
    91     """Constructor for the RPC object. All arguments are optional, and
    87     """Constructor for the RPC object. All arguments are optional, and
    92     simply set members on the class. These data members will be
    88     simply set members on the class. These data members will be
    93     overriden by values passed to MakeCall.
    89     overriden by values passed to MakeCall.
       
    90     """
       
    91     super(RPC, self).__init__(*args, **kargs)
       
    92     self.__result_dict = {}
    94 
    93 
    95     Args:
    94   def _WaitImpl(self):
    96       package: string, the package for the call
       
    97       call: string, the call within the package
       
    98       request: ProtocolMessage instance, appropriate for the arguments
       
    99       response: ProtocolMessage instance, appropriate for the response
       
   100       callback: callable, called when call is complete
       
   101     """
       
   102     self.__exception = None
       
   103     self.__traceback = None
       
   104     self.__result_dict = {}
       
   105     self.__state = RPC.IDLE
       
   106 
       
   107     self.package = package
       
   108     self.call = call
       
   109     self.request = request
       
   110     self.response = response
       
   111     self.callback = callback
       
   112 
       
   113 
       
   114   def MakeCall(self, package=None, call=None, request=None, response=None,
       
   115                callback=None):
       
   116     """Makes an asynchronous (i.e. non-blocking) API call within the
       
   117     specified package for the specified call method. request and response must
       
   118     be the appropriately typed ProtocolBuffers for the API call.
       
   119     callback, if provided, will be called when the request completes
       
   120     successfully or when an error occurs.  If an error has ocurred, the
       
   121     exception() method on this class will return the error, which can be
       
   122     accessed from the callback.
       
   123 
       
   124     Args:
       
   125       Same as constructor; see __init__.
       
   126 
       
   127     Raises:
       
   128       TypeError or AssertionError if an argument is of an invalid type.
       
   129       AssertionError or RuntimeError is an RPC is already in use.
       
   130     """
       
   131     self.callback = callback or self.callback
       
   132     self.package = package or self.package
       
   133     self.call = call or self.call
       
   134     self.request = request or self.request
       
   135     self.response = response or self.response
       
   136 
       
   137     assert self.__state is RPC.IDLE, ("RPC for %s.%s has already been started" %
       
   138                                       (self.package, self.call))
       
   139     assert self.callback is None or callable(self.callback)
       
   140     assert isinstance(self.request, ProtocolBuffer.ProtocolMessage)
       
   141     assert isinstance(self.response, ProtocolBuffer.ProtocolMessage)
       
   142 
       
   143     e = ProtocolBuffer.Encoder()
       
   144     self.request.Output(e)
       
   145 
       
   146     self.__state = RPC.RUNNING
       
   147     _apphosting_runtime___python__apiproxy.MakeCall(
       
   148         self.package, self.call, e.buffer(), self.__result_dict,
       
   149         self.__MakeCallDone, self)
       
   150 
       
   151   def Wait(self):
       
   152     """Waits on the API call associated with this RPC. The callback,
    95     """Waits on the API call associated with this RPC. The callback,
   153     if provided, will be executed before Wait() returns. If this RPC
    96     if provided, will be executed before Wait() returns. If this RPC
   154     is already complete, or if the RPC was never started, this
    97     is already complete, or if the RPC was never started, this
   155     function will return immediately.
    98     function will return immediately.
   156 
    99 
   157     Raises:
   100     Raises:
   158       InterruptedError if a callback throws an uncaught exception.
   101       InterruptedError if a callback throws an uncaught exception.
   159     """
   102     """
   160     try:
   103     try:
   161       rpc_completed = _apphosting_runtime___python__apiproxy.Wait(self)
   104       rpc_completed = _apphosting_runtime___python__apiproxy.Wait(self)
   162     except runtime.DeadlineExceededError:
   105     except (runtime.DeadlineExceededError, apiproxy_errors.InterruptedError):
   163       raise
       
   164     except apiproxy_errors.InterruptedError:
       
   165       raise
   106       raise
   166     except:
   107     except:
   167       exc_class, exc, tb = sys.exc_info()
   108       exc_class, exc, tb = sys.exc_info()
   168       if (isinstance(exc, SystemError) and
   109       if (isinstance(exc, SystemError) and
   169           exc.args == ('uncaught RPC exception',)):
   110           exc.args[0] == 'uncaught RPC exception'):
   170         raise
   111         raise
   171       rpc = None
   112       rpc = None
   172       if hasattr(exc, "_appengine_apiproxy_rpc"):
   113       if hasattr(exc, "_appengine_apiproxy_rpc"):
   173         rpc = exc._appengine_apiproxy_rpc
   114         rpc = exc._appengine_apiproxy_rpc
   174       new_exc = apiproxy_errors.InterruptedError(exc, rpc)
   115       new_exc = apiproxy_errors.InterruptedError(exc, rpc)
   175       raise new_exc.__class__, new_exc, tb
   116       raise new_exc.__class__, new_exc, tb
       
   117     return True
   176 
   118 
   177     assert rpc_completed, ("RPC for %s.%s was not completed, and no other " +
   119   def _MakeCallImpl(self):
   178                            "exception was raised " % (self.package, self.call))
   120     assert isinstance(self.request, ProtocolBuffer.ProtocolMessage)
       
   121     assert isinstance(self.response, ProtocolBuffer.ProtocolMessage)
   179 
   122 
   180   def CheckSuccess(self):
   123     e = ProtocolBuffer.Encoder()
   181     """If there was an exception, raise it now.
   124     self.request.Output(e)
   182 
   125 
   183     Raises:
   126     self.__state = RPC.RUNNING
   184       Exception of the API call or the callback, if any.
       
   185     """
       
   186     if self.exception and self.__traceback:
       
   187       raise self.exception.__class__, self.exception, self.__traceback
       
   188     if self.exception:
       
   189       raise self.exception
       
   190 
   127 
   191   @property
   128     _apphosting_runtime___python__apiproxy.MakeCall(
   192   def exception(self):
   129         self.package, self.call, e.buffer(), self.__result_dict,
   193     return self.__exception
   130         self.__MakeCallDone, self)
   194 
       
   195   @property
       
   196   def state(self):
       
   197     return self.__state
       
   198 
   131 
   199   def __MakeCallDone(self):
   132   def __MakeCallDone(self):
   200     self.__state = RPC.FINISHING
   133     self.__state = RPC.FINISHING
   201     if self.__result_dict['error'] == APPLICATION_ERROR:
   134     if self.__result_dict['error'] == APPLICATION_ERROR:
   202       self.__exception = apiproxy_errors.ApplicationError(
   135       self.__exception = apiproxy_errors.ApplicationError(
   208             self.__result_dict['error_detail'])
   141             self.__result_dict['error_detail'])
   209       else:
   142       else:
   210         self.__exception = apiproxy_errors.CapabilityDisabledError(
   143         self.__exception = apiproxy_errors.CapabilityDisabledError(
   211             "The API call %s.%s() is temporarily unavailable." % (
   144             "The API call %s.%s() is temporarily unavailable." % (
   212             self.package, self.call))
   145             self.package, self.call))
   213     elif _ExceptionsMap.has_key(self.__result_dict['error']):
   146     elif self.__result_dict['error'] in _ExceptionsMap:
   214       exception_entry = _ExceptionsMap[self.__result_dict['error']]
   147       exception_entry = _ExceptionsMap[self.__result_dict['error']]
   215       self.__exception = exception_entry[0](
   148       self.__exception = exception_entry[0](
   216           exception_entry[1] % (self.package, self.call))
   149           exception_entry[1] % (self.package, self.call))
   217     else:
   150     else:
   218       try:
   151       try:
   219         self.response.ParseFromString(self.__result_dict['result_string'])
   152         self.response.ParseFromString(self.__result_dict['result_string'])
   220       except Exception, e:
   153       except Exception, e:
   221         self.__exception = e
   154         self.__exception = e
   222     if self.callback:
   155     self.__Callback()
   223       try:
   156 
   224         self.callback()
   157 def CreateRPC():
   225       except:
   158   """Create a RPC instance. suitable for talking to remote services.
   226         exc_class, self.__exception, self.__traceback = sys.exc_info()
   159 
   227         self.__exception._appengine_apiproxy_rpc = self
   160   Each RPC instance can be used only once, and should not be reused.
   228         raise
   161 
       
   162   Returns:
       
   163     an instance of RPC object
       
   164   """
       
   165   return RPC()
   229 
   166 
   230 
   167 
   231 def MakeSyncCall(package, call, request, response):
   168 def MakeSyncCall(package, call, request, response):
   232   """Makes a synchronous (i.e. blocking) API call within the specified
   169   """Makes a synchronous (i.e. blocking) API call within the specified
   233   package for the specified call method. request and response must be the
   170   package for the specified call method. request and response must be the
   238     See MakeCall above.
   175     See MakeCall above.
   239 
   176 
   240   Raises:
   177   Raises:
   241     See CheckSuccess() above.
   178     See CheckSuccess() above.
   242   """
   179   """
   243   rpc = RPC()
   180   rpc = CreateRPC()
   244   rpc.MakeCall(package, call, request, response)
   181   rpc.MakeCall(package, call, request, response)
   245   rpc.Wait()
   182   rpc.Wait()
   246   rpc.CheckSuccess()
   183   rpc.CheckSuccess()