Ejemplo n.º 1
0
    def test_set_data(self):
        """ Test XplMessage.set_data() method.
        """
        self.__xpl_message.set_data({
            "command": "dim",
            "device": "a1",
            "level": "75"
        })
        self.assertEqual(
            self.__xpl_message.data,
            OrderedDict({
                "command": "dim",
                "device": "a1",
                "level": "75"
            }))

        # Check if correctly remove previous data
        self.__xpl_message.set_data({
            "command2": "dim",
            "device2": "a1",
            "level2": "75"
        })
        self.assertEqual(
            self.__xpl_message.data,
            OrderedDict({
                "command2": "dim",
                "device2": "a1",
                "level2": "75"
            }))
Ejemplo n.º 2
0
    def __init__(self, packet=None):
        """ Message object.

        Create Message instance from a message string and check if the
        structure is correct. Raise exception if it is not
        The message can be None (to allow building a message)

        @param packet : message packet, as sent on the network
        @type packet: str
        """
        super(XplMessage, self).__init__()
        self.type = ""
        self.hop_count = 1
        self.source = ""
        self.source_vendor_id = ""
        self.source_device_id = ""
        self.source_instance_id = ""
        self.target = ""
        self.target_vendor_id = ""
        self.target_device_id = ""
        self.target_instance_id = ""
        self.schema = ""
        self.schema_class = ""
        self.schema_type = ""
        self.data = OrderedDict()
        if packet is not None:
            self.from_packet(packet)
Ejemplo n.º 3
0
    def set_data(self, data):
        """ Set message data, replacing previous ones. ???

        First build data as str, to be parsed by the regexp.

        @param data: message data, as name/value pairs
        @type data: dict or L{OrderedDict}
        """
        data_backup = copy.deepcopy(self.data)
        try:
            self.data = OrderedDict()
            self.add_data(data)
        except XplMessageError:
            self.data = copy.deepcopy(data_backup)
            raise
Ejemplo n.º 4
0
    def __init__(self, packet=None):
        """ Message object.

        Create Message instance from a message string and check if the
        structure is correct. Raise exception if it is not
        The message can be None (to allow building a message)

        @param packet : message packet, as sent on the network
        @type packet: str
        """
        super(XplMessage, self).__init__()
        self.type = ""
        self.hop_count = 1
        self.source = ""
        self.source_vendor_id = ""
        self.source_device_id = ""
        self.source_instance_id = ""
        self.target = ""
        self.target_vendor_id = ""
        self.target_device_id = ""
        self.target_instance_id = ""
        self.schema = ""
        self.schema_class = ""
        self.schema_type = ""
        self.data = OrderedDict()
        if packet is not None:
            self.from_packet(packet)
Ejemplo n.º 5
0
    def fragment_message(message, uid):
        """ Fill the instance with fragments from the message
        @param message: XplMessage instance to split
        @param uid : the unique ID that should identify this message
        @return an OrderedDict which contains all the fragments
        """
        #we use an OrderedDict to store messages until we know the total number of messages
        message_list = OrderedDict()
        msg = FragmentedXplMessage.__init_fragment(message, uid)
        base_len = len(msg.to_packet())
        f_id = 1
        for k in message.data:
            if type(message.data[k]) == list:
                for l in message.data[k]:
                    if not FragmentedXplMessage.__try_add_item_to_message(
                            msg, k, l):
                        message_list[f_id] = msg
                        msg = FragmentedXplMessage.__init_fragment(
                            message, uid)
                        FragmentedXplMessage.__try_add_item_to_message(
                            msg, k, l)
                        f_id = f_id + 1
            else:
                if not FragmentedXplMessage.__try_add_item_to_message(
                        msg, k, message.data[k]):
                    message_list[f_id] = msg
                    msg = FragmentedXplMessage.__init_fragment(message, uid)
                    FragmentedXplMessage.__try_add_item_to_message(
                        msg, k, message.data[k])
                    f_id = f_id + 1

        message_list[f_id] = msg
        return FragmentedXplMessage.__update_fragments_ids(message_list, uid)
