root/pm/trunk/umit/pm/core/bus.py @ 5510

Revision 5510, 7.6 kB (checked in by nopper, 7 months ago)

Fixing a bug in bus that lead nose-test to fail

Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# Copyright (C) 2009 Adriano Monteiro Marques
4#
5# Author: Francesco Piccinno <stack.box@gmail.com>
6#
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
21import gobject
22import inspect
23import functools
24
25from umit.pm.core.logger import log
26from umit.pm.core.atoms import Singleton
27
28class Service(gobject.GObject):
29    __gtype_name__ = "Service"
30    __gsignals__ = {
31        'vfunc-registered' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
32                              (gobject.TYPE_STRING, )),
33        'vfunc-deregistered' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
34                              (gobject.TYPE_STRING, )),
35        'func-registered' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
36                             (gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)),
37        'func-deregistered' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
38                               (gobject.TYPE_STRING, )),
39        'func-binded' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
40                         (gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)),
41        'func-unbinded' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
42                           (gobject.TYPE_STRING, )),
43    }
44
45    def __init__(self, svcid):
46        self.id = svcid
47        self.funcs = {}
48        gobject.GObject.__init__(self)
49
50    def register_vfunction(self, funcname):
51        "Register a virtual function"
52        if not funcname in self.funcs:
53            self.funcs[funcname] = None
54            self.emit('vfunc-registered', funcname)
55
56            log.info('%s vfunction registered for %s' % (funcname, self.id))
57
58    def register_function(self, funcname, cb):
59        if not funcname in self.funcs or not self.funcs[funcname]:
60            self.funcs[funcname] = cb
61            self.emit('func-registered', funcname, cb)
62
63            log.info('%s function registered for %s' % (funcname, self.id))
64        else:
65            raise ValueError("Function `%s' already registered" % funcname)
66
67    def bind_function(self, funcname, func):
68        if funcname in self.funcs and self.funcs[funcname] is None:
69            self.funcs[funcname] = func
70            self.emit('func-binded', funcname, func)
71            log.info("Function %s binded as %s" % (func, funcname))
72        else:
73            raise ValueError("Service doesn't provide `%s' method" % \
74                             funcname)
75
76    def unbind_function(self, funcname):
77        if funcname in self.funcs:
78            self.funcs[funcname] = None
79            self.emit('func-unbinded', funcname)
80        else:
81            raise ValueError("Service doesn't export `%s' method" % \
82                             funcname)
83
84    def get_function(self, funcname):
85        return self.funcs[funcname]
86
87    def call(self, funcname, *args, **kwargs):
88        return self.funcs[funcname](*args, **kwargs)
89
90class ServiceBus(Singleton, gobject.GObject):
91    __gtype_name__ = "ServiceBus"
92    __gsignals__ = {
93        'registered' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
94                        (gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, )),
95        'deregistered' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
96                          (gobject.TYPE_STRING, )),
97    }
98
99    def __init__(self):
100        self.__svc = {}
101        gobject.GObject.__init__(self)
102
103    def get_service(self, svcid):
104        return self.__svc.get(svcid, None)
105
106    def deregister_service(self, svcid):
107        if not svcid in self.__svc:
108            raise KeyError("Service `%s' not registered" % svcid)
109
110        del self.__svc[svcid]
111
112        self.emit('deregistered', svcid)
113
114    def register_service(self, svcid, obj):
115        if svcid in self.__svc:
116            raise ValueError("Service `%s' alredy registered" % svcid)
117
118        self.__svc[svcid] = obj
119        self.emit('registered', svcid, obj)
120
121    # Utilities functions
122    def get_function(self, svcid, funcname):
123        return self.__svc[svcid].get_function(funcname)
124
125    def call(self, svcid, funcname, *args, **kwargs):
126        return self.__svc[svcid].call(funcname, *args, **kwargs)
127
128# Decorators start here.
129
130def register_interface(svcid):
131    # Should be nice to have type checking or something li
132    def export_imethods(svc):
133        svc_inst = Service(svcid)
134        ServiceBus().register_service(svcid, svc_inst)
135
136        log.info("Registering new service INTERFACE `%s'" % svcid)
137
138        for _, meth in inspect.getmembers(svc, inspect.ismethod):
139            meth_name = meth.__name__
140
141            if meth_name[0] == '_':
142                continue
143
144            svc_inst.register_vfunction(meth_name)
145            log.info("Service has `%s' VFUNC" % meth_name)
146
147        return svc
148    return export_imethods
149
150def export_methods(self, *args, **kwargs):
151    cls = self.__class__
152    cls.__init__ = cls.__original_init__
153
154    svcid, implementor = cls.__svc_id__
155    cls.__init__(self, *args, **kwargs)
156
157    delattr(cls, '__svc_id__')
158    delattr(cls, '__original_init__')
159
160    if not implementor:
161        log.info("Registering new service %s" % svcid)
162
163        svc_inst = Service(svcid)
164        ServiceBus().register_service(svcid, svc_inst)
165    else:
166        svc_inst = ServiceBus().get_service(svcid)
167
168    if not svc_inst:
169        return
170
171    for _, meth in inspect.getmembers(self, inspect.ismethod):
172        meth_name = meth.__name__
173
174        if meth_name.startswith('__impl_'):
175            if implementor:
176                svc_inst.bind_function(meth_name[7:], meth)
177            else:
178                svc_inst.register_function(meth_name[7:], meth)
179
180        elif not implementor and meth_name.startswith('__intf_'):
181            svc_inst.register_vfunction(meth_name[7:])
182
183def provides(svcid):
184    def wrap(cls):
185        cls.__original_init__ = cls.__init__
186        cls.__init__ = export_methods
187
188        setattr(cls, '__svc_id__', (svcid, False))
189        return cls
190
191    return wrap
192
193def implements(svcid):
194    def wrap(cls):
195        cls.__original_init__ = cls.__init__
196        cls.__init__ = export_methods
197
198        setattr(cls, '__svc_id__', (svcid, True))
199        return cls
200
201    return wrap
202
203class unbind_function(object):
204    def __init__(self, svcid, funcname):
205        self.svcid = svcid
206        self.funcname = funcname
207
208    def __call__(self, f):
209        @functools.wraps(f)
210        def wrap(*args, **kwargs):
211            f(*args, **kwargs)
212
213            svc_inst = ServiceBus().get_service(self.svcid)
214
215            if svc_inst:
216                if isinstance(self.funcname, (list, tuple)):
217                    for func in self.funcname:
218                        svc_inst.unbind_function(func)
219                else:
220                    svc_inst.unbind_function(self.funcname)
221
222        return wrap
223
224# Initialize services from here
225
226def services_boot():
227    @register_interface('pm.hostlist')
228    class SvcHostList(object):
229        """
230        This service is used to share a list of hosts
231        """
232        def populate(self, interface): pass
233        def info(self, intf, ip, mac): pass
234
235        def get(self): pass
236        def get_target(self, l2_addr=None, l3_addr=None, hostname=None, \
237                       netmask=None): pass
Note: See TracBrowser for help on using the browser.