summaryrefslogtreecommitdiff
path: root/heat/common/serializers.py
blob: 3125ba98ba5051ab3ae1c32f6a2de0e2aa28b1be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# Copyright 2013 IBM Corp.
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

"""Utility methods for serializing responses."""

import datetime

from lxml import etree
from oslo_log import log as logging
from oslo_serialization import jsonutils
import six

LOG = logging.getLogger(__name__)


class JSONResponseSerializer(object):

    def to_json(self, data):
        def sanitizer(obj):
            if isinstance(obj, datetime.datetime):
                return obj.isoformat()
            return six.text_type(obj)

        response = jsonutils.dumps(data, default=sanitizer)

        # TODO(ricolin): Fix response through private credential information,
        # before enable below debug message.
        # LOG.debug("JSON response : %s" % response)

        return response

    def default(self, response, result):
        response.content_type = 'application/json'
        response.body = six.b(self.to_json(result))


# Escape XML serialization for these keys, as the AWS API defines them as
# JSON inside XML when the response format is XML.
JSON_ONLY_KEYS = ('TemplateBody', 'Metadata')


class XMLResponseSerializer(object):

    def object_to_element(self, obj, element):
        if isinstance(obj, list):
            for item in obj:
                subelement = etree.SubElement(element, "member")
                self.object_to_element(item, subelement)
        elif isinstance(obj, dict):
            for key, value in obj.items():
                subelement = etree.SubElement(element, key)
                if key in JSON_ONLY_KEYS:
                    if value:
                        # Need to use json.dumps for the JSON inside XML
                        # otherwise quotes get mangled and json.loads breaks
                        try:
                            subelement.text = jsonutils.dumps(value)
                        except TypeError:
                            subelement.text = str(value)
                else:
                    self.object_to_element(value, subelement)
        else:
            element.text = six.text_type(obj)

    def to_xml(self, data):
        # Assumption : root node is dict with single key
        root = next(six.iterkeys(data))
        eltree = etree.Element(root)
        self.object_to_element(data.get(root), eltree)
        response = etree.tostring(eltree)
        return response

    def default(self, response, result):
        response.content_type = 'application/xml'
        response.body = self.to_xml(result)