rename src/nepi/ into just nepi/
[nepi.git] / nepi / resources / omf / omf6_parser.py
diff --git a/nepi/resources/omf/omf6_parser.py b/nepi/resources/omf/omf6_parser.py
new file mode 100644 (file)
index 0000000..68786b6
--- /dev/null
@@ -0,0 +1,289 @@
+#
+#    NEPI, a framework to manage network experiments
+#    Copyright (C) 2013 INRIA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License version 2 as
+#    published by the Free Software Foundation;
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Alina Quereilhac <alina.quereilhac@inria.fr>
+#         Julien Tribino <julien.tribino@inria.fr>
+
+from nepi.util.logger import Logger
+
+import os
+import traceback
+import xml.etree.ElementTree as ET
+
+# inherit from BaseXmpp and XMLstream classes
+class OMF6Parser(Logger): 
+    """
+    .. class:: Class Args :
+      
+        :param jid: Jabber Id (= Xmpp Slice + Date)
+        :type jid: str
+        :param password: Jabber Password (= Xmpp Password)
+        :type password: str
+
+    .. note::
+
+       This class is an XMPP Client with customized method
+
+    """
+
+    def __init__(self):
+        """
+
+        :param jid: Jabber Id (= Xmpp Slice + Date)
+        :type jid: str
+        :param password: Jabber Password (= Xmpp Password)
+        :type password: str
+
+
+        """
+        super(OMF6Parser, self).__init__("OMF6API")
+        self.mailbox={}
+        self.traces={}
+        self.trace='NULL'
+
+        self.init_mailbox()
+
+
+    def init_mailbox(self):
+        self.mailbox['create'] = []
+        self.mailbox['started'] = []
+        self.mailbox['release'] = []
+  
+    def _check_for_tag(self, root, namespaces, tag):
+        """  Check if an element markup is in the ElementTree
+
+        :param root: Root of the tree
+        :type root: ElementTree Element
+        :param namespaces: Namespaces of the element
+        :type namespaces: str
+        :param tag: Tag that will search in the tree
+        :type tag: str
+
+        """
+        for element in root.iter(namespaces+tag):
+            if element.text:
+                return element.text
+            else : 
+                return None
+
+    def _check_for_props(self, root, namespaces):
+        """  Check if an element markup is in the ElementTree
+
+        :param root: Root of the tree
+        :type root: ElementTree Element
+        :param namespaces: Namespaces of the element
+        :type namespaces: str
+
+        """
+        props = {}
+        for properties in root.iter(namespaces+'props'):
+            for element in properties.iter():
+                if element.tag and element.text:
+                    props[element.tag] = element.text
+        return props
+
+    def _check_for_membership(self, root, namespaces):
+        """  Check if an element markup is in the ElementTree
+
+        :param root: Root of the tree
+        :type root: ElementTree Element
+        :param namespaces: Namespaces of the element
+        :type namespaces: str
+
+        """
+        for element in root.iter(namespaces+'membership'):
+            for elt in element.iter(namespaces+'it'):
+                ##XXX : change
+                return elt.text
+
+
+    def _check_output(self, root, namespaces):
+        """ Check the significative element in the answer and display it
+
+        :param root: Root of the tree
+        :type root: ElementTree Element
+        :param namespaces: Namespaces of the tree
+        :type namespaces: str
+
+        """
+        fields = ["TARGET", "REASON", "PATH", "APPID", "VALUE"]
+        response = ""
+        for elt in fields:
+            msg = self._check_for_tag(root, namespaces, elt)
+            if msg is not None:
+                response = response + " " + msg.text + " :"
+        deb = self._check_for_tag(root, namespaces, "MESSAGE")
+        if deb is not None:
+            msg = response + " " + deb.text
+            self.debug(msg)
+        else :
+            self.info(response)
+
+
+    def _inform_creation_ok(self, root, namespaces):
+        """ Parse and Display CREATION OK message
+
+        """
+        #ET.dump(root)
+        uid = self._check_for_tag(root, namespaces, "uid")
+        cid = self._check_for_tag(root, namespaces, "cid")
+        member = self._check_for_membership(root, namespaces)
+        binary_path = self._check_for_tag(root, namespaces, "binary_path")
+        msg = "CREATION OK -- "
+        if binary_path :
+            msg = msg + "The resource : '"+binary_path
+        else :
+            msg = msg + "The interface"
+        if uid :
+            msg = msg + "' is listening to the topics : '"+ uid
+        if member :
+            msg = msg + "' and '"+ member +"'"
+        if cid:
+            self.info(msg)
+            self.mailbox['create'].append([cid, uid ])
+
+    def _inform_creation_failed(self, root, namespaces):
+        """ Parse and Display CREATION FAILED message
+
+        """
+        reason = self._check_for_tag(root, namespaces, "reason")
+        cid = self._check_for_tag(root, namespaces, "cid")
+        msg = "CREATION FAILED - The reason : "+reason
+        if cid:
+            self.error(msg)
+            self.mailbox['create'].append([cid, uid ])
+
+    def _inform_status(self, root, namespaces):
+        """ Parse and Display STATUS message
+
+        """
+        props = self._check_for_props(root, namespaces)
+        uid = self._check_for_tag(root, namespaces, "uid")
+        event = self._check_for_tag(root, namespaces, "event")
+
+        log = "STATUS -- "
+        for elt in props:
+            ns, tag = elt.split('}')
+            if tag == "it":
+                log = log + "membership : " + props[elt]+" -- "
+            elif tag == "event":
+                self.mailbox['started'].append(uid)
+                log = log + "event : " + props[elt]+" -- "
+            elif tag == "msg":
+                if event == "STDOUT" : 
+                    filename = os.path.join("/tmp", "%s.out" % uid)
+                    with open(filename,'a+') as f:
+                        # XXX: Adding fake \n for visual formatting 
+                        msg = props[elt] # + "\n"
+                        f.write(msg)
+                elif event == "STDERR" :
+                    filename = os.path.join("/tmp", "%s.err" % uid)
+                    with open(filename,'a+') as f:
+                        # XXX: Adding fake \n for visual formatting 
+                        msg = props[elt] # + "\n"
+                        f.write(msg)
+                log = log + tag +" : " + props[elt]+" -- "
+            else:
+                log = log + tag +" : " + props[elt]+" -- "
+        log = log + " STATUS "
+        self.info(log)
+
+    def _inform_released(self, root, namespaces):
+        """ Parse and Display RELEASED message
+
+        """
+        #ET.dump(root)
+        parent_id = self._check_for_tag(root, namespaces, "src")
+        child_id = self._check_for_tag(root, namespaces, "res_id")
+        cid = self._check_for_tag(root, namespaces, "cid")
+        if cid :
+            msg = "RELEASED - The resource : '"+child_id+ \
+              "' has been released by : '"+ parent_id
+            self.info(msg)
+            self.mailbox['release'].append(cid)
+
+    def _inform_error(self, root, namespaces):
+        """ Parse and Display ERROR message
+
+        """
+        reason = self._check_for_tag(root, namespaces, "reason")
+        msg = "The reason : "+reason
+        self.error(msg)
+
+    def _inform_warn(self, root, namespaces):
+        """ Parse and Display WARN message
+
+        """
+        reason = self._check_for_tag(root, namespaces, "reason")
+        msg = "The reason : "+reason
+        self.warn(msg)
+
+    def _parse_inform(self, root, namespaces):
+        """ Check the significative element in the answer
+            Then Parse it and display using specific method
+
+        :param root: Root of the tree
+        :type root: ElementTree Element
+        :param namespaces: Namespaces of the tree
+        :type namespaces: str
+
+        """
+        itype = self._check_for_tag(root, namespaces, "itype")
+        if itype :
+            method_name = '_inform_'+ itype.replace('.', '_').lower()
+            method = getattr(self, method_name)
+            if method :
+                method(root, namespaces)
+            else :
+                msg = "There is no method to parse the response of the type " + itype
+                self.info(msg)
+                return
+        
+
+    def check_mailbox(self, itype, attr):
+        """ Check the mail box
+
+        :param itype: type of mail
+        :type itype: str
+        :param attr: value wanted
+        :type attr: str
+
+        """
+        if itype == "create":
+            for res in self.mailbox[itype]:
+                binary, uid = res
+                if binary == attr:
+                    self.mailbox[itype].remove(res)
+                    return uid
+        else :
+            for res in self.mailbox[itype]:
+                if attr == res:
+                    self.mailbox[itype].remove(res)
+                    return res
+               
+
+    def handle(self, iq):
+        """ Check the mail box
+
+        :param iq: message received
+        :type itype: iq
+        """
+        namespaces = "{http://schema.mytestbed.net/omf/6.0/protocol}"
+        for i in iq['pubsub_event']['items']:
+            root = ET.fromstring(str(i))
+            #ET.dump(root)
+            self._parse_inform(root, namespaces)
+