Welcome to the "trac"-ing site of soap4r!
[soap4r] [httpclient] [openpgp4u] [pkcs1] [logger] [csv] [vtr]

root/tags/RELEASE_1_0_1/lib/SOAPElement.rb

Revision 5, 10.5 kB (checked in by nakahiro, 8 years ago)

Use 'def self.foo' instead of 'module_function'.
Removed parameter 'namespace' from 'encode'. Misunderstanding of namespace

specification...

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to author date id revision
Line 
1 =begin
2 SOAP4R
3 Copyright (C) 2000 NAKAMURA Hiroshi.
4
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; either version 2 of the License, or (at your option) any later
8 version.
9
10 This program is distributed in the hope that it will be useful, but WITHOUT ANY
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
12 PRATICULAR PURPOSE. See the GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc., 675 Mass
16 Ave, Cambridge, MA 02139, USA.
17 =end
18
19 require 'SOAPData'
20 require 'xmltreebuilder'
21
22
23 ###
24 ## SOAP elements
25 #
26 class SOAPMethod < SOAPCompoundBase
27   public
28
29   attr_reader :namespace
30   attr_reader :name
31   attr_reader :paramDef
32
33   attr_accessor :paramNames
34   attr_reader :paramTypes
35   attr_reader :params
36
37   attr_reader :retName
38   attr_accessor :retVal
39
40   def initialize( namespace, name, paramDef = nil )
41     super( self.type.to_s )
42
43     @namespace = namespace
44     @name = name
45     @paramDef = paramDef
46
47     @paramNames = []
48     @paramTypes = {}
49     @params = {}
50     @retName = nil
51     @retVal = nil
52
53     setParamDef() if @paramDef
54   end
55
56   def setParams( params )
57     params.each do | param, data |
58       @params[ param ] = data
59     end
60   end
61
62   def encode( ns, forResponse = false )
63     if !forResponse
64       paramElem = @paramNames.collect { | param |
65         @params[ param ].encode( ns.clone, param )
66       }
67       Element.new( ns.name( @namespace, @name ), nil, paramElem )
68     else
69       retElem = nil
70       if retVal.is_a?( SOAPStruct )
71         children = retVal.collect { | param, data |
72           data.encode( ns.clone, param )
73         }
74         retElem = Element.new( 'return', nil, children )
75       else
76         retElem = retVal.encode( ns.clone, 'return' )
77       end
78       Element.new( ns.name( @namespace, @name ), nil, retElem )
79     end
80   end
81
82   private
83
84   def setParamDef()
85     @paramDef.each do | pair |
86       type, name = pair
87       type.scan( /[^,\s]+/ ).each do | typeToken |
88         case typeToken
89         when 'in'
90           @paramNames.push( name )
91           @paramTypes[ name ] = 1
92         when 'out'
93           @paramNames.push( name )
94           @paramTypes[ name ] = 2
95         when 'retval'
96           if ( @retName )
97             raise MethodDefinitionError.new( 'Duplicated retval' )
98           end
99           @retName = name
100         else
101           raise MethodDefinitionError.new( 'Unknown type: ' << typeToken )
102         end
103       end
104     end
105   end
106
107   # Module function
108
109   public
110
111   def self.decode( ns, elem )
112     retVal = nil
113     outParams = {}
114     elem.childNodes.each do | child |
115       next if ( isEmptyText( child ))
116       childNS = ns.clone
117       parseNS( childNS, child )
118       if ( !retVal )
119         retVal = decodeChild( childNS, child )
120       else
121         # ToDo: [in/out] or [out] parameters here...
122         raise NotImplementError.new( '"out" parameters not supported.' )
123       end
124     end
125
126     elemNamespace, elemName = ns.parse( elem.nodeName )
127     m = SOAPMethod.new( elemNamespace, elemName )
128
129     m.retVal = retVal
130     #m.setParams( outParams )
131     m
132   end
133 end
134
135
136 class SOAPFault < SOAPCompoundBase
137   public
138
139   attr_reader :faultCode
140   attr_reader :faultString
141   attr_reader :faultActor
142   attr_reader :detail
143   attr_reader :options
144
145   def initialize( faultCode, faultString, faultActor, detail = nil, options = [] )
146     super( self.type.to_s )
147     @faultCode = faultCode
148     @faultString = faultString
149     @faultActor = faultActor
150     @detail = detail
151     @options = options
152   end
153
154   def encode( ns )
155     # Caution: never been executed!!
156     faultElems = [ @faultCode.encode( ns, 'faultcode' ),
157       @faultString.encode( ns, 'faultstring' ),
158       @faultActor.encode( ns, 'faultactor' ) ]
159     faultElems.push( @detail.encode( ns, 'detail' )) if @detail
160     @options.each do | opt |
161       paramElem.push( opt.encode( ns ))
162     end
163     Element.new( ns.name( EnvelopeNamespace, 'Fault' ), nil, faultElems )
164   end
165
166   # Module function
167
168   public
169
170   def self.decode( ns, elem )
171     faultCode = nil
172     faultString = nil
173     faultActor = nil
174     detail = nil
175     options = []
176     elem.childNodes.each do | child |
177       next if ( isEmptyText( child ))
178       childNS = ns.clone
179       parseNS( childNS, child )
180
181       if ( childNS.compare( EnvelopeNamespace, 'faultcode', child.nodeName ))
182         raise FormatDecodeError.new( 'Duplicated faultcode in Fault' ) if faultCode
183         faultCode = SOAPInteger.decode( childNS, child )
184
185       elsif ( childNS.compare( EnvelopeNamespace, 'faultstring', child.nodeName ))
186         raise FormatDecodeError.new( 'Duplicated faultstring in Fault' ) if faultString
187         faultString = SOAPString.decode( childNS, child )
188
189       elsif ( childNS.compare( EnvelopeNamespace, 'faultactor', child.nodeName ))
190         raise FormatDecodeError.new( 'Duplicated faultactor in Fault' ) if faultActor
191         faultActor = SOAPString.decode( childNS, child )
192
193       elsif ( childNS.compare( EnvelopeNamespace, 'detail', child.nodeName ))
194         raise FormatDecodeError.new( 'Duplicated detail in Fault' ) if detail
195         detail = decodeChild( childNS, child )
196
197       else
198         options.push( decodeChild( childNS, child ))
199       end
200     end
201
202     SOAPFault.new( faultCode, faultString, faultActor, detail, options )
203   end
204 end
205
206
207 class SOAPBody < SOAPCompoundBase
208   public
209
210   attr_reader :data
211   attr_reader :isFault
212
213   def initialize( data, isFault = false )
214     super( self.type.to_s )
215     @data = data
216     @isFault = isFault
217   end
218
219   def encode( ns, forResponse = false )
220     attrs = []
221     contents = nil
222     if @isFault
223       contents = @data.encode( ns )
224     else
225       attrs.push( Attr.new( ns.name( EnvelopeNamespace, AttrEncodingStyle ), EncodingNamespace ))
226       contents = @data.encode( ns, forResponse )
227     end
228
229     Element.new( ns.name( EnvelopeNamespace, 'Body' ), attrs, contents )
230   end
231
232   # Module function
233
234   public
235
236   def self.decode( ns, elem, method )
237     data = nil
238     isFault = false
239     result = []
240
241     elem.childNodes.each do | child |
242       childNS = ns.clone
243       parseNS( childNS, child )
244       if ( isEmptyText( child ))
245         # Nothing to do.
246       elsif ( childNS.compare( EnvelopeNamespace, 'Fault', child.nodeName ))
247         data = SOAPFault.decode( childNS, child )
248         isFault = true
249       elsif !data
250         data = SOAPMethod.decode( childNS, child )
251       else
252         # ToDo: May be a pointer...
253         result.push( child )
254         raise FormatDecodeError.new( 'Unknown node name: ' << child.nodeName )
255       end
256     end
257
258     # ToDo: Must resolve pointers in result...
259
260     SOAPBody.new( data, isFault )
261   end
262 end
263
264
265 class SOAPHeaderItem < SOAPCompoundBase
266   public
267
268   attr_reader :namespace
269   attr_reader :name
270   attr_accessor :content
271   attr_accessor :mustUnderstand
272   attr_accessor :encodingStyle
273
274   def initialize( namespace, name, content, mustUnderstand = false, encodingStyle = nil )
275     super( self.type.to_s )
276     @namespace = namespace
277     @name = name
278     @content = content
279     @mustUnderstand = mustUnderstand
280     @encodingStyle = encodingStyle
281   end
282
283   def encode( ns )
284     return nil if @name.empty?
285     attrs = []
286     attrs.push( Attr.new( ns.name( EnvelopeNamespace, AttrMustUnderstand ), ( @mustUnderstand ? '1' : '0' )))
287     attrs.push( Attr.new( ns.name( EnvelopeNamespace, AttrEncodingStyle ), @encodingStyle )) if @encodingStyle
288     Element.new( ns.name( @namespace, @name ), attrs, @content )
289   end
290
291   # Module function
292
293   public
294
295   def self.decode( ns, elem )
296     mustUnderstand = nil
297     encodingStyle = nil
298     elem.attributes.each do | attr |
299       name = attr.nodeName
300       if ( ns.compare( EnvelopeNamespace, AttrMustUnderstand, name ))
301         raise FormatDecodeError.new( 'Duplicated mustUnderstand in HeaderItem' ) if mustUnderstand
302         mustUnderstand = attr.nodeValue
303       elsif ( ns.compare( EnvelopeNamespace, AttrEncodingStyle, name ))
304         raise FormatDecodeError.new( 'Duplicated encodingStyle in HeaderItem' ) if encodingStyle
305         encodingStyle = attr.nodeValue
306       else
307         raise FormatDecodeError.new( 'Unknown attribute: ' << name )
308       end
309     end
310     elemNamespace, elemName = ns.parse( elem.nodeName )
311
312     # Convert NodeList to simple Array.
313     childArray = []
314     elem.childNodes.each do | child |
315       childArray.push( child )
316     end
317
318     SOAPHeaderItem.new( elemNamespace, elemName, childArray, mustUnderstand, encodingStyle )
319   end
320 end
321
322
323 class SOAPHeader < SOAPArray
324   public
325
326   def initialize()
327     super( self.type.to_s )
328   end
329
330   def encode( ns )
331     children = @data.collect { | child |
332       child.encode( ns.clone )
333     }
334     Element.new( ns.name( EnvelopeNamespace, 'Header' ), nil, children )
335   end
336
337   # Module function
338
339   public
340
341   def self.decode( ns, elem )
342     s = SOAPHeader.new()
343     elem.childNodes.each do | child |
344       childNS = ns.clone
345       parseNS( childNS, child )
346       next if ( isEmptyText( child ))
347       s.add( SOAPHeaderItem.decode( childNS, child ))
348     end
349     s
350   end
351 end
352
353
354 class SOAPEnvelope < SOAPCompoundBase
355   public
356
357   attr_reader :header
358   attr_reader :body
359
360   def initialize( initHeader, initBody )
361     super( self.type.to_s )
362     @header = initHeader
363     @body = initBody
364   end
365
366   def encode( ns )
367     # Namespace preloading.
368     attrs = ns.namespaceTag.collect { | namespace, tag |
369       if ( tag == '' )
370         Attr.new( 'xmlns' , namespace )
371       else
372         Attr.new( 'xmlns:' << tag, namespace )
373       end
374     }
375
376 #    attrs.push( Attr.new( ns.name( EnvelopeNamespace, AttrEncodingStyle ), EncodingNamespace ))
377
378     contents = []
379     contents.push( @header.encode( ns )) if @header and @header.length > 0
380     contents.push( @body.encode( ns ))
381
382     Element.new( ns.name( EnvelopeNamespace, 'Envelope' ), attrs, contents )
383   end
384
385   # Module function
386
387   public
388
389   def self.decode( ns, doc, method )
390     if ( doc.childNodes.size != 1 )
391       raise FormatDecodeError.new( 'Envelope must be a child.' )
392     end
393
394     elem = doc.childNodes[ 0 ]
395     parseNS( ns, elem )
396
397     if ( !ns.compare( EnvelopeNamespace, 'Envelope', elem.nodeName ))
398       raise FormatDecodeError.new( 'Envelope not found.' )
399     end
400
401     header = nil
402     body = nil
403     elem.childNodes.each do | child |
404       childNS = ns.clone
405       parseNS( childNS, child )
406       name = child.nodeName
407       if ( isEmptyText( child ))
408         # Nothing to do.
409       elsif ( childNS.compare( EnvelopeNamespace, 'Header', name ))
410         raise FormatDecodeError.new( 'Duplicated Header in Envelope' ) if header
411         header = SOAPHeader.decode( childNS, child )
412       elsif ( childNS.compare( EnvelopeNamespace, 'Body', name ))
413         raise FormatDecodeError.new( 'Duplicated Body in Envelope' ) if body
414         body = SOAPBody.decode( childNS, child, method )
415       else
416         raise FormatDecodeError.new( 'Unknown scoping element: ' << name )
417       end
418     end
419
420     SOAPEnvelope.new( header, body )
421   end
422 end
Note: See TracBrowser for help on using the browser.