25 |
25 |
26 |
26 |
27 |
27 |
28 |
28 |
29 |
29 |
|
30 import inspect |
30 import sys |
31 import sys |
31 |
32 |
|
33 def CreateRPC(service): |
|
34 """Creates a RPC instance for the given service. |
|
35 |
|
36 The instance is suitable for talking to remote services. |
|
37 Each RPC instance can be used only once, and should not be reused. |
|
38 |
|
39 Args: |
|
40 service: string representing which service to call. |
|
41 |
|
42 Returns: |
|
43 the rpc object. |
|
44 |
|
45 Raises: |
|
46 AssertionError or RuntimeError if the stub for service doesn't supply a |
|
47 CreateRPC method. |
|
48 """ |
|
49 stub = apiproxy.GetStub(service) |
|
50 assert stub, 'No api proxy found for service "%s"' % service |
|
51 assert hasattr(stub, 'CreateRPC'), ('The service "%s" doesn\'t have ' + |
|
52 'a CreateRPC method.' % service) |
|
53 return stub.CreateRPC() |
|
54 |
|
55 |
32 def MakeSyncCall(service, call, request, response): |
56 def MakeSyncCall(service, call, request, response): |
33 """The APIProxy entry point. |
57 """The APIProxy entry point for a synchronous API call. |
34 |
58 |
35 Args: |
59 Args: |
36 service: string representing which service to call |
60 service: string representing which service to call |
37 call: string representing which function to call |
61 call: string representing which function to call |
38 request: protocol buffer for the request |
62 request: protocol buffer for the request |
39 response: protocol buffer for the response |
63 response: protocol buffer for the response |
40 |
64 |
41 Raises: |
65 Raises: |
42 apiproxy_errors.Error or a subclass. |
66 apiproxy_errors.Error or a subclass. |
43 """ |
67 """ |
44 stub = apiproxy.GetStub(service) |
68 apiproxy.MakeSyncCall(service, call, request, response) |
45 assert stub, 'No api proxy found for service "%s"' % service |
69 |
46 stub.MakeSyncCall(service, call, request, response) |
70 |
|
71 class ListOfHooks(object): |
|
72 """An ordered collection of hooks for a particular API call. |
|
73 |
|
74 A hook is a function that has exactly the same signature as |
|
75 a service stub. It will be called before or after an api hook is |
|
76 executed, depending on whether this list is for precall of postcall hooks. |
|
77 Hooks can be used for debugging purposes (check certain |
|
78 pre- or postconditions on api calls) or to apply patches to protocol |
|
79 buffers before/after a call gets submitted. |
|
80 """ |
|
81 |
|
82 def __init__(self): |
|
83 """Constructor.""" |
|
84 |
|
85 self.__content = [] |
|
86 |
|
87 self.__unique_keys = set() |
|
88 |
|
89 def __len__(self): |
|
90 """Returns the amount of elements in the collection.""" |
|
91 return self.__content.__len__() |
|
92 |
|
93 def __Insert(self, index, key, function, service=None): |
|
94 """Appends a hook at a certain position in the list. |
|
95 |
|
96 Args: |
|
97 index: the index of where to insert the function |
|
98 key: a unique key (within the module) for this particular function. |
|
99 If something from the same module with the same key is already |
|
100 registered, nothing will be added. |
|
101 function: the hook to be added. |
|
102 service: optional argument that restricts the hook to a particular api |
|
103 |
|
104 Returns: |
|
105 True if the collection was modified. |
|
106 """ |
|
107 unique_key = (key, inspect.getmodule(function)) |
|
108 if unique_key in self.__unique_keys: |
|
109 return False |
|
110 self.__content.insert(index, (key, function, service)) |
|
111 self.__unique_keys.add(unique_key) |
|
112 return True |
|
113 |
|
114 def Append(self, key, function, service=None): |
|
115 """Appends a hook at the end of the list. |
|
116 |
|
117 Args: |
|
118 key: a unique key (within the module) for this particular function. |
|
119 If something from the same module with the same key is already |
|
120 registered, nothing will be added. |
|
121 function: the hook to be added. |
|
122 service: optional argument that restricts the hook to a particular api |
|
123 |
|
124 Returns: |
|
125 True if the collection was modified. |
|
126 """ |
|
127 return self.__Insert(len(self), key, function, service) |
|
128 |
|
129 def Push(self, key, function, service=None): |
|
130 """Inserts a hook at the beginning of the list. |
|
131 |
|
132 Args: |
|
133 key: a unique key (within the module) for this particular function. |
|
134 If something from the same module with the same key is already |
|
135 registered, nothing will be added. |
|
136 function: the hook to be added. |
|
137 service: optional argument that restricts the hook to a particular api |
|
138 |
|
139 Returns: |
|
140 True if the collection was modified. |
|
141 """ |
|
142 return self.__Insert(0, key, function, service) |
|
143 |
|
144 def Clear(self): |
|
145 """Removes all hooks from the list (useful for unit tests).""" |
|
146 self.__content = [] |
|
147 self.__unique_keys = set() |
|
148 |
|
149 def Call(self, service, call, request, response): |
|
150 """Invokes all hooks in this collection. |
|
151 |
|
152 Args: |
|
153 service: string representing which service to call |
|
154 call: string representing which function to call |
|
155 request: protocol buffer for the request |
|
156 response: protocol buffer for the response |
|
157 """ |
|
158 for key, function, srv in self.__content: |
|
159 if srv is None or srv == service: |
|
160 function(service, call, request, response) |
47 |
161 |
48 |
162 |
49 class APIProxyStubMap: |
163 class APIProxyStubMap: |
50 """Container of APIProxy stubs for more convenient unittesting. |
164 """Container of APIProxy stubs for more convenient unittesting. |
51 |
165 |
95 |
219 |
96 Returns the stub registered for 'service', and returns the default stub |
220 Returns the stub registered for 'service', and returns the default stub |
97 if no such stub is found. |
221 if no such stub is found. |
98 """ |
222 """ |
99 return self.__stub_map.get(service, self.__default_stub) |
223 return self.__stub_map.get(service, self.__default_stub) |
|
224 |
|
225 def MakeSyncCall(self, service, call, request, response): |
|
226 """The APIProxy entry point. |
|
227 |
|
228 Args: |
|
229 service: string representing which service to call |
|
230 call: string representing which function to call |
|
231 request: protocol buffer for the request |
|
232 response: protocol buffer for the response |
|
233 |
|
234 Raises: |
|
235 apiproxy_errors.Error or a subclass. |
|
236 """ |
|
237 stub = self.GetStub(service) |
|
238 assert stub, 'No api proxy found for service "%s"' % service |
|
239 self.__precall_hooks.Call(service, call, request, response) |
|
240 stub.MakeSyncCall(service, call, request, response) |
|
241 self.__postcall_hooks.Call(service, call, request, response) |
|
242 |
100 |
243 |
101 def GetDefaultAPIProxy(): |
244 def GetDefaultAPIProxy(): |
102 try: |
245 try: |
103 runtime = __import__('google.appengine.runtime', globals(), locals(), |
246 runtime = __import__('google.appengine.runtime', globals(), locals(), |
104 ['apiproxy']) |
247 ['apiproxy']) |