Instantiate dbus system bus where it works
[gregoa/zavai.git] / zavai / registry.py
1 # registry - zavai resource registry
2 #
3 # Copyright (C) 2009  Enrico Zini <enrico@enricozini.org>
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19 import zavai
20
21 class Registry(object):
22     """Collection of resources.
23
24     Various factories can be registered by name on the registry. Then when an
25     object is requested for the first time, it is created using the factory.
26     When it is requested again, the existing object is reused.
27     """
28
29     def __init__(self):
30         self.factories = dict()
31         self.objects = dict()
32
33     def resource(self, name):
34         """Get a resource, instantiating it if it has not been done yet.
35
36         First it tries to use the factory registered with `name` itself. If it
37         fails, it tries to use the factory registered one level above (using
38         the dot '.' as a separator).
39
40         If no suitable factory has been found, returns None.
41         """
42         res = self.objects.get(name, None)
43         if res is None:
44             fac = self.factories.get(name, None)
45             root = name
46             if fac is None:
47                 while True:
48                     pos = root.rfind(".")
49                     if pos == -1: break
50                     root = root[:pos]
51                     fac = self.factories.get(root, None)
52                 if fac is None:
53                     return None
54             zavai.info("Instantiating", name, "with factory", root)
55             res = fac(self, name)
56             if res is not None:
57                 self.objects[name] = res
58         return res
59
60     def menu(self, name):
61         """Get a menu resource, instantiating it if it has not been done yet.
62
63         All menu resources share the same factory, which builds zavai.Menu
64         objects.
65         """
66         return self.resource("menu." + name)
67
68     def menu_link(self, name, label):
69         """Return a MenuLink to the menu with the given name
70         """
71         return zavai.MenuLink(self, name, label)
72
73     def get_existing(self, name):
74         """Get a menu resource, but only if it has been already instantiated.
75
76         If the resource has not been instantiated yet, returns None.
77         """
78         return self.objects.get(name, None)
79
80     def register(self, name, factory):
81         """Register a factory for this registry.
82
83         Name is a name for this factory, like "menu.gps.monitor".
84
85         Factory is a function that creates a Resource object. The function will
86         be passed the Registry itself as the only parameter"""
87         if name in self.factories:
88             return KeyError("% is already registered as a factory", name)
89         self.factories[name] = factory
90
91     def shutdown(self):
92         """Shut down all objects in this Registry.
93
94         After shutting down, all objects cannot be used anymore"""
95         for o in self.objects.itervalues():
96             if isinstance(o, Resource):
97                 o.shutdown()
98         self.objects.clear()
99
100 class Resource(object):
101     def __init__(self, registry, name, *args, **kw):
102         """The default constructor does nothing, but is there to eat the
103         parameters passed by Registry in case subclassers do not need a
104         constructor"""
105         pass
106
107     def shutdown(self):
108         """Shut down this resource.
109
110         Normally one does nothing here, but it is important to give resources a
111         chance to do cleanup when the program quits.
112
113         This can be used for tasks like closing the tags on a GPX track,
114         releasing a FSO resource, restoring mixer settings and so on.
115         """
116         pass