Ejemplo n.º 6
0
    def test_from_packet(self):
        """ Test the XplMessage.from_packet() method.
        """
        wrong_packet = \
"""xpl-cmnd
{
target=acme-cm12.server
}
{
command=dim
device=a1
level=75
}
"""
        self.assertRaises(XplMessageError, self.__xpl_message.from_packet,
                          wrong_packet)

        packet = \
"""xpl-cmnd
{
hop=1
source=xpl-xplhal.myhouse
target=acme-cm12.server
}
x10.basic
{
command=dim
device=a1
level=75
}
"""
        self.__xpl_message.from_packet(packet)
        self.assertEqual(self.__xpl_message.type, 'xpl-cmnd')
        self.assertEqual(self.__xpl_message.hop_count, 1)
        self.assertEqual(self.__xpl_message.source, "xpl-xplhal.myhouse")
        self.assertEqual(self.__xpl_message.source_vendor_id, "xpl")
        self.assertEqual(self.__xpl_message.source_device_id, "xplhal")
        self.assertEqual(self.__xpl_message.source_instance_id, "myhouse")
        self.assertEqual(self.__xpl_message.target, "acme-cm12.server")
        self.assertEqual(self.__xpl_message.target_vendor_id, "acme")
        self.assertEqual(self.__xpl_message.target_device_id, "cm12")
        self.assertEqual(self.__xpl_message.target_instance_id, "server")
        self.assertEqual(self.__xpl_message.schema, "x10.basic")
        self.assertEqual(self.__xpl_message.schema_class, "x10")
        self.assertEqual(self.__xpl_message.schema_type, "basic")
        self.assertEqual(
            self.__xpl_message.data,
            OrderedDict({
                "command": "dim",
                "device": "a1",
                "level": "75"
            }))
Ejemplo n.º 7
0
    def set_data(self, data):
        """ Set message data, replacing previous ones. ???

        First build data as str, to be parsed by the regexp.

        @param data: message data, as name/value pairs
        @type data: dict or L{OrderedDict}
        """
        data_backup = copy.deepcopy(self.data)
        try:
            self.data = OrderedDict()
            self.add_data(data)
        except XplMessageError:
            self.data = copy.deepcopy(data_backup)
            raise
Ejemplo n.º 8
0
    def from_packet(self, packet):
        """ Decode message from given packet.

        @param packet: message packet, as sent on the network
        @type packet: str

        @raise XplMessageError: the message packet is incorrect

        @raise XplMessageError: invalid message packet
        """
        match_global = XplMessage.__regexp_global.match(packet)
        if match_global is None:
            raise XplMessageError("Invalid message packet")
        else:
            match_global_dict = match_global.groupdict()
            self.set_type(match_global_dict['type_'])
            self.set_hop_count(match_global_dict['hop_count'])
            self.set_source(match_global_dict['source'])
            self.set_target(match_global_dict['target'])
            self.set_schema(match_global_dict['schema'])
            self.data = OrderedDict()
            data = match_global_dict[
                'data'] + '\n'  # The global match remove the last '\n'
            self.__parse_data(data)
Ejemplo n.º 9
0
    def from_packet(self, packet):
        """ Decode message from given packet.

        @param packet: message packet, as sent on the network
        @type packet: str

        @raise XplMessageError: the message packet is incorrect

        @raise XplMessageError: invalid message packet
        """
        match_global = XplMessage.__regexp_global.match(packet)
        if match_global is None:
            raise XplMessageError("Invalid message packet")
        else:
            match_global_dict = match_global.groupdict()
            self.set_type(match_global_dict['type_'])
            self.set_hop_count(match_global_dict['hop_count'])
            self.set_source(match_global_dict['source'])
            self.set_target(match_global_dict['target'])
            self.set_schema(match_global_dict['schema'])
            self.data = OrderedDict()
            data = match_global_dict['data'] + '\n'  # The global match remove the last '\n'
            self.__parse_data(data)
Ejemplo n.º 10
0
 def clear_data(self):
     """ Clear the message data.
     """
     self.data = OrderedDict()
