Beispiel #1
0
    def _decode_resource_data(self, resource_element):
        """Decode a resource element.

        Args:
            resource_element (dict): an json element that represent a
                resource.

        Returns:
            BaseResource. decoded resource.
        """
        type_element = resource_element[TYPE_NAME]
        type_name = self.recursive_decode(type_element)
        resource_type = extract_type(type_name)

        properties_element = resource_element[PROPERTIES]
        resource_properties = self.recursive_decode(properties_element)

        # Get the related fields.
        list_field_names = [
            key for key, value in iteritems(resource_properties)
            if isinstance(value, list)
        ]

        list_fields = [(field_name, resource_properties.pop(field_name))
                       for field_name in list_field_names]

        resource = resource_type(**resource_properties)
        for field in resource._meta.fields:
            if isinstance(field, ForeignKey):
                if hasattr(resource, field.name):
                    field_value = getattr(resource, field.name)
                    if field_value:
                        setattr(resource, "{}_id".format(field.name),
                                field_value.id)

        for field_name, field_values in list_fields:
            # Set the related fields' values.
            field_object, _, is_direct, is_many_to_many = \
                resource_type._meta.get_field_by_name(field_name)

            if is_direct:
                raise ParsingError("Got unsupported direct list field %r" %
                                   field_name)

            if is_many_to_many:
                raise ParsingError("Got unsupported many to many field %r" %
                                   field_name)

            for related_object in field_values:
                # Set the related model's pointer to the current model.
                setattr(related_object, field_object.field.name, resource)

        return resource
Beispiel #2
0
    def _decode_message(self, data):
        """Decode a message from an XML string.

        Args:
            data (str): data to decode. data is an XML string that represent an
                'AbstractMessage' object.

        Returns:
            AbstractMessage. decoded message.

        Raises:
            ParsingError: scheme validation failed.
            AttributeError: message tag name is not a valid message class name.
                the scheme should validate that this case will never happen.
        """
        root = objectify.XML(data)

        if not self.scheme.validate(root):
            scheme_errors = self.scheme.error_log.filter_from_errors()
            raise ParsingError("Scheme validation failed. reason: %r" %
                               scheme_errors)

        message_class = getattr(messages, root.tag)
        kwargs = dict([(element.tag, self._decode(element))
                       for element in root.getchildren()])

        return message_class(**kwargs)
Beispiel #3
0
    def _decode_resource_data(self, resource_element):
        """Decode a resource element.

        Args:
            resource_element (ElementTree): an XML element that represent a
                resource.

        Returns:
            BaseResource. decoded resource.
        """
        type_element = getattr(resource_element, TYPE_NAME)
        type_name = self._decode(type_element)
        resource_type = extract_type(type_name)

        properties_element = getattr(resource_element, PROPERTIES)
        resource_properties = self._decode(properties_element)

        # Get the related fields.
        list_field_names = [
            key for key, value in resource_properties.items()
            if isinstance(value, list)
        ]

        list_fields = [(field_name, resource_properties.pop(field_name))
                       for field_name in list_field_names]

        resource = resource_type(**resource_properties)

        for field_name, field_values in list_fields:
            # Set the related fields' values.
            field_object, _, is_direct, is_many_to_many = \
                resource_type._meta.get_field_by_name(field_name)

            if is_direct:
                raise ParsingError("Got unsupported direct list field %r" %
                                   field_name)

            if is_many_to_many:
                raise ParsingError("Got unsupported many to many field %r" %
                                   field_name)

            for related_object in field_values:
                # Set the related model's pointer to the current model.
                setattr(related_object, field_object.field.name, resource)

        return resource
Beispiel #4
0
    def _decode(self, element):
        """Decode an XML element according to its inner type.

        Args:
            element (ElementTree): an XML element.

        Returns:
            object. decoded object.

        Raises:
            ParsingError: failed to decode the element.
        """
        sub_elements = element.getchildren()

        # If it has no children it is a basic type
        if len(sub_elements) == 0:
            value = element.pyval

            if value == self._NONE_TYPE:
                return None

            # Strings are encoded with "" surrounding them, therefore when
            # decoding a string the "" are removed.
            if isinstance(value, basestring):
                return value[1:-1]

            if isinstance(value, (bool, Number)):
                return value

        # The XML parser's scheme allows only 1 child under each element
        # (unless it is dictionary, list or resource).
        sub_element = sub_elements[0]

        try:
            decoder = self.complex_decoders[sub_element.tag]
            return decoder(sub_element)

        except Exception as exception:
            raise ParsingError("Failed to decode element %r. Reason: %s" %
                               (element, exception))
Beispiel #5
0
    def _encode_dict(self, dict_data):
        """Encode a dictionary to an json string.

        Args:
            dict_data (dict): dictionary to encode.

        Returns:
            dict. json element represent a dictionary.

        Raises:
            ParsingError: one of the keys is not of type str.
        """
        dict_return = {}

        for key, value in iteritems(dict_data):
            if not isinstance(key, string_types):
                raise ParsingError("Failed to encode dictionary, "
                                   "key %r is not a string" % key)

            dict_return[key] = self.recursive_encode(value)

        return {self._DICT_TYPE: dict_return}
Beispiel #6
0
    def _encode_dict(self, dict_data):
        """Encode a dictionary to an XML string.

        Args:
            dict_data (dict): dictionary to encode.

        Returns:
            ElementTree. XML element represent a dictionary.

        Raises:
            ParsingError: one of the keys is not of type str.
        """
        dict_element = builder.E(self._DICT_TYPE)

        for key, value in dict_data.iteritems():
            if not isinstance(key, basestring):
                raise ParsingError("Failed to encode dictionary, "
                                   "key %r is not a string" % key)

            element = builder.E(key, self._encode(value))
            dict_element.append(element)

        return dict_element
Beispiel #7
0
    def _request(self, request_msg, timeout=_DEFAULT_REPLY_TIMEOUT):
        """Send a message to manager server and wait for an answer.

        * Encodes the request message and sends it to manager server.
        * Waits for manager server reply message.

        Args:
            request_msg (AbstractMessage): request for manager server.
            timeout (number): the request's waiting timeout.

        Returns:
            AbstractMessage. Server reply for given request.

        Raises:
            TypeError: client received an illegal reply message.
            ParsingError: client failed to decode server's reply.
            ParsingError: server failed to decode client's request.
            RuntimeError: server reply on a different request.
            RuntimeError: server didn't respond, timeout expired.
            ServerError: server failed to execute the request.
        """
        self._set_reply_timeout(timeout)

        request_msg.msg_id = self._messages_counter.next()
        encoded_request = self._parser.encode(request_msg) + MESSAGE_DELIMITER
        sent_bytes = 0

        if len(encoded_request) > MESSAGE_MAX_LENGTH:
            raise RuntimeError("Client error: Trying to send a too long "
                               "message to the server (%d > %d)" %
                               (len(encoded_request), MESSAGE_MAX_LENGTH))

        while sent_bytes < len(encoded_request):
            sent_bytes += self._socket.send(encoded_request[sent_bytes:])

        encoded_reply = ""

        try:
            while not encoded_reply.endswith(MESSAGE_DELIMITER):
                encoded_reply += self._socket.recv(MESSAGE_MAX_LENGTH)

            reply_msg = self._parser.decode(encoded_reply)

        except socket.timeout:
            raise RuntimeError("Server failed to respond to %r after %r "
                               "seconds" %
                               (request_msg, self._socket.gettimeout()))

        if isinstance(reply_msg, messages.ParsingFailure):
            raise ParsingError("Server failed to parse a message, assumed ID "
                               "%r. Failure Reason is: %r." %
                               (request_msg.msg_id, reply_msg.reason))

        if not isinstance(reply_msg, messages.AbstractReply):
            raise TypeError(
                "Server sent an illegal message. Replies should "
                "be of type AbstractReply. Received message is: %r" %
                reply_msg)

        if reply_msg.request_id != request_msg.msg_id:
            raise RuntimeError("Client expect for reply on message with id %r,"
                               " but got a reply on message with id %r" %
                               (request_msg.msg_id, reply_msg.request_id))

        if isinstance(reply_msg, messages.ErrorReply):
            raise ErrorFactory.build_error(reply_msg.code, reply_msg.content)

        return reply_msg