Fixing issues with serialization
[nepi.git] / src / nepi / util / parsers / xml_parser.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 from nepi.util.timefuncs import stformat, tsformat
21
22 from xml.dom import minidom
23
24 import datetime
25 import sys
26 import os
27
28 STRING = "string"
29 BOOL = "bool"
30 INTEGER = "integer"
31 DOUBLE = "float"
32
33 def xmlencode(s):
34     if isinstance(s, str):
35         rv = s.decode("latin1")
36     if isinstance(s, datetime.datetime):
37         rv = tsformat(s)
38     elif not isinstance(s, unicode):
39         rv = unicode(s)
40     else:
41         rv = s
42     return rv.replace(u'\x00',u'&#0000;')
43
44 def xmldecode(s, cast = str):
45     ret = s.replace(u'&#0000',u'\x00').encode("ascii")
46     ret = cast(ret)
47     if s == "None":
48         return None
49     return ret
50
51 def from_type(value):
52     if isinstance(value, bool):
53         return BOOL
54     if isinstance(value, int):
55         return INTEGER
56     if isinstance(value, float):
57         return DOUBLE
58
59     return STRING
60
61 def to_type(type, value):
62     if not value:
63         return value
64
65     if type == STRING:
66         return str(value)
67     if type == BOOL:
68         return value == "True"
69     if type == INTEGER:
70         return int(value)
71     if type == DOUBLE:
72         return float(value)
73
74 class ECXMLParser(object):
75     def to_xml(self, ec):
76         
77         doc = minidom.Document()
78         
79         self._ec_to_xml(doc, ec)
80        
81         try:
82             xml = doc.toprettyxml(indent="    ", encoding="UTF-8")
83         except:
84             print >>sys.stderr, "Oops: generating XML from %s" % (data,)
85             raise
86         
87         return xml
88
89     def _ec_to_xml(self, doc, ec):
90         ecnode = doc.createElement("experiment")
91         ecnode.setAttribute("exp_id", xmlencode(ec.exp_id))
92         ecnode.setAttribute("run_id", xmlencode(ec.run_id))
93         ecnode.setAttribute("nthreads", xmlencode(ec.nthreads))
94         ecnode.setAttribute("local_dir", xmlencode(ec.local_dir))
95         ecnode.setAttribute("exp_dir", xmlencode(ec.exp_dir))
96
97         doc.appendChild(ecnode)
98
99         for guid, rm in ec._resources.iteritems():
100             self._rm_to_xml(doc, ecnode, ec, guid, rm)
101
102         return doc
103     
104     def _netgraph_to_xml(self, doc, ecnode, ec):
105
106     def _rm_to_xml(self, doc, ecnode, ec, guid, rm):
107         rmnode = doc.createElement("rm")
108         rmnode.setAttribute("guid", xmlencode(guid))
109         rmnode.setAttribute("rtype", xmlencode(rm._rtype))
110         rmnode.setAttribute("state", xmlencode(rm._state))
111         if rm._start_time:
112             rmnode.setAttribute("start_time", xmlencode(rm._start_time))
113         if rm._stop_time:
114             rmnode.setAttribute("stop_time", xmlencode(rm._stop_time))
115         if rm._discover_time:
116             rmnode.setAttribute("discover_time", xmlencode(rm._discover_time))
117         if rm._provision_time:    
118             rmnode.setAttribute("provision_time", xmlencode(rm._provision_time))
119         if rm._ready_time:
120             rmnode.setAttribute("ready_time", xmlencode(rm._ready_time))
121         if rm._release_time:
122             rmnode.setAttribute("release_time", xmlencode(rm._release_time))
123         if rm._failed_time:
124             rmnode.setAttribute("failed_time", xmlencode(rm._failed_time))
125         ecnode.appendChild(rmnode)
126
127         anode = doc.createElement("attributes")
128         attributes = False
129
130         for attr in rm._attrs.values():
131             if attr.has_changed:
132                 attributes = True
133                 aanode = doc.createElement("attribute")
134                 aanode.setAttribute("name", xmlencode(attr.name))
135                 aanode.setAttribute("value", xmlencode(attr.value))
136                 aanode.setAttribute("type", from_type(attr.value))
137                 anode.appendChild(aanode)
138     
139         if attributes: 
140             rmnode.appendChild(anode)
141
142         cnode = doc.createElement("connections")
143         connections = False
144         
145         for guid in rm._connections:
146             connections = True
147             ccnode = doc.createElement("connection")
148             ccnode.setAttribute("guid", xmlencode(guid))
149             cnode.appendChild(ccnode)
150         
151         if connections:
152            rmnode.appendChild(cnode)
153
154         cnnode = doc.createElement("conditions")
155         conditions = False
156
157         for action, conds in rm._conditions.iteritems():
158             conditions = True
159             for (group, state, time) in conds:
160                 ccnnode = doc.createElement("condition")
161                 ccnnode.setAttribute("action", xmlencode(action))
162                 ccnnode.setAttribute("group", xmlencode(group))
163                 ccnnode.setAttribute("state", xmlencode(state))
164                 ccnnode.setAttribute("time", xmlencode(time))
165                 cnnode.appendChild(ccnnode)
166         
167         if conditions:
168            rmnode.appendChild(cnnode)
169
170         tnode = doc.createElement("traces")
171         traces = False
172
173         for trace in rm._trcs.values():
174             if trace.enabled:
175                 traces = True
176                 ttnode = doc.createElement("trace")
177                 ttnode.setAttribute("name", xmlencode(trace.name))
178                 tnode.appendChild(ttnode)
179     
180         if traces: 
181             rmnode.appendChild(tnode)
182
183     def from_xml(self, xml):
184         doc = minidom.parseString(xml)
185         return self._ec_from_xml(doc)
186
187     def _ec_from_xml(self, doc):
188         from nepi.execution.ec import ExperimentController
189         ec = None
190         
191         ecnode_list = doc.getElementsByTagName("experiment")
192         for ecnode in ecnode_list:
193             if ecnode.nodeType == doc.ELEMENT_NODE:
194                 exp_id = xmldecode(ecnode.getAttribute("exp_id"))
195                 run_id = xmldecode(ecnode.getAttribute("run_id"))
196                 local_dir = xmldecode(ecnode.getAttribute("local_dir"))
197                 nthreads = xmldecode(ecnode.getAttribute("nthreads"))
198             
199                 os.environ["NEPI_NTHREADS"] = nthreads
200                 ec = ExperimentController(exp_id = exp_id, local_dir = local_dir)
201
202                 connections = set()
203
204                 rmnode_list = ecnode.getElementsByTagName("rm")
205                 for rmnode in rmnode_list:
206                     if rmnode.nodeType == doc.ELEMENT_NODE:
207                         self._rm_from_xml(doc, rmnode, ec, connections)
208
209                 for (guid1, guid2) in connections:
210                     ec.register_connection(guid1, guid2)
211
212                 break
213
214         return ec
215
216     def _rm_from_xml(self, doc, rmnode, ec, connections):
217         start_time = None
218         stop_time = None
219         discover_time = None
220         provision_time = None
221         ready_time = None
222         release_time = None
223         failed_time = None
224
225         guid = xmldecode(rmnode.getAttribute("guid"), int)
226         rtype = xmldecode(rmnode.getAttribute("rtype"))
227
228         # FOR NOW ONLY STATE NEW IS ALLOWED
229         state = 0
230         """
231         state = xmldecode(rmnode.getAttribute("state"), int)
232
233         if rmnode.hasAttribute("start_time"):
234             start_time = xmldecode(rmnode.getAttribute("start_time"), 
235                     datetime.datetime)
236         if rmnode.hasAttribute("stop_time"):
237             stop_time = xmldecode(rmnode.getAttribute("stop_time"), 
238                     datetime.datetime)
239         if rmnode.hasAttribute("discover_time"):
240             dicover_time = xmldecode(rmnode.getAttribute("discover_time"), 
241                     datetime.datetime)
242         if rmnode.hasAttribute("provision_time"):
243             provision_time = xmldecode(rmnode.getAttribute("provision_time"),
244                     datetime.datetime)
245         if rmnode.hasAttribute("ready_time"):
246             ready_time = xmldecode(rmnode.getAttribute("ready_time"),
247                     datetime.datetime)
248         if rmnode.hasAttribute("release_time"):
249             release_time = xmldecode(rmnode.getAttribute("release_time"),
250                     datetime.datetime)
251         if rmnode.hasAttribute("failed_time"):
252             failed_time = xmldecode(rmnode.getAttribute("failed_time"),
253                     datetime.datetime)
254         """
255
256         ec.register_resource(rtype, guid = guid)
257         rm = ec.get_resource(guid)
258         rm.set_state_time(state, "_start_time", start_time)
259         rm.set_state_time(state, "_stop_time", stop_time)
260         rm.set_state_time(state, "_discover_time", discover_time)
261         rm.set_state_time(state, "_provision_time", provision_time)
262         rm.set_state_time(state, "_ready_time", ready_time)
263         rm.set_state_time(state, "_release_time", release_time)
264         rm.set_state_time(state, "_failed_time", failed_time)
265         
266         anode_list = rmnode.getElementsByTagName("attributes")
267         if anode_list:
268             aanode_list = anode_list[0].getElementsByTagName("attribute") 
269             for aanode in aanode_list:
270                 name = xmldecode(aanode.getAttribute("name"))
271                 value = xmldecode(aanode.getAttribute("value"))
272                 tipe = xmldecode(aanode.getAttribute("type"))
273                 value = to_type(tipe, value)
274                 rm.set(name, value)
275
276         cnode_list = rmnode.getElementsByTagName("connections")
277         if cnode_list:
278             ccnode_list = cnode_list[0].getElementsByTagName("connection") 
279             for ccnode in ccnode_list:
280                 guid2 = xmldecode(ccnode.getAttribute("guid"), int)
281                 connections.add((guid, guid2))
282
283         tnode_list = rmnode.getElementsByTagName("traces")
284         if tnode_list:
285             ttnode_list = tnode_list[0].getElementsByTagName("trace") 
286             for ttnode in ttnode_list:
287                 name = xmldecode(ttnode.getAttribute("name"))
288                 ec.enable_trace(guid, name)
289
290         cnnode_list = rmnode.getElementsByTagName("conditions")
291         if cnnode_list:
292             ccnnode_list = cnnode_list[0].getElementsByTagName("condition") 
293             for ccnnode in ccnnode_list:
294                 action = xmldecode(ccnnode.getAttribute("action"), int)
295                 group = xmldecode(ccnnode.getAttribute("group"), eval)
296                 state = xmldecode(ccnnode.getAttribute("state"), int)
297                 time = xmldecode(ccnnode.getAttribute("time"))
298                 time = to_type('STRING', time)
299                 ec.register_condition(guid, action, group, state, time = time)
300