Ejemplo n.º 11
0
class XplMessage(object):
    """ xPL Message facility.

    XplMessage is the object for data send/received on the network.
    """
    __regexp_type = re.compile(REGEXP_TYPE, re.UNICODE | re.VERBOSE)
    __regexp_hop_count = re.compile(REGEXP_HOP_COUNT, re.UNICODE | re.VERBOSE)
    __regexp_source = re.compile(REGEXP_SOURCE, re.UNICODE | re.VERBOSE)
    __regexp_target = re.compile(REGEXP_TARGET, re.UNICODE | re.VERBOSE)
    __regexp_schema = re.compile(REGEXP_SCHEMA, re.UNICODE | re.VERBOSE)
    __regexp_data = re.compile(REGEXP_DATA, re.UNICODE | re.VERBOSE)
    __regexp_single_data = re.compile(REGEXP_SINGLE_DATA, re.UNICODE | re.VERBOSE)
    __regexp_global = re.compile(REGEXP_GLOBAL, re.DOTALL | re.UNICODE | re.VERBOSE)

    def __init__(self, packet=None):
        """ Message object.

        Create Message instance from a message string and check if the
        structure is correct. Raise exception if it is not
        The message can be None (to allow building a message)

        @param packet : message packet, as sent on the network
        @type packet: str
        """
        super(XplMessage, self).__init__()
        self.type = ""
        self.hop_count = 1
        self.source = ""
        self.source_vendor_id = ""
        self.source_device_id = ""
        self.source_instance_id = ""
        self.target = ""
        self.target_vendor_id = ""
        self.target_device_id = ""
        self.target_instance_id = ""
        self.schema = ""
        self.schema_class = ""
        self.schema_type = ""
        self.data = OrderedDict()
        if packet is not None:
            self.from_packet(packet)

    def __str__(self):
        return self.to_packet()

    def __parse_data(self, data):
        """ Parse message data.

        The data are added to existing ones.

        @param data: message data, as "<name1>=>value1>\n<name2>=<value2>\n..."
        @type data: str

        @raise XplMessageError: invalid data

        @todo: use OrderedDict for data storage
        """
        match_data = XplMessage.__regexp_data.match(data)
        if match_data is None:
            raise XplMessageError("Invalid data")
        match_data_dict = match_data.groupdict()
        data_list = match_data_dict['data'].split('\n')
        for data_ in data_list:
            if data_:
                self.__parse_single_data(data_)

    def __parse_single_data(self, data):
        """ Parse single message data.

        The data are added to existing ones.

        @param data: single message data, as "<name>=<value>"
        @type data: str

        @raise XplMessageError: invalid data
        """
        match_single_data = XplMessage.__regexp_single_data.match(data)
        if match_single_data is None:
            raise XplMessageError("Invalid data (%s)" % data)
        match_single_data_dict = match_single_data.groupdict()
        #self.data.append((match_single_data_dict['data_name'], match_single_data_dict['data_value']))
        key = match_single_data_dict['data_name']
        if key in self.data:
            if type(self.data[key]) != list:
                v = self.data[key]
                self.data[key] = [v]
            self.data[key].append(match_single_data_dict['data_value'])
        else:
            self.data[key] = match_single_data_dict['data_value']

    def set_type(self, type_):
        """ Set the message type.

        @param type_: message type, in ('xpl-stat', 'xpl-trig', 'xpl-cmnd')
        @type type_: str

        @raise XplMessageError: invalid type
        """
        match_type = XplMessage.__regexp_type.match(type_)
        if match_type is None:
            raise XplMessageError("Invalid type (%s)" % type_)
        self.type = type_

    def set_hop_count(self, hop_count):
        """ Set hop count value.

        @param hop_count: hop count
        @type hop_count: int or str

        @raise XplMessageError: invalid hop count value
        """
        match_hop_count = XplMessage.__regexp_hop_count.match(str(hop_count))
        if match_hop_count is None:
            raise XplMessageError("Invalid hop count value (%d)" % int(hop_count))
        self.hop_count = int(hop_count)

    def inc_hop_count(self):
        """ Increment hop count value.

        @raise XplMessageError: exceeded hop count value
        """
        hop_count = self.hop_count + 1
        match_hop_count = XplMessage.__regexp_hop_count.match(str(hop_count))
        if match_hop_count is None:
            raise XplMessageError("Exceeded hop count value (%s)" % str(hop_count))
        self.hop_count = hop_count

    def set_source(self, source):
        """ Set source.

        @param source: message source
        @type source: str

        @raise XplMessageError: invalid source
        """
        match_source = XplMessage.__regexp_source.match(source)
        if match_source is None:
            raise XplMessageError("Invalid source (%s)" % source)
        match_source_dict = match_source.groupdict()
        for key, value in match_source_dict.items():
            setattr(self, key, value)

    def set_target(self, target):
        """ Set target.

        @param target: message target
        @type targer: str

        @raise XplMessageError: invalid target
        """
        match_target = XplMessage.__regexp_target.match(target)
        if match_target is None:
            raise XplMessageError("Invalid target (%s)" % target)
        match_target_dict = match_target.groupdict()
        for key, value in match_target_dict.items():
            setattr(self, key, value)

    def set_header(self, hop_count=None, source=None, target=None):
        """ Set the message header.

        @param hop_count: hop count
        @type hop_count: int

        @param source: message source
        @type source: str

        @param target: message target
        @type targer: str
        """
        if hop_count is not None:
            self.set_hop_count(hop_count)
        if source is not None:
            self.set_source(source)
        if target is not None:
            self.set_target(target)

    def set_schema(self, schema):
        """ Set message schema.

        @param schema: message schema
        @type schema: str

        @raise XplMessageError: invalid schema
        """
        match_schema = XplMessage.__regexp_schema.match(schema)
        if match_schema is None:
            raise XplMessageError("Invalid schema (%s)" % schema)
        match_schema_dict = match_schema.groupdict()
        for key, value in match_schema_dict.items():
            setattr(self, key, value)

    def add_single_data(self, name, value):
        """ Add a single message data.

        @param name: data name
        @type name: str

        @param value: data value
        @type value: any
        """
        data_str = "%s=%s" % (name, value)
        self.__parse_single_data(data_str)

    def add_data(self, data):
        """ Add message data to the existing ones.

        First build data as str, to be parsed by the regexp.

        @param data: message data, as name/value pairs
        @type data: dict or L{OrderedDict}
        """
        for name, value in data.items():
            self.add_single_data(name, value)

    def set_data(self, data):
        """ Set message data, replacing previous ones. ???

        First build data as str, to be parsed by the regexp.

        @param data: message data, as name/value pairs
        @type data: dict or L{OrderedDict}
        """
        data_backup = copy.deepcopy(self.data)
        try:
            self.data = OrderedDict()
            self.add_data(data)
        except XplMessageError:
            self.data = copy.deepcopy(data_backup)
            raise

    def clear_data(self):
        """ Clear the message data.
        """
        self.data = OrderedDict()

    def from_packet(self, packet):
        """ Decode message from given packet.

        @param packet: message packet, as sent on the network
        @type packet: str

        @raise XplMessageError: the message packet is incorrect

        @raise XplMessageError: invalid message packet
        """
        match_global = XplMessage.__regexp_global.match(packet)
        if match_global is None:
            raise XplMessageError("Invalid message packet")
        else:
            match_global_dict = match_global.groupdict()
            self.set_type(match_global_dict['type_'])
            self.set_hop_count(match_global_dict['hop_count'])
            self.set_source(match_global_dict['source'])
            self.set_target(match_global_dict['target'])
            self.set_schema(match_global_dict['schema'])
            self.data = OrderedDict()
            data = match_global_dict['data'] + '\n'  # The global match remove the last '\n'
            self.__parse_data(data)

    def to_packet(self):
        """ Convert the message to packet.

        @return: message packet, as sent on the network
        @rtype: str
        """
        packet = "%s\n" % self.type
        packet += "{\n"
        packet += "hop=%d\n" % self.hop_count
        packet += "source=%s\n" % self.source
        packet += "target=%s\n" % self.target
        packet += "}\n"
        packet += "%s\n" % self.schema
        packet += "{\n"
        for key, value in self.data.items():
            if type(value) == list:
                for v in value:
                    packet += "%s=%s\n" % (key, v)
            else:
                packet += "%s=%s\n" % (key, value)
        packet += "}\n"

        return packet

    def is_valid(self):
        """ Check if the message is valid.

        @return: True if message is valid, False otherwise
        @rtype: bool
        """
        try:
            self.from_packet(self.to_packet())
        except XplMessageError:
            return False
        else:
            return True
