|
1 #!/usr/bin/env python |
|
2 # |
|
3 # Copyright 2007 Google Inc. |
|
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 """Base class for implementing RPC of API proxy stubs.""" |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 import sys |
|
25 |
|
26 |
|
27 class RPC(object): |
|
28 """Base class for implementing RPC of API proxy stubs. |
|
29 |
|
30 To implement a RPC to make real asynchronous API call: |
|
31 - Extend this class. |
|
32 - Override _MakeCallImpl and/or _WaitImpl to do a real asynchronous call. |
|
33 """ |
|
34 |
|
35 IDLE = 0 |
|
36 RUNNING = 1 |
|
37 FINISHING = 2 |
|
38 |
|
39 def __init__(self, package=None, call=None, request=None, response=None, |
|
40 callback=None, stub=None): |
|
41 """Constructor for the RPC object. |
|
42 |
|
43 All arguments are optional, and simply set members on the class. |
|
44 These data members will be overriden by values passed to MakeCall. |
|
45 |
|
46 Args: |
|
47 package: string, the package for the call |
|
48 call: string, the call within the package |
|
49 request: ProtocolMessage instance, appropriate for the arguments |
|
50 response: ProtocolMessage instance, appropriate for the response |
|
51 callback: callable, called when call is complete |
|
52 stub: APIProxyStub instance, used in default _WaitImpl to do real call |
|
53 """ |
|
54 self.__exception = None |
|
55 self.__state = RPC.IDLE |
|
56 self.__traceback = None |
|
57 |
|
58 self.package = package |
|
59 self.call = call |
|
60 self.request = request |
|
61 self.response = response |
|
62 self.callback = callback |
|
63 self.stub = stub |
|
64 |
|
65 def MakeCall(self, package=None, call=None, request=None, response=None, |
|
66 callback=None): |
|
67 """Makes an asynchronous (i.e. non-blocking) API call within the |
|
68 specified package for the specified call method. |
|
69 |
|
70 It will call the _MakeRealCall to do the real job. |
|
71 |
|
72 Args: |
|
73 Same as constructor; see __init__. |
|
74 |
|
75 Raises: |
|
76 TypeError or AssertionError if an argument is of an invalid type. |
|
77 AssertionError or RuntimeError is an RPC is already in use. |
|
78 """ |
|
79 self.callback = callback or self.callback |
|
80 self.package = package or self.package |
|
81 self.call = call or self.call |
|
82 self.request = request or self.request |
|
83 self.response = response or self.response |
|
84 |
|
85 assert self.__state is RPC.IDLE, ('RPC for %s.%s has already been started' % |
|
86 (self.package, self.call)) |
|
87 assert self.callback is None or callable(self.callback) |
|
88 |
|
89 self._MakeCallImpl() |
|
90 |
|
91 def Wait(self): |
|
92 """Waits on the API call associated with this RPC.""" |
|
93 rpc_completed = self._WaitImpl() |
|
94 |
|
95 assert rpc_completed, ('RPC for %s.%s was not completed, and no other ' + |
|
96 'exception was raised ' % (self.package, self.call)) |
|
97 |
|
98 def CheckSuccess(self): |
|
99 """If there was an exception, raise it now. |
|
100 |
|
101 Raises: |
|
102 Exception of the API call or the callback, if any. |
|
103 """ |
|
104 if self.exception and self.__traceback: |
|
105 raise self.exception.__class__, self.exception, self.__traceback |
|
106 elif self.exception: |
|
107 raise self.exception |
|
108 |
|
109 @property |
|
110 def exception(self): |
|
111 return self.__exception |
|
112 |
|
113 @property |
|
114 def state(self): |
|
115 return self.__state |
|
116 |
|
117 def _MakeCallImpl(self): |
|
118 """Override this method to implement a real asynchronous call rpc.""" |
|
119 self.__state = RPC.RUNNING |
|
120 |
|
121 def _WaitImpl(self): |
|
122 """Override this method to implement a real asynchronous call rpc. |
|
123 |
|
124 Returns: |
|
125 True if the async call was completed successfully. |
|
126 """ |
|
127 try: |
|
128 try: |
|
129 self.stub.MakeSyncCall(self.package, self.call, |
|
130 self.request, self.response) |
|
131 except Exception, e: |
|
132 self.__exception = e |
|
133 finally: |
|
134 self.__state = RPC.FINISHING |
|
135 self.__Callback() |
|
136 |
|
137 return True |
|
138 |
|
139 def __Callback(self): |
|
140 if self.callback: |
|
141 try: |
|
142 self.callback() |
|
143 except: |
|
144 exc_class, self.__exception, self.__traceback = sys.exc_info() |
|
145 self.__exception._appengine_apiproxy_rpc = self |
|
146 raise |