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
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