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 API proxy stubs."""
29 from __future__
import with_statement
37 from google
.appengine
.api
import apiproxy_rpc
38 from google
.appengine
.api
import request_info
39 from google
.appengine
.runtime
import apiproxy_errors
42 MAX_REQUEST_SIZE
= 1 << 20
45 class APIProxyStub(object):
46 """Base class for implementing API proxy stub classes.
48 To implement an API proxy stub:
50 - Override __init__ to pass in appropriate default service name.
51 - Implement service methods as _Dynamic_<method>(request, response).
56 _ACCEPTS_REQUEST_ID
= False
63 def __init__(self
, service_name
, max_request_size
=MAX_REQUEST_SIZE
,
68 service_name: Service name expected for all calls.
69 max_request_size: int, maximum allowable size of the incoming request. A
70 apiproxy_errors.RequestTooLargeError will be raised if the inbound
71 request exceeds this size. Default is 1 MB.
72 request_data: A request_info.RequestInfo instance used to look up state
73 associated with the request that generated an API call.
75 self
.__service
_name
= service_name
76 self
.__max
_request
_size
= max_request_size
77 self
.request_data
= request_data
or request_info
._local
_request
_info
81 self
._mutex
= threading
.RLock()
83 self
.__error
_dict
= {}
86 """Creates RPC object instance.
91 return apiproxy_rpc
.RPC(stub
=self
)
93 def MakeSyncCall(self
, service
, call
, request
, response
, request_id
=None):
94 """The main RPC entry point.
97 service: Must be name as provided to service_name of constructor.
98 call: A string representing the rpc to make. Must be part of
99 the underlying services methods and impemented by _Dynamic_<call>.
100 request: A protocol buffer of the type corresponding to 'call'.
101 response: A protocol buffer of the type corresponding to 'call'.
102 request_id: A unique string identifying the request associated with the
105 assert service
== self
.__service
_name
, ('Expected "%s" service name, '
106 'was "%s"' % (self
.__service
_name
,
108 if request
.ByteSize() > self
.__max
_request
_size
:
109 raise apiproxy_errors
.RequestTooLargeError(
110 'The request to API call %s.%s() was too large.' % (service
, call
))
112 assert request
.IsInitialized(messages
), messages
117 exception_type
, frequency
= self
.__error
_dict
.get(call
, (None, None))
118 if exception_type
and frequency
:
119 if random
.random() <= frequency
:
123 if random
.random() <= self
.__error
_rate
:
127 method
= getattr(self
, '_Dynamic_' + call
)
128 if self
._ACCEPTS
_REQUEST
_ID
:
129 method(request
, response
, request_id
)
131 method(request
, response
)
133 def SetError(self
, error
, method
=None, error_rate
=1):
134 """Set an error condition that may be raised when calls made to stub.
136 If a method is specified, the error will only apply to that call.
137 The error rate is applied to the method specified or all calls if
141 error: An instance of apiproxy_errors.Error or None for no error.
142 method: A string representing the method that the error will affect.
143 error_rate: a number from [0, 1] that sets the chance of the error,
146 assert error
is None or isinstance(error
, apiproxy_errors
.Error
)
148 self
.__error
_dict
[method
] = error
, error_rate
150 self
.__error
_rate
= error_rate
154 def Synchronized(method
):
155 """Decorator to acquire a mutex around an APIProxyStub method.
158 method: An unbound method of APIProxyStub or a subclass.
161 The method, altered such it acquires self._mutex throughout its execution.
164 def WrappedMethod(self
, *args
, **kwargs
):
166 return method(self
, *args
, **kwargs
)