Ejemplo n.º 12
0
class HeyuManager:
    """
    This class manages the heyu configuration file
    """

    ITEMS_SECTION = OrderedDict()
    ITEMS_SECTION['general'] = [
        'TTY', 'TTY_AUX', 'LOG_DIR', 'HOUSECODE', 'REPORT_PATH',
        'DEFAULT_MODULE', 'START_ENGINE', 'DATE_FORMAT', 'LOGDATE_YEAR',
        'TAILPATH', 'HEYU_UMASK', 'STATUS_TIMEOUT', 'SPF_TIMEOUT',
        'TRANS_DIMLEVEL'
    ]
    ITEMS_SECTION['aliases'] = ['ALIAS']
    ITEMS_SECTION['scenes'] = ['SCENE', 'USERSYN', 'MAX_PPARMS']
    ITEMS_SECTION['scripts'] = ['SCRIPT', 'SCRIPT_MODE', 'SCRIPT_CTRL']
    ITEMS_SECTION['scheduler'] = [
        'SCHEDULE_FILE', 'MODE', 'PROGRAM_DAYS', 'COMBINE_EVENTS',
        'COMPRESS_MACROS', 'REPL_DELAYED_MACROS', 'WRITE_CHECK_FILES'
    ]
    ITEMS_SECTION['dawnduk'] = [
        'LONGITUDE', 'LATITUDE', 'DAWN_OPTION', 'DUSK_OPTION', 'MIN_DAWN',
        'MAX_DAWN', 'MIN_DUSK', 'MAX_DUSK'
    ]

    def __init__(self, path):
        """
        @param path = The heyu config file path, must be absolute
        """
        self._file = "%s" % path

    def load(self):
        """
        Load the file and parse it
        @return a list containing all the *uncommented* lines of config file
        """
        f = open(self._file, "r")
        lines = f.readlines()
        f.close()
        result = []
        for line in lines:
            if not line.startswith("#") and line.strip() != "":
                result.append(line.strip())
        return result

    def write(self, data):
        """
        Write config datas in the config file
        @param data : list of config lines
        @Warning : it will erease the previous config file
        @raise IOError if the file can'"t be opened
        """
        f = open(self._file, "w")
        for section in self.ITEMS_SECTION:
            f.write("##### %s #####\n\n" % section)
            for item in self.ITEMS_SECTION[section]:
                for d in data:
                    if d.startswith("%s " % item) or d.startswith(
                            "%s\t" % item):
                        f.write("%s\n" % d)
            f.write("\n")
        f.close()

    def restart(self):
        """
        Restart heyu process, needed to reload config
        @return the output of heyu restart command on stderr,
        should be empty if everything goes well
        """
        return ""
Ejemplo n.º 13
0
 def clear_data(self):
     """ Clear the message data.
     """
     self.data = OrderedDict()
Ejemplo n.º 14
0
class XplMessage(object):
    """ xPL Message facility.

    XplMessage is the object for data send/received on the network.
    """
    __regexp_type = re.compile(REGEXP_TYPE, re.UNICODE | re.VERBOSE)
    __regexp_hop_count = re.compile(REGEXP_HOP_COUNT, re.UNICODE | re.VERBOSE)
    __regexp_source = re.compile(REGEXP_SOURCE, re.UNICODE | re.VERBOSE)
    __regexp_target = re.compile(REGEXP_TARGET, re.UNICODE | re.VERBOSE)
    __regexp_schema = re.compile(REGEXP_SCHEMA, re.UNICODE | re.VERBOSE)
    __regexp_data = re.compile(REGEXP_DATA, re.UNICODE | re.VERBOSE)
    __regexp_single_data = re.compile(REGEXP_SINGLE_DATA,
                                      re.UNICODE | re.VERBOSE)
    __regexp_global = re.compile(REGEXP_GLOBAL,
                                 re.DOTALL | re.UNICODE | re.VERBOSE)

    def __init__(self, packet=None):
        """ Message object.

        Create Message instance from a message string and check if the
        structure is correct. Raise exception if it is not
        The message can be None (to allow building a message)

        @param packet : message packet, as sent on the network
        @type packet: str
        """
        super(XplMessage, self).__init__()
        self.type = ""
        self.hop_count = 1
        self.source = ""
        self.source_vendor_id = ""
        self.source_device_id = ""
        self.source_instance_id = ""
        self.target = ""
        self.target_vendor_id = ""
        self.target_device_id = ""
        self.target_instance_id = ""
        self.schema = ""
        self.schema_class = ""
        self.schema_type = ""
        self.data = OrderedDict()
        if packet is not None:
            self.from_packet(packet)

    def __str__(self):
        return self.to_packet()

    def __parse_data(self, data):
        """ Parse message data.

        The data are added to existing ones.

        @param data: message data, as "<name1>=>value1>\n<name2>=<value2>\n..."
        @type data: str

        @raise XplMessageError: invalid data

        @todo: use OrderedDict for data storage
        """
        match_data = XplMessage.__regexp_data.match(data)
        if match_data is None:
            raise XplMessageError("Invalid data")
        match_data_dict = match_data.groupdict()
        data_list = match_data_dict['data'].split('\n')
        for data_ in data_list:
            if data_:
                self.__parse_single_data(data_)

    def __parse_single_data(self, data):
        """ Parse single message data.

        The data are added to existing ones.

        @param data: single message data, as "<name>=<value>"
        @type data: str

        @raise XplMessageError: invalid data
        """
        match_single_data = XplMessage.__regexp_single_data.match(data)
        if match_single_data is None:
            raise XplMessageError("Invalid data (%s)" % data)
        match_single_data_dict = match_single_data.groupdict()
        #self.data.append((match_single_data_dict['data_name'], match_single_data_dict['data_value']))
        key = match_single_data_dict['data_name']
        if key in self.data:
            if type(self.data[key]) != list:
                v = self.data[key]
                self.data[key] = [v]
            self.data[key].append(match_single_data_dict['data_value'])
        else:
            self.data[key] = match_single_data_dict['data_value']

    def set_type(self, type_):
        """ Set the message type.

        @param type_: message type, in ('xpl-stat', 'xpl-trig', 'xpl-cmnd')
        @type type_: str

        @raise XplMessageError: invalid type
        """
        match_type = XplMessage.__regexp_type.match(type_)
        if match_type is None:
            raise XplMessageError("Invalid type (%s)" % type_)
        self.type = type_

    def set_hop_count(self, hop_count):
        """ Set hop count value.

        @param hop_count: hop count
        @type hop_count: int or str

        @raise XplMessageError: invalid hop count value
        """
        match_hop_count = XplMessage.__regexp_hop_count.match(str(hop_count))
        if match_hop_count is None:
            raise XplMessageError("Invalid hop count value (%d)" %
                                  int(hop_count))
        self.hop_count = int(hop_count)

    def inc_hop_count(self):
        """ Increment hop count value.

        @raise XplMessageError: exceeded hop count value
        """
        hop_count = self.hop_count + 1
        match_hop_count = XplMessage.__regexp_hop_count.match(str(hop_count))
        if match_hop_count is None:
            raise XplMessageError("Exceeded hop count value (%s)" %
                                  str(hop_count))
        self.hop_count = hop_count

    def set_source(self, source):
        """ Set source.

        @param source: message source
        @type source: str

        @raise XplMessageError: invalid source
        """
        match_source = XplMessage.__regexp_source.match(source)
        if match_source is None:
            raise XplMessageError("Invalid source (%s)" % source)
        match_source_dict = match_source.groupdict()
        for key, value in match_source_dict.iteritems():
            setattr(self, key, value)

    def set_target(self, target):
        """ Set target.

        @param target: message target
        @type targer: str

        @raise XplMessageError: invalid target
        """
        match_target = XplMessage.__regexp_target.match(target)
        if match_target is None:
            raise XplMessageError("Invalid target (%s)" % target)
        match_target_dict = match_target.groupdict()
        for key, value in match_target_dict.iteritems():
            setattr(self, key, value)

    def set_header(self, hop_count=None, source=None, target=None):
        """ Set the message header.

        @param hop_count: hop count
        @type hop_count: int

        @param source: message source
        @type source: str

        @param target: message target
        @type targer: str
        """
        if hop_count is not None:
            self.set_hop_count(hop_count)
        if source is not None:
            self.set_source(source)
        if target is not None:
            self.set_target(target)

    def set_schema(self, schema):
        """ Set message schema.

        @param schema: message schema
        @type schema: str

        @raise XplMessageError: invalid schema
        """
        match_schema = XplMessage.__regexp_schema.match(schema)
        if match_schema is None:
            raise XplMessageError("Invalid schema (%s)" % schema)
        match_schema_dict = match_schema.groupdict()
        for key, value in match_schema_dict.iteritems():
            setattr(self, key, value)

    def add_single_data(self, name, value):
        """ Add a single message data.

        @param name: data name
        @type name: str

        @param value: data value
        @type value: any
        """
        data_str = "%s=%s" % (name, value)
        self.__parse_single_data(data_str)

    def add_data(self, data):
        """ Add message data to the existing ones.

        First build data as str, to be parsed by the regexp.

        @param data: message data, as name/value pairs
        @type data: dict or L{OrderedDict}
        """
        for name, value in data.iteritems():
            self.add_single_data(name, value)

    def set_data(self, data):
        """ Set message data, replacing previous ones. ???

        First build data as str, to be parsed by the regexp.

        @param data: message data, as name/value pairs
        @type data: dict or L{OrderedDict}
        """
        data_backup = copy.deepcopy(self.data)
        try:
            self.data = OrderedDict()
            self.add_data(data)
        except XplMessageError:
            self.data = copy.deepcopy(data_backup)
            raise

    def clear_data(self):
        """ Clear the message data.
        """
        self.data = OrderedDict()

    def from_packet(self, packet):
        """ Decode message from given packet.

        @param packet: message packet, as sent on the network
        @type packet: str

        @raise XplMessageError: the message packet is incorrect

        @raise XplMessageError: invalid message packet
        """
        match_global = XplMessage.__regexp_global.match(packet)
        if match_global is None:
            raise XplMessageError("Invalid message packet")
        else:
            match_global_dict = match_global.groupdict()
            self.set_type(match_global_dict['type_'])
            self.set_hop_count(match_global_dict['hop_count'])
            self.set_source(match_global_dict['source'])
            self.set_target(match_global_dict['target'])
            self.set_schema(match_global_dict['schema'])
            self.data = OrderedDict()
            data = match_global_dict[
                'data'] + '\n'  # The global match remove the last '\n'
            self.__parse_data(data)

    def to_packet(self):
        """ Convert the message to packet.

        @return: message packet, as sent on the network
        @rtype: str
        """
        packet = "%s\n" % self.type
        packet += "{\n"
        packet += "hop=%d\n" % self.hop_count
        packet += "source=%s\n" % self.source
        packet += "target=%s\n" % self.target
        packet += "}\n"
        packet += "%s\n" % self.schema
        packet += "{\n"
        for key, value in self.data.iteritems():
            if type(value) == list:
                for v in value:
                    packet += "%s=%s\n" % (key, v)
            else:
                packet += "%s=%s\n" % (key, value)
        packet += "}\n"

        return packet

    def is_valid(self):
        """ Check if the message is valid.

        @return: True if message is valid, False otherwise
        @rtype: bool
        """
        try:
            self.from_packet(self.to_packet())
        except XplMessageError:
            return False
        else:
            return True