d5bc8a3fe36fbd8063e60bc042a808c3721c8fb4
[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         doc.appendChild(ecnode)
95
96         for guid, rm in ec._resources.iteritems():
97             self._rm_to_xml(doc, ecnode, ec, guid, rm)
98
99         return doc
100
101     def _rm_to_xml(self, doc, ecnode, ec, guid, rm):
102         rmnode = doc.createElement("rm")
103         rmnode.setAttribute("guid", xmlencode(guid))
104         rmnode.setAttribute("rtype", xmlencode(rm._rtype))
105         rmnode.setAttribute("state", xmlencode(rm._state))
106         if rm._start_time:
107             rmnode.setAttribute("start_time", xmlencode(rm._start_time))
108         if rm._stop_time:
109             rmnode.setAttribute("stop_time", xmlencode(rm._stop_time))
110         if rm._discover_time:
111             rmnode.setAttribute("discover_time", xmlencode(rm._discover_time))
112         if rm._provision_time:    
113             rmnode.setAttribute("provision_time", xmlencode(rm._provision_time))
114         if rm._ready_time:
115             rmnode.setAttribute("ready_time", xmlencode(rm._ready_time))
116         if rm._release_time:
117             rmnode.setAttribute("release_time", xmlencode(rm._release_time))
118         if rm._failed_time:
119             rmnode.setAttribute("failed_time", xmlencode(rm._failed_time))
120         ecnode.appendChild(rmnode)
121
122         anode = doc.createElement("attributes")
123         attributes = False
124
125         for attr in rm._attrs.values():
126             if attr.has_changed:
127                 attributes = True
128                 aanode = doc.createElement("attribute")
129                 aanode.setAttribute("name", xmlencode(attr.name))
130                 aanode.setAttribute("value", xmlencode(attr.value))
131                 aanode.setAttribute("type", from_type(attr.value))
132                 anode.appendChild(aanode)
133     
134         if attributes: 
135             rmnode.appendChild(anode)
136
137         cnode = doc.createElement("connections")
138         connections = False
139         
140         for guid in rm._connections:
141             connections = True
142             ccnode = doc.createElement("connection")
143             ccnode.setAttribute("guid", xmlencode(guid))
144             cnode.appendChild(ccnode)
145         
146         if connections:
147            rmnode.appendChild(cnode)
148
149         cnnode = doc.createElement("conditions")
150         conditions = False
151
152         for action, conds in rm._conditions.iteritems():
153             conditions = True
154             for (group, state, time) in conds:
155                 ccnnode = doc.createElement("condition")
156                 ccnnode.setAttribute("action", xmlencode(action))
157                 ccnnode.setAttribute("group", xmlencode(group))
158                 ccnnode.setAttribute("state", xmlencode(state))
159                 ccnnode.setAttribute("time", xmlencode(time))
160                 cnnode.appendChild(ccnnode)
161         
162         if conditions:
163            rmnode.appendChild(cnnode)
164
165         tnode = doc.createElement("traces")
166         traces = False
167
168         for trace in rm._trcs.values():
169             if trace.enabled:
170                 traces = True
171                 ttnode = doc.createElement("trace")
172                 ttnode.setAttribute("name", xmlencode(trace.name))
173                 tnode.appendChild(ttnode)
174     
175         if traces: 
176             rmnode.appendChild(tnode)
177
178     def from_xml(self, xml):
179         doc = minidom.parseString(xml)
180         return self._ec_from_xml(doc)
181
182     def _ec_from_xml(self, doc):
183         from nepi.execution.ec import ExperimentController
184         ec = None
185         
186         ecnode_list = doc.getElementsByTagName("experiment")
187         for ecnode in ecnode_list:
188             if ecnode.nodeType == doc.ELEMENT_NODE:
189                 exp_id = xmldecode(ecnode.getAttribute("exp_id"))
190                 run_id = xmldecode(ecnode.getAttribute("run_id"))
191                 nthreads = xmldecode(ecnode.getAttribute("nthreads"))
192             
193                 os.environ["NEPI_NTHREADS"] = nthreads
194                 ec = ExperimentController(exp_id = exp_id)
195
196                 connections = set()
197
198                 rmnode_list = ecnode.getElementsByTagName("rm")
199                 for rmnode in rmnode_list:
200                     if rmnode.nodeType == doc.ELEMENT_NODE:
201                         self._rm_from_xml(doc, rmnode, ec, connections)
202
203                 for (guid1, guid2) in connections:
204                     ec.register_connection(guid1, guid2)
205
206                 break
207
208         return ec
209
210     def _rm_from_xml(self, doc, rmnode, ec, connections):
211         start_time = None
212         stop_time = None
213         discover_time = None
214         provision_time = None
215         ready_time = None
216         release_time = None
217         failed_time = None
218
219         guid = xmldecode(rmnode.getAttribute("guid"), int)
220         rtype = xmldecode(rmnode.getAttribute("rtype"))
221
222         # FOR NOW ONLY STATE NEW IS ALLOWED
223         state = 0
224         """
225         state = xmldecode(rmnode.getAttribute("state"), int)
226
227         if rmnode.hasAttribute("start_time"):
228             start_time = xmldecode(rmnode.getAttribute("start_time"), 
229                     datetime.datetime)
230         if rmnode.hasAttribute("stop_time"):
231             stop_time = xmldecode(rmnode.getAttribute("stop_time"), 
232                     datetime.datetime)
233         if rmnode.hasAttribute("discover_time"):
234             dicover_time = xmldecode(rmnode.getAttribute("discover_time"), 
235                     datetime.datetime)
236         if rmnode.hasAttribute("provision_time"):
237             provision_time = xmldecode(rmnode.getAttribute("provision_time"),
238                     datetime.datetime)
239         if rmnode.hasAttribute("ready_time"):
240             ready_time = xmldecode(rmnode.getAttribute("ready_time"),
241                     datetime.datetime)
242         if rmnode.hasAttribute("release_time"):
243             release_time = xmldecode(rmnode.getAttribute("release_time"),
244                     datetime.datetime)
245         if rmnode.hasAttribute("failed_time"):
246             failed_time = xmldecode(rmnode.getAttribute("failed_time"),
247                     datetime.datetime)
248         """
249
250         ec.register_resource(rtype, guid = guid)
251         rm = ec.get_resource(guid)
252         rm.set_state_time(state, "_start_time", start_time)
253         rm.set_state_time(state, "_stop_time", stop_time)
254         rm.set_state_time(state, "_discover_time", discover_time)
255         rm.set_state_time(state, "_provision_time", provision_time)
256         rm.set_state_time(state, "_ready_time", ready_time)
257         rm.set_state_time(state, "_release_time", release_time)
258         rm.set_state_time(state, "_failed_time", failed_time)
259         
260         anode_list = rmnode.getElementsByTagName("attributes")
261         if anode_list:
262             aanode_list = anode_list[0].getElementsByTagName("attribute") 
263             for aanode in aanode_list:
264                 name = xmldecode(aanode.getAttribute("name"))
265                 value = xmldecode(aanode.getAttribute("value"))
266                 tipe = xmldecode(aanode.getAttribute("type"))
267                 value = to_type(tipe, value)
268                 rm.set(name, value)
269
270         cnode_list = rmnode.getElementsByTagName("connections")
271         if cnode_list:
272             ccnode_list = cnode_list[0].getElementsByTagName("connection") 
273             for ccnode in ccnode_list:
274                 guid2 = xmldecode(ccnode.getAttribute("guid"), int)
275                 connections.add((guid, guid2))
276
277         tnode_list = rmnode.getElementsByTagName("traces")
278         if tnode_list:
279             ttnode_list = tnode_list[0].getElementsByTagName("trace") 
280             for ttnode in ttnode_list:
281                 name = xmldecode(ttnode.getAttribute("name"))
282                 ec.enable_trace(guid, name)
283
284         cnnode_list = rmnode.getElementsByTagName("conditions")
285         if cnnode_list:
286             ccnnode_list = cnnode_list[0].getElementsByTagName("condition") 
287             for ccnnode in ccnnode_list:
288                 action = xmldecode(ccnnode.getAttribute("action"), int)
289                 group = xmldecode(ccnnode.getAttribute("group"), eval)
290                 state = xmldecode(ccnnode.getAttribute("state"), int)
291                 time = xmldecode(ccnnode.getAttribute("time"))
292                 time = to_type('STRING', time)
293                 ec.register_condition(guid, action, group, state, time = time)
294