Fixed nasty concurrency bug in EC
[nepi.git] / src / nepi / execution / attribute.py
1 #
2 #    NEPI, a framework to manage network experiments
3 #    Copyright (C) 2013 INRIA
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 3 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, see <http://www.gnu.org/licenses/>.
17 #
18 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
19
20 ### Attribute Types
21 class Types:
22     String  = "STRING"
23     Bool    = "BOOL"
24     Enumerate    = "ENUM"
25     Double  = "DOUBLE"
26     Integer = "INTEGER"
27
28 ### Attribute Flags
29 class Flags:
30     """ Differents flags to characterize an attribute
31
32     """
33     # Attribute can be modified by the user 
34     NoFlags         = 0x00
35     # Attribute is not modifiable by the user
36     ReadOnly        = 0x01
37     # Attribute is not modifiable by the user during runtime
38     ExecReadOnly        = 0x02
39     # Attribute is an access credential
40     Credential      = 0x04
41     # Attribute is a filter used to discover resources
42     Filter      = 0x08
43
44 class Attribute(object):
45     """
46     .. class:: Class Args :
47
48         An Attribute reflects a configuration parameter for
49         a particular resource. Attributes might be read only or
50         not.
51       
52         :param name: Name of the attribute
53         :type name: str
54
55         :param help: Attribute description
56         :type help: str
57         
58         :param type: The type expected for the attribute value.
59                      Should be one of Attribute.Types .
60         :type type: str
61
62         :param flags: Defines attribute behavior (i.e. whether it is read-only,
63                 read and write, etc). This parameter should take its values from
64                 Attribute.Flags. Flags values can be bitwised.
65         :type flags: hex
66
67         :param default: Default value of the attribute
68         :type default: depends on the type of attribute
69         
70         :param allowed: List of values that the attribute can take. 
71                 This parameter is only meaningful for Enumerate type attributes.
72         :type allowed: list
73         
74         :param range: (max, min) tuple with range of possible values for
75                 attributes.
76                 This parameter is only meaningful for Integer or Double type
77                 attributes.
78         :type range: (int, int) or (float, float)
79         
80         :param set_hook: Function that will be executed when ever a new 
81                 value is set for the attribute.
82         :type set_hook: function
83
84     """
85     def __init__(self, name, help, type = Types.String,
86             flags = Flags.NoFlags, default = None, allowed = None,
87             range = None, set_hook = None):
88         self._name = name
89         self._help = help
90         self._type = type
91         self._flags = flags
92         self._allowed = allowed
93         self._range = range
94         self._default = self._value = default
95         # callback to be invoked upon changing the 
96         # attribute value
97         self.set_hook = set_hook
98
99     @property
100     def name(self):
101         """ Returns the name of the attribute """
102         return self._name
103
104     @property
105     def default(self):
106         """ Returns the default value of the attribute """
107         return self._default
108
109     @property
110     def type(self):
111         """ Returns the type of the attribute """
112         return self._type
113
114     @property
115     def help(self):
116         """ Returns the help of the attribute """
117         return self._help
118
119     @property
120     def flags(self):
121         """ Returns the flags of the attribute """
122         return self._flags
123
124     @property
125     def allowed(self):
126         """ Returns the allowed value for this attribute """
127         return self._allowed
128
129     @property
130     def range(self):
131         """ Returns the range of the attribute """
132         return self._range
133
134     def has_flag(self, flag):
135         """ Returns true if the attribute has the flag 'flag'
136
137         :param flag: Flag that need to be ckecked
138         :type flag: Flags
139         """
140         return (self._flags & flag) == flag
141
142     def get_value(self):
143         """ Returns the value of the attribute """
144         return self._value
145
146     def set_value(self, value):
147         """ Change the value of the attribute after checking the type """
148         valid = True
149
150         if self.type == Types.Enumerate:
151             valid = value in self._allowed
152
153         if self.type in [Types.Double, Types.Integer] and self.range:
154             (min, max) = self.range
155             valid = (value >= min and value <= max) 
156         
157         valid = valid and self.is_valid_value(value)
158
159         if valid: 
160             if self.set_hook:
161                 # Hook receives old value, new value
162                 value = self.set_hook(self._value, value)
163
164             self._value = value
165         else:
166             raise ValueError("Invalid value %s for attribute %s" %
167                     (str(value), self.name))
168
169     value = property(get_value, set_value)
170
171     def is_valid_value(self, value):
172         """ Attribute subclasses will override this method to add 
173         adequate validation"""
174         return True
175