1.9.30 sync.
[gae.git] / python / google / appengine / api / apiproxy_rpc.py
blob0ed4129b90879922fc2a0ae069485260d414988d
1 #!/usr/bin/env python
3 # Copyright 2007 Google Inc.
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
21 """Base class for implementing RPC of API proxy stubs."""
32 import sys
35 class RPC(object):
36 """Base class for implementing RPC of API proxy stubs.
38 To implement a RPC to make real asynchronous API call:
39 - Extend this class.
40 - Override _MakeCallImpl and/or _WaitImpl to do a real asynchronous call.
41 """
43 IDLE = 0
44 RUNNING = 1
45 FINISHING = 2
47 def __init__(self, package=None, call=None, request=None, response=None,
48 callback=None, deadline=None, stub=None):
49 """Constructor for the RPC object.
51 All arguments are optional, and simply set members on the class.
52 These data members will be overriden by values passed to MakeCall.
54 Args:
55 package: string, the package for the call
56 call: string, the call within the package
57 request: ProtocolMessage instance, appropriate for the arguments
58 response: ProtocolMessage instance, appropriate for the response
59 callback: callable, called when call is complete
60 deadline: A double specifying the deadline for this call as the number of
61 seconds from the current time. Ignored if non-positive.
62 stub: APIProxyStub instance, used in default _WaitImpl to do real call
63 """
64 self._exception = None
65 self._state = RPC.IDLE
66 self._traceback = None
68 self.package = package
69 self.call = call
70 self.request = request
71 self.response = response
72 self.callback = callback
73 self.deadline = deadline
74 self.stub = stub
75 self.cpu_usage_mcycles = 0
77 def Clone(self):
78 """Make a shallow copy of this instances attributes, excluding methods.
80 This is usually used when an RPC has been specified with some configuration
81 options and is being used as a template for multiple RPCs outside of a
82 developer's easy control.
83 """
84 if self.state != RPC.IDLE:
85 raise AssertionError('Cannot clone a call already in progress')
87 clone = self.__class__()
88 for k, v in self.__dict__.iteritems():
89 setattr(clone, k, v)
90 return clone
92 def MakeCall(self, package=None, call=None, request=None, response=None,
93 callback=None, deadline=None):
94 """Makes an asynchronous (i.e. non-blocking) API call within the
95 specified package for the specified call method.
97 It will call the _MakeRealCall to do the real job.
99 Args:
100 Same as constructor; see __init__.
102 Raises:
103 TypeError or AssertionError if an argument is of an invalid type.
104 AssertionError or RuntimeError is an RPC is already in use.
106 self.callback = callback or self.callback
107 self.package = package or self.package
108 self.call = call or self.call
109 self.request = request or self.request
110 self.response = response or self.response
111 self.deadline = deadline or self.deadline
113 assert self._state is RPC.IDLE, ('RPC for %s.%s has already been started' %
114 (self.package, self.call))
115 assert self.callback is None or callable(self.callback)
116 self._MakeCallImpl()
118 def Wait(self):
119 """Waits on the API call associated with this RPC."""
120 rpc_completed = self._WaitImpl()
122 assert rpc_completed, ('RPC for %s.%s was not completed, and no other '
123 'exception was raised ' % (self.package, self.call))
125 def CheckSuccess(self):
126 """If there was an exception, raise it now.
128 Raises:
129 Exception of the API call or the callback, if any.
131 if self.exception and self._traceback:
132 raise self.exception.__class__, self.exception, self._traceback
133 elif self.exception:
134 raise self.exception
136 @property
137 def exception(self):
138 return self._exception
140 @property
141 def state(self):
142 return self._state
144 def _MakeCallImpl(self):
145 """Override this method to implement a real asynchronous call rpc."""
146 self._state = RPC.RUNNING
148 def _WaitImpl(self):
149 """Override this method to implement a real asynchronous call rpc.
151 Returns:
152 True if the async call was completed successfully.
154 try:
155 try:
156 self.stub.MakeSyncCall(self.package, self.call,
157 self.request, self.response)
158 except Exception:
159 _, self._exception, self._traceback = sys.exc_info()
160 finally:
161 self._state = RPC.FINISHING
162 self._Callback()
164 return True
166 def _Callback(self):
167 if self.callback:
168 try:
169 self.callback()
170 except:
171 _, self._exception, self._traceback = sys.exc_info()
172 self._exception._appengine_apiproxy_rpc = self
173 raise