def dispatch(self, ctxt, version, method, namespace, **kwargs): """Dispatch a message based on a requested version. :param ctxt: The request context :param version: The requested API version from the incoming message :param method: The method requested to be called by the incoming message. :param namespace: The namespace for the requested method. If None, the dispatcher will look for a method on a callback object with no namespace set. :param kwargs: A dict of keyword arguments to be passed to the method. :returns: Whatever is returned by the underlying method that gets called. """ if not version: version = '1.0' had_compatible = False for proxyobj in self.callbacks: # Check for namespace compatibility try: cb_namespace = proxyobj.RPC_API_NAMESPACE except AttributeError: cb_namespace = None if namespace != cb_namespace: continue # Check for version compatibility try: rpc_api_version = proxyobj.RPC_API_VERSION except AttributeError: rpc_api_version = '1.0' is_compatible = rpc_common.version_is_compatible(rpc_api_version, version) had_compatible = had_compatible or is_compatible if not hasattr(proxyobj, method): continue if is_compatible: kwargs = self._deserialize_args(ctxt, kwargs) result = getattr(proxyobj, method)(ctxt, **kwargs) return self.serializer.serialize_entity(ctxt, result) if had_compatible: raise AttributeError("No such RPC function '%s'" % method) else: raise rpc_common.UnsupportedRpcVersion(version=version)