--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/thirdparty/google_appengine/google/appengine/runtime/apiproxy.py Tue Aug 26 21:49:54 2008 +0000
@@ -0,0 +1,246 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""Makes API calls to various Google-provided services.
+
+Provides methods for making calls into Google Apphosting services and APIs
+from your application code. This code will only work properly from within
+the Google Apphosting environment.
+"""
+
+
+import sys
+from google.net.proto import ProtocolBuffer
+from google.appengine import runtime
+from google.appengine.runtime import apiproxy_errors
+from google3.apphosting.runtime import _apphosting_runtime___python__apiproxy
+
+OK = 0
+RPC_FAILED = 1
+CALL_NOT_FOUND = 2
+ARGUMENT_ERROR = 3
+DEADLINE_EXCEEDED = 4
+CANCELLED = 5
+APPLICATION_ERROR = 6
+OTHER_ERROR = 7
+OVER_QUOTA = 8
+REQUEST_TOO_LARGE = 9
+CAPABILITY_DISABLED = 10
+
+_ExceptionsMap = {
+ RPC_FAILED:
+ (apiproxy_errors.RPCFailedError,
+ "The remote RPC to the application server failed for the call %s.%s()."),
+ CALL_NOT_FOUND:
+ (apiproxy_errors.CallNotFoundError,
+ "The API package '%s' or call '%s()' was not found."),
+ ARGUMENT_ERROR:
+ (apiproxy_errors.ArgumentError,
+ "An error occurred parsing (locally or remotely) the arguments to %s.%s()."),
+ DEADLINE_EXCEEDED:
+ (apiproxy_errors.DeadlineExceededError,
+ "The API call %s.%s() took too long to respond and was cancelled."),
+ CANCELLED:
+ (apiproxy_errors.CancelledError,
+ "The API call %s.%s() was explicitly cancelled."),
+ OTHER_ERROR:
+ (apiproxy_errors.Error,
+ "An error occurred for the API request %s.%s()."),
+ OVER_QUOTA:
+ (apiproxy_errors.OverQuotaError,
+ "The API call %s.%s() required more quota than is available."),
+ REQUEST_TOO_LARGE:
+ (apiproxy_errors.RequestTooLargeError,
+ "The request to API call %s.%s() was too large."),
+
+
+
+
+
+
+}
+
+class RPC(object):
+ """A RPC object, suitable for talking to remote services.
+
+ Each instance of this object can be used only once, and should not be reused.
+
+ Stores the data members and methods for making RPC calls via the APIProxy.
+ """
+
+ IDLE = 0
+ RUNNING = 1
+ FINISHING = 2
+
+ def __init__(self, package=None, call=None, request=None, response=None,
+ callback=None):
+ """Constructor for the RPC object. All arguments are optional, and
+ simply set members on the class. These data members will be
+ overriden by values passed to MakeCall.
+
+ Args:
+ package: string, the package for the call
+ call: string, the call within the package
+ request: ProtocolMessage instance, appropriate for the arguments
+ response: ProtocolMessage instance, appropriate for the response
+ callback: callable, called when call is complete
+ """
+ self.__exception = None
+ self.__traceback = None
+ self.__result_dict = {}
+ self.__state = RPC.IDLE
+
+ self.package = package
+ self.call = call
+ self.request = request
+ self.response = response
+ self.callback = callback
+
+
+ def MakeCall(self, package=None, call=None, request=None, response=None,
+ callback=None):
+ """Makes an asynchronous (i.e. non-blocking) API call within the
+ specified package for the specified call method. request and response must
+ be the appropriately typed ProtocolBuffers for the API call.
+ callback, if provided, will be called when the request completes
+ successfully or when an error occurs. If an error has ocurred, the
+ exception() method on this class will return the error, which can be
+ accessed from the callback.
+
+ Args:
+ Same as constructor; see __init__.
+
+ Raises:
+ TypeError or AssertionError if an argument is of an invalid type.
+ AssertionError or RuntimeError is an RPC is already in use.
+ """
+ self.callback = callback or self.callback
+ self.package = package or self.package
+ self.call = call or self.call
+ self.request = request or self.request
+ self.response = response or self.response
+
+ assert self.__state is RPC.IDLE, ("RPC for %s.%s has already been started" %
+ (self.package, self.call))
+ assert self.callback is None or callable(self.callback)
+ assert isinstance(self.request, ProtocolBuffer.ProtocolMessage)
+ assert isinstance(self.response, ProtocolBuffer.ProtocolMessage)
+
+ e = ProtocolBuffer.Encoder()
+ self.request.Output(e)
+
+ self.__state = RPC.RUNNING
+ _apphosting_runtime___python__apiproxy.MakeCall(
+ self.package, self.call, e.buffer(), self.__result_dict,
+ self.__MakeCallDone, self)
+
+ def Wait(self):
+ """Waits on the API call associated with this RPC. The callback,
+ if provided, will be executed before Wait() returns. If this RPC
+ is already complete, or if the RPC was never started, this
+ function will return immediately.
+
+ Raises:
+ InterruptedError if a callback throws an uncaught exception.
+ """
+ try:
+ rpc_completed = _apphosting_runtime___python__apiproxy.Wait(self)
+ except runtime.DeadlineExceededError:
+ raise
+ except apiproxy_errors.InterruptedError:
+ raise
+ except:
+ exc_class, exc, tb = sys.exc_info()
+ if (isinstance(exc, SystemError) and
+ exc.args == ('uncaught RPC exception',)):
+ raise
+ rpc = None
+ if hasattr(exc, "_appengine_apiproxy_rpc"):
+ rpc = exc._appengine_apiproxy_rpc
+ new_exc = apiproxy_errors.InterruptedError(exc, rpc)
+ raise new_exc.__class__, new_exc, tb
+
+ assert rpc_completed, ("RPC for %s.%s was not completed, and no other " +
+ "exception was raised " % (self.package, self.call))
+
+ def CheckSuccess(self):
+ """If there was an exception, raise it now.
+
+ Raises:
+ Exception of the API call or the callback, if any.
+ """
+ if self.exception and self.__traceback:
+ raise self.exception.__class__, self.exception, self.__traceback
+ if self.exception:
+ raise self.exception
+
+ @property
+ def exception(self):
+ return self.__exception
+
+ @property
+ def state(self):
+ return self.__state
+
+ def __MakeCallDone(self):
+ self.__state = RPC.FINISHING
+ if self.__result_dict['error'] == APPLICATION_ERROR:
+ self.__exception = apiproxy_errors.ApplicationError(
+ self.__result_dict['application_error'],
+ self.__result_dict['error_detail'])
+ elif self.__result_dict['error'] == CAPABILITY_DISABLED:
+ if self.__result_dict['error_detail']:
+ self.__exception = apiproxy_errors.CapabilityDisabledError(
+ self.__result_dict['error_detail'])
+ else:
+ self.__exception = apiproxy_errors.CapabilityDisabledError(
+ "The API call %s.%s() is temporarily unavailable." % (
+ self.package, self.call))
+ elif _ExceptionsMap.has_key(self.__result_dict['error']):
+ exception_entry = _ExceptionsMap[self.__result_dict['error']]
+ self.__exception = exception_entry[0](
+ exception_entry[1] % (self.package, self.call))
+ else:
+ try:
+ self.response.ParseFromString(self.__result_dict['result_string'])
+ except Exception, e:
+ self.__exception = e
+ if self.callback:
+ try:
+ self.callback()
+ except:
+ exc_class, self.__exception, self.__traceback = sys.exc_info()
+ self.__exception._appengine_apiproxy_rpc = self
+ raise
+
+
+def MakeSyncCall(package, call, request, response):
+ """Makes a synchronous (i.e. blocking) API call within the specified
+ package for the specified call method. request and response must be the
+ appropriately typed ProtocolBuffers for the API call. An exception is
+ thrown if an error occurs when communicating with the system.
+
+ Args:
+ See MakeCall above.
+
+ Raises:
+ See CheckSuccess() above.
+ """
+ rpc = RPC()
+ rpc.MakeCall(package, call, request, response)
+ rpc.Wait()
+ rpc.CheckSuccess()