Now RyuApp is able to load bundle, a collection of RyuApp, and accept
class object directly.
Later this feature will simplifies ryu start up.

Signed-off-by: Isaku Yamahata <yamah...@valinux.co.jp>
---
 ryu/base/app_manager.py |  106 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 89 insertions(+), 17 deletions(-)

diff --git a/ryu/base/app_manager.py b/ryu/base/app_manager.py
index 42891fc..45e9574 100644
--- a/ryu/base/app_manager.py
+++ b/ryu/base/app_manager.py
@@ -17,6 +17,7 @@
 import inspect
 import itertools
 import logging
+import traceback
 
 from ryu import utils
 from ryu.controller.handler import register_instance
@@ -29,6 +30,35 @@ LOG = logging.getLogger('ryu.base.app_manager')
 SERVICE_BRICKS = {}
 
 
+def _load_cls(parent_clses, name):
+    try:
+        mod = utils.import_module(name)
+    except ImportError:
+        try:
+            cls = utils.import_class(name)
+        except ImportError, e:
+            LOG.debug('ImportError %s %s', e, traceback.format_exc())
+            return None
+        if not issubclass(cls, parent_clses):
+            return None
+        return cls
+
+    clses = inspect.getmembers(
+        mod, lambda cls: (inspect.isclass(cls) and
+                          issubclass(cls, parent_clses)))
+    if clses:
+        return clses[0][1]
+    return None
+
+
+def _load_bundle_cls(name):
+    return _load_cls(RyuBundle, name)
+
+
+def _load_app_cls(name):
+    return _load_cls(RyuApp, name)
+
+
 def lookup_service_brick(name):
     return SERVICE_BRICKS.get(name)
 
@@ -139,6 +169,17 @@ class RyuApp(object):
         pass
 
 
+class RyuBundle(object):
+    APPS = []
+
+
+def _split(str_or_class):
+    if inspect.isclass(str_or_class):
+        return [str_or_class]
+    assert isinstance(str_or_class, basestring)
+    return str_or_class.split(',')
+
+
 class AppManager(object):
     def __init__(self):
         self.applications_cls = {}
@@ -146,34 +187,65 @@ class AppManager(object):
         self.contexts_cls = {}
         self.contexts = {}
 
-    def load_app(self, name):
-        mod = utils.import_module(name)
-        clses = inspect.getmembers(mod, lambda cls: (inspect.isclass(cls) and
-                                                     issubclass(cls, RyuApp)))
-        if clses:
-            return clses[0][1]
-        return None
+    def _setup_app(self, app_cls_name, app_cls):
+        # for now, only single instance of a given module
+        # Do we need to support multiple instances?
+        # Yes, maybe for slicing.
+        assert app_cls_name not in self.applications_cls
+        assert issubclass(app_cls, RyuApp)
+        self.applications_cls[app_cls_name] = app_cls
+
+        for key, context_cls in app_cls.context_iteritems():
+            cls = self.contexts_cls.setdefault(key, context_cls)
+            assert cls == context_cls
 
     def load_apps(self, app_lists):
-        for app_cls_name in itertools.chain.from_iterable([app_list.split(',')
-                                                           for app_list
-                                                           in app_lists]):
-            LOG.info('loading app %s', app_cls_name)
+        bundle_loaded_apps = {}
+
+        for str_or_cls in itertools.chain.from_iterable([_split(app_list)
+                                                         for app_list
+                                                         in app_lists]):
+            if inspect.isclass(str_or_cls):
+                cls = str_or_cls
+                cls_name = cls.__name__
+            else:
+                cls = None
+                cls_name = str_or_cls
 
             # for now, only single instance of a given module
             # Do we need to support multiple instances?
             # Yes, maybe for slicing.
-            assert app_cls_name not in self.applications_cls
+            assert cls_name not in self.applications_cls
+            LOG.info('loading app %s', cls_name)
 
-            cls = self.load_app(app_cls_name)
             if cls is None:
+                cls = _load_bundle_cls(cls_name)
+                if cls is None:
+                    cls = _load_app_cls(cls_name)
+                    if cls is None:
+                        continue
+
+            if issubclass(cls, RyuBundle):
+                for app_cls in cls.APPS:
+                    if isinstance(app_cls, basestring):
+                        app_name = app_cls
+                        LOG.info('loading class %s', app_name)
+                        app_cls = _load_app_cls(app_name)
+                        if app_cls is None:
+                            raise ValueError('class %s can be loaded' %
+                                             app_name)
+                    else:
+                        app_name = app_cls.__name__
+                    bundle_loaded_apps.setdefault(app_name, app_cls)
+                    assert bundle_loaded_apps[app_name] == app_cls
                 continue
 
-            self.applications_cls[app_cls_name] = cls
+            self._setup_app(cls_name, cls)
 
-            for key, context_cls in cls.context_iteritems():
-                cls = self.contexts_cls.setdefault(key, context_cls)
-                assert cls == context_cls
+        LOG.debug('bundle_loaded_apps %s', bundle_loaded_apps)
+        for cls_name, cls in bundle_loaded_apps.iteritems():
+            if cls_name not in self.applications_cls:
+                self._setup_app(cls_name, cls)
 
     def create_contexts(self):
         for key, cls in self.contexts_cls.items():
-- 
1.7.10.4


------------------------------------------------------------------------------
How ServiceNow helps IT people transform IT departments:
1. A cloud service to automate IT design, transition and operations
2. Dashboards that offer high-level views of enterprise services
3. A single system of record for all IT processes
http://p.sf.net/sfu/servicenow-d2d-j
_______________________________________________
Ryu-devel mailing list
Ryu-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ryu-devel

Reply via email to