1 """
2 The necessary class and decorators for L{interface} and L{module}
3
4 @copyright: (c) 2011 hackmeeting U{http://sindominio.net/hackmeeting}
5 @author: Ruben Pollan
6 @organization: hackmeeting U{http://sindominio.net/hackmeeting}
7 @contact: meskio@sindominio.net
8 @license:
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the Do What The Fuck You Want To
11 Public License, Version 2, as published by Sam Hocevar. See
12 U{http://sam.zoy.org/projects/COPYING.WTFPL} for more details.
13 """
14
15 import thread
16 import logging
17
18 import emma
19
20
22 """
23 Decorator that adds a lock to a method
24
25 It decorates methods of child classes of L{Complement}, usually
26 L{interface} or L{module}. Adds the use of a locker (mutex) to the method,
27 so the access to the class data is thread safe.
28
29 >>> from emma.complement import use_lock
30 >>> class myModule(Module):
31 ... @use_lock
32 ... def run(self):
33 ... self.var = 0
34 ...
35 ... @use_lock
36 ... def inc(self):
37 ... self.var += 1
38 """
39 def wrapper(self, *arg):
40 with self.lock:
41 res = fn(self, *arg)
42 return res
43 return wrapper
44
45
47 """
48 Empty class mented to be inhered by L{interface} and L{module}
49
50 It handles the configuration, identifier and locker.
51
52 There will be some useful variables:
53 - self.conf(dict): with all the configuration of the complement
54 - self.identifier(str): the identifier of the instantiation of the
55 complement
56 - self.db(mongoDB collection): the database collection
57 """
58 - def __init__(self, identifier, conf, db):
59 """
60 @type identifier: string
61 @param identifier: complement unique identifier, on L{interface} it is
62 use for the L{Event} invocation
63 @type conf: dictionary
64 @param conf: the configuration of the module as {item: value}
65 @type db: database collection (mongoDB)
66 @param db: the database collection of the complement
67 """
68 self.conf = conf
69 self.identifier = identifier
70 self.lock = thread.allocate_lock()
71 self.db = db
72
74 """
75 The starting method of the complement
76
77 Each L{interface} or L{module} should define here the initialization,
78 L{subscribe<emma.events.subscribe>} to events, the
79 L{periodic<emma.sched.periodic>} actions, ...
80 """
81 pass
82
83 - def log(self, msg, level=logging.INFO):
84 """
85 Output a log string
86
87 If loggin activated prompts on standard output the string adding to it
88 "[complement_name identifier] ". Uses L{emma.logger.log()}.
89
90 @type msg: string
91 @param msg: the text to output
92 @type level: logging level
93 @param level: default logging.INFO
94 """
95 name = self.__module__.split(".")[-1]
96 logging.log(level, "[%s %s] %s" % (name, self.identifier, msg))
97
99 """
100 Update database
101
102 Stores the emma version on the collection of the complement. And
103 returns the old version from the database and the actual version
104 of emma.
105
106 @note: That is meant to be use for updating the database structure of
107 the complement.
108 @returns: (old version, new version)
109 """
110 dbmeta = self.db.find({'type': 'meta'})
111 old_version = None
112 metaUpdated = False
113 if dbmeta.count():
114 for meta in dbmeta:
115 v = float(meta['version'])
116 if not old_version or v < old_version:
117 old_version = v
118 if v != emma.__version__:
119 self.db.remove(meta['_id'])
120 else:
121 metaUpdated = True
122
123 if not metaUpdated:
124 self.db.insert({'type': 'meta', 'version': emma.__version__})
125 return (old_version, emma.__version__)
126