4ea57179ed1cf6f61b4f5be09219ea5e44357cf6
[nepi.git] / src / nepi / resources / omf / omf6_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 #         Julien Tribino <julien.tribino@inria.fr>
20
21 from nepi.util.logger import Logger
22
23 import traceback
24 import xml.etree.ElementTree as ET
25
26 # inherit from BaseXmpp and XMLstream classes
27 class OMF6Parser(Logger): 
28     """
29     .. class:: Class Args :
30       
31         :param jid: Jabber Id (= Xmpp Slice + Date)
32         :type jid: str
33         :param password: Jabber Password (= Xmpp Password)
34         :type password: str
35
36     .. note::
37
38        This class is an XMPP Client with customized method
39
40     """
41
42     def __init__(self):
43         """
44
45         :param jid: Jabber Id (= Xmpp Slice + Date)
46         :type jid: str
47         :param password: Jabber Password (= Xmpp Password)
48         :type password: str
49
50
51         """
52         super(OMF6Parser, self).__init__("OMF6API")
53         self.mailbox={}
54
55         self.init_mailbox()
56
57     def init_mailbox(self):
58         self.mailbox['create'] = []
59         self.mailbox['started'] = []
60         self.mailbox['release'] = []
61   
62     def _check_for_tag(self, root, namespaces, tag):
63         """  Check if an element markup is in the ElementTree
64
65         :param root: Root of the tree
66         :type root: ElementTree Element
67         :param namespaces: Namespaces of the element
68         :type namespaces: str
69         :param tag: Tag that will search in the tree
70         :type tag: str
71
72         """
73         for element in root.iter(namespaces+tag):
74             if element.text:
75                 return element.text
76             else : 
77                 return None
78
79     def _check_for_props(self, root, namespaces):
80         """  Check if an element markup is in the ElementTree
81
82         :param root: Root of the tree
83         :type root: ElementTree Element
84         :param namespaces: Namespaces of the element
85         :type namespaces: str
86
87         """
88         props = {}
89         for properties in root.iter(namespaces+'props'):
90             for element in properties.iter():
91                 if element.tag and element.text:
92                     props[element.tag] = element.text
93         return props
94
95     def _check_for_membership(self, root, namespaces):
96         """  Check if an element markup is in the ElementTree
97
98         :param root: Root of the tree
99         :type root: ElementTree Element
100         :param namespaces: Namespaces of the element
101         :type namespaces: str
102
103         """
104         for element in root.iter(namespaces+'membership'):
105             for elt in element.iter(namespaces+'it'):
106                 ##XXX : change
107                 return elt.text
108
109
110     def _check_output(self, root, namespaces):
111         """ Check the significative element in the answer and display it
112
113         :param root: Root of the tree
114         :type root: ElementTree Element
115         :param namespaces: Namespaces of the tree
116         :type namespaces: str
117
118         """
119         fields = ["TARGET", "REASON", "PATH", "APPID", "VALUE"]
120         response = ""
121         for elt in fields:
122             msg = self._check_for_tag(root, namespaces, elt)
123             if msg is not None:
124                 response = response + " " + msg.text + " :"
125         deb = self._check_for_tag(root, namespaces, "MESSAGE")
126         if deb is not None:
127             msg = response + " " + deb.text
128             self.debug(msg)
129         else :
130             self.info(response)
131
132
133     def _inform_creation_ok(self, root, namespaces):
134         """ Parse and Display CREATION OK message
135
136         """
137         #ET.dump(root)
138         uid = self._check_for_tag(root, namespaces, "uid")
139         cid = self._check_for_tag(root, namespaces, "cid")
140         member = self._check_for_membership(root, namespaces)
141         binary_path = self._check_for_tag(root, namespaces, "binary_path")
142         msg = "CREATION OK -- "
143         if binary_path :
144             msg = msg + "The resource : '"+binary_path
145         else :
146             msg = msg + "The interface"
147         if uid :
148             msg = msg + "' is listening to the topics : '"+ uid
149         if member :
150             msg = msg + "' and '"+ member +"'"
151         if cid:
152             self.info(msg)
153             self.mailbox['create'].append([cid, uid ])
154
155     def _inform_creation_failed(self, root, namespaces):
156         """ Parse and Display CREATION FAILED message
157
158         """
159         reason = self._check_for_tag(root, namespaces, "reason")
160         cid = self._check_for_tag(root, namespaces, "cid")
161         msg = "CREATION FAILED - The reason : "+reason
162         if cid:
163             self.error(msg)
164             self.mailbox['create'].append([cid, uid ])
165
166     def _inform_status(self, root, namespaces):
167         """ Parse and Display STATUS message
168
169         """
170         props = self._check_for_props(root, namespaces)
171         uid = self._check_for_tag(root, namespaces, "uid")
172         msg = "STATUS -- "
173         for elt in props.keys():
174             ns, tag = elt.split('}')
175             if tag == "it":
176                 msg = msg + "membership : " + props[elt]+" -- "
177             elif tag == "event":
178                 self.mailbox['started'].append(uid)
179                 msg = msg + "event : " + props[elt]+" -- "
180             else:
181                 msg = msg + tag +" : " + props[elt]+" -- "
182         msg = msg + " STATUS "
183         self.info(msg)
184
185     def _inform_released(self, root, namespaces):
186         """ Parse and Display RELEASED message
187
188         """
189         #ET.dump(root)
190         parent_id = self._check_for_tag(root, namespaces, "src")
191         child_id = self._check_for_tag(root, namespaces, "res_id")
192         cid = self._check_for_tag(root, namespaces, "cid")
193         if cid :
194             msg = "RELEASED - The resource : '"+child_id+ \
195               "' has been released by : '"+ parent_id
196             self.info(msg)
197             self.mailbox['release'].append(cid)
198
199     def _inform_error(self, root, namespaces):
200         """ Parse and Display ERROR message
201
202         """
203         reason = self._check_for_tag(root, namespaces, "reason")
204         msg = "The reason : "+reason
205         self.error(msg)
206
207     def _inform_warn(self, root, namespaces):
208         """ Parse and Display WARN message
209
210         """
211         reason = self._check_for_tag(root, namespaces, "reason")
212         msg = "The reason : "+reason
213         self.warn(msg)
214
215     def _parse_inform(self, root, namespaces):
216         """ Check the significative element in the answer
217             Then Parse it and display using specific method
218
219         :param root: Root of the tree
220         :type root: ElementTree Element
221         :param namespaces: Namespaces of the tree
222         :type namespaces: str
223
224         """
225         itype = self._check_for_tag(root, namespaces, "itype")
226         if itype :
227             method_name = '_inform_'+ itype.replace('.', '_').lower()
228             method = getattr(self, method_name)
229             if method :
230                 method(root, namespaces)
231             else :
232                 msg = "There is no method to parse the response of the type " + itype
233                 self.info(msg)
234                 return
235         
236
237     def check_mailbox(self, itype, attr):
238         """ Check the mail box
239
240         :param itype: type of mail
241         :type itype: str
242         :param attr: value wanted
243         :type attr: str
244
245         """
246         if itype == "create":
247             for res in self.mailbox[itype]:
248                 binary, uid = res
249                 if binary == attr:
250                     self.mailbox[itype].remove(res)
251                     return uid
252         else :
253             for res in self.mailbox[itype]:
254                 if attr == res:
255                     self.mailbox[itype].remove(res)
256                     return res
257                
258
259     def handle(self, iq):
260         """ Check the mail box
261
262         :param iq: message received
263         :type itype: iq
264         """
265         namespaces = "{http://schema.mytestbed.net/omf/6.0/protocol}"
266         for i in iq['pubsub_event']['items']:
267             root = ET.fromstring(str(i))
268             #ET.dump(root)
269             self._parse_inform(root, namespaces)
270