1# This program is free software; you can redistribute it and/or modify
2# it under the terms of the (LGPL) GNU Lesser General Public License as
3# published by the Free Software Foundation; either version 3 of the
4# License, or (at your option) any later version.
5#
6# This program is distributed in the hope that it will be useful,
7# but WITHOUT ANY WARRANTY; without even the implied warranty of
8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9# GNU Library Lesser General Public License for more details at
10# ( http://www.gnu.org/licenses/lgpl.html ).
11#
12# You should have received a copy of the GNU Lesser General Public License
13# along with this program; if not, write to the Free Software
14# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15# written by: Jeff Ortel ( jortel@redhat.com )
16
17"""
18Provides encoded I{marshaller} classes.
19"""
20
21from suds import *
22from suds.mx import *
23from suds.mx.literal import Literal
24from suds.mx.typer import Typer
25from suds.sudsobject import Factory, Object
26from suds.xsd.query import TypeQuery
27
28
29#
30# Add encoded extensions
31# aty = The soap (section 5) encoded array type.
32#
33Content.extensions.append('aty')
34
35
36class Encoded(Literal):
37    """
38    A SOAP section (5) encoding marshaller.
39    This marshaller supports rpc/encoded soap styles.
40    """
41
42    def start(self, content):
43        #
44        # For soap encoded arrays, the 'aty' (array type) information
45        # is extracted and added to the 'content'.  Then, the content.value
46        # is replaced with an object containing an 'item=[]' attribute
47        # containing values that are 'typed' suds objects.
48        #
49        start = Literal.start(self, content)
50        if start and isinstance(content.value, (list,tuple)):
51            resolved = content.type.resolve()
52            for c in resolved:
53                if hasattr(c[0], 'aty'):
54                    content.aty = (content.tag, c[0].aty)
55                    self.cast(content)
56                    break
57        return start
58
59    def end(self, parent, content):
60        #
61        # For soap encoded arrays, the soapenc:arrayType attribute is
62        # added with proper type and size information.
63        # Eg: soapenc:arrayType="xs:int[3]"
64        #
65        Literal.end(self, parent, content)
66        if content.aty is None:
67            return
68        tag, aty = content.aty
69        ns0 = ('at0', aty[1])
70        ns1 = ('at1', 'http://schemas.xmlsoap.org/soap/encoding/')
71        array = content.value.item
72        child = parent.getChild(tag)
73        child.addPrefix(ns0[0], ns0[1])
74        child.addPrefix(ns1[0], ns1[1])
75        name = '%s:arrayType' % ns1[0]
76        value = '%s:%s[%d]' % (ns0[0], aty[0], len(array))
77        child.set(name, value)
78
79    def encode(self, node, content):
80        if content.type.any():
81            Typer.auto(node, content.value)
82            return
83        if content.real.any():
84            Typer.auto(node, content.value)
85            return
86        ns = None
87        name = content.real.name
88        if self.xstq:
89            ns = content.real.namespace()
90        Typer.manual(node, name, ns)
91
92    def cast(self, content):
93        """
94        Cast the I{untyped} list items found in content I{value}.
95        Each items contained in the list is checked for XSD type information.
96        Items (values) that are I{untyped}, are replaced with suds objects and
97        type I{metadata} is added.
98        @param content: The content holding the collection.
99        @type content: L{Content}
100        @return: self
101        @rtype: L{Encoded}
102        """
103        aty = content.aty[1]
104        resolved = content.type.resolve()
105        array = Factory.object(resolved.name)
106        array.item = []
107        query = TypeQuery(aty)
108        ref = query.execute(self.schema)
109        if ref is None:
110            raise TypeNotFound(qref)
111        for x in content.value:
112            if isinstance(x, (list, tuple)):
113                array.item.append(x)
114                continue
115            if isinstance(x, Object):
116                md = x.__metadata__
117                md.sxtype = ref
118                array.item.append(x)
119                continue
120            if isinstance(x, dict):
121                x = Factory.object(ref.name, x)
122                md = x.__metadata__
123                md.sxtype = ref
124                array.item.append(x)
125                continue
126            x = Factory.property(ref.name, x)
127            md = x.__metadata__
128            md.sxtype = ref
129            array.item.append(x)
130        content.value = array
131        return self
132