summaryrefslogtreecommitdiffstats
path: root/keystone/common
diff options
context:
space:
mode:
authorDolph Mathews <dolph.mathews@gmail.com>2012-12-19 10:04:21 -0600
committerDolph Mathews <dolph.mathews@gmail.com>2012-12-21 11:57:44 -0600
commit03eb2801a3ad38a39e9cf127c05ab710bf38ee1d (patch)
treec91ae80657c574cabcecf5abfa78f3940392c517 /keystone/common
parentac2d92ca2eea1070f765be320acb62fd5bef6dd3 (diff)
Driver registry
Uses automatic dependency injection to provide controllers with driver interfaces (identity_api, token_api, etc). See tests/test_injection.py for a self-contained example. Change-Id: I255087de534292fbf57a45b19f97488f831f607c
Diffstat (limited to 'keystone/common')
-rw-r--r--keystone/common/controller.py10
-rw-r--r--keystone/common/dependency.py67
2 files changed, 70 insertions, 7 deletions
diff --git a/keystone/common/controller.py b/keystone/common/controller.py
index 5f351411..ee7ce5b5 100644
--- a/keystone/common/controller.py
+++ b/keystone/common/controller.py
@@ -1,6 +1,7 @@
import uuid
import functools
+from keystone.common import dependency
from keystone.common import logging
from keystone.common import wsgi
from keystone import exception
@@ -55,15 +56,10 @@ def protected(f):
return wrapper
+@dependency.requires('identity_api', 'policy_api', 'token_api')
class V2Controller(wsgi.Application):
"""Base controller class for Identity API v2."""
-
- def __init__(self, catalog_api, identity_api, policy_api, token_api):
- self.catalog_api = catalog_api
- self.identity_api = identity_api
- self.policy_api = policy_api
- self.token_api = token_api
- super(V2Controller, self).__init__()
+ pass
class V3Controller(V2Controller):
diff --git a/keystone/common/dependency.py b/keystone/common/dependency.py
new file mode 100644
index 00000000..dc3e4ac4
--- /dev/null
+++ b/keystone/common/dependency.py
@@ -0,0 +1,67 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack LLC
+#
+# 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.
+
+REGISTRY = {}
+
+
+class UnresolvableDependencyException(Exception):
+ def __init__(self, name):
+ msg = 'Unregistered dependency: %s' % name
+ super(UnresolvableDependencyException, self).__init__(msg)
+
+
+def provider(name):
+ """Register the wrapped dependency provider under the specified name."""
+ def wrapper(cls):
+ def wrapped(init):
+ def __wrapped_init__(self, *args, **kwargs):
+ """Initialize the wrapped object and add it to the registry."""
+ init(self, *args, **kwargs)
+ REGISTRY[name] = self
+
+ return __wrapped_init__
+
+ cls.__init__ = wrapped(cls.__init__)
+ return cls
+
+ return wrapper
+
+
+def requires(*dependencies):
+ """Inject specified dependencies from the registry into the instance."""
+ def wrapper(self, *args, **kwargs):
+ """Inject each dependency from the registry."""
+ self.__wrapped_init__(*args, **kwargs)
+
+ for dependency in self._dependencies:
+ if dependency not in REGISTRY:
+ raise UnresolvableDependencyException(dependency)
+ setattr(self, dependency, REGISTRY[dependency])
+
+ def wrapped(cls):
+ """Note the required dependencies on the object for later injection.
+
+ The dependencies of the parent class are combined with that of the
+ child class to create a new set of dependencies.
+ """
+ existing_dependencies = getattr(cls, '_dependencies', set())
+ cls._dependencies = existing_dependencies.union(dependencies)
+ if not hasattr(cls, '__wrapped_init__'):
+ cls.__wrapped_init__ = cls.__init__
+ cls.__init__ = wrapper
+ return cls
+
+ return wrapped