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

root/tags/RELEASE_1_0_0/lib/SOAPElement.rb

Revision 2, 10.7 kB (checked in by nakahiro, 8 years ago)

SOAP4R initial release.

  • 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, @namespace, 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, @namespace, param )
73         }
74         retElem = Element.new( 'return', nil, children )
75       else
76         retElem = retVal.encode( ns.clone, nil, '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 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   module_function :decode
134 end
135
136
137 class SOAPFault < SOAPCompoundBase
138   public
139
140   attr_reader :faultCode
141   attr_reader :faultString
142   attr_reader :faultActor
143   attr_reader :detail
144   attr_reader :options
145
146   def initialize( faultCode, faultString, faultActor, detail = nil, options = [] )
147     super( self.type.to_s )
148     @faultCode = faultCode
149     @faultString = faultString
150     @faultActor = faultActor
151     @detail = detail
152     @options = options
153   end
154
155   def encode( ns )
156     # Caution: never been executed!!
157     faultElems = [ @faultCode.encode( ns, EnvelopeNamespace, 'faultcode' ),
158       @faultString.encode( ns, EnvelopeNamespace, 'faultstring' ),
159       @faultActor.encode( ns, EnvelopeNamespace, 'faultactor' ) ]
160     faultElems.push( @detail.encode( ns, EnvelopeNamespace, 'detail' )) if @detail
161     @options.each do | opt |
162       paramElem.push( opt.encode( ns ))
163     end
164     Element.new( ns.name( EnvelopeNamespace, 'Fault' ), nil, faultElems )
165   end
166
167   # Module function
168
169   public
170
171   def decode( ns, elem )
172     faultCode = nil
173     faultString = nil
174     faultActor = nil
175     detail = nil
176     options = []
177     elem.childNodes.each do | child |
178       next if ( isEmptyText( child ))
179       childNS = ns.clone
180       parseNS( childNS, child )
181
182       if ( childNS.compare( EnvelopeNamespace, 'faultcode', child.nodeName ))
183         raise FormatDecodeError.new( 'Duplicated faultcode in Fault' ) if faultCode
184         faultCode = SOAPInteger.decode( childNS, child )
185
186       elsif ( childNS.compare( EnvelopeNamespace, 'faultstring', child.nodeName ))
187         raise FormatDecodeError.new( 'Duplicated faultstring in Fault' ) if faultString
188         faultString = SOAPString.decode( childNS, child )
189
190       elsif ( childNS.compare( EnvelopeNamespace, 'faultactor', child.nodeName ))
191         raise FormatDecodeError.new( 'Duplicated faultactor in Fault' ) if faultActor
192         faultActor = SOAPString.decode( childNS, child )
193
194       elsif ( childNS.compare( EnvelopeNamespace, 'detail', child.nodeName ))
195         raise FormatDecodeError.new( 'Duplicated detail in Fault' ) if detail
196         detail = decodeChild( childNS, child )
197
198       else
199         options.push( decodeChild( childNS, child ))
200       end
201     end
202
203     SOAPFault.new( faultCode, faultString, faultActor, detail, options )
204   end
205   module_function :decode
206 end
207
208
209 class SOAPBody < SOAPCompoundBase
210   public
211
212   attr_reader :data
213   attr_reader :isFault
214
215   def initialize( data, isFault = false )
216     super( self.type.to_s )
217     @data = data
218     @isFault = isFault
219   end
220
221   def encode( ns, forResponse = false )
222     attrs = []
223     contents = nil
224     if @isFault
225       contents = @data.encode( ns )
226     else
227       attrs.push( Attr.new( ns.name( EnvelopeNamespace, AttrEncodingStyle ), EncodingNamespace ))
228       contents = @data.encode( ns, forResponse )
229     end
230
231     Element.new( ns.name( EnvelopeNamespace, 'Body' ), attrs, contents )
232   end
233
234   # Module function
235
236   public
237
238   def decode( ns, elem, method )
239     data = nil
240     isFault = false
241     result = []
242
243     elem.childNodes.each do | child |
244       childNS = ns.clone
245       parseNS( childNS, child )
246       if ( isEmptyText( child ))
247         # Nothing to do.
248       elsif ( childNS.compare( EnvelopeNamespace, 'Fault', child.nodeName ))
249         data = SOAPFault.decode( childNS, child )
250         isFault = true
251       elsif !data
252         data = SOAPMethod.decode( childNS, child )
253       else
254         # ToDo: May be a pointer...
255         result.push( child )
256         raise FormatDecodeError.new( 'Unknown node name: ' << child.nodeName )
257       end
258     end
259
260     # ToDo: Must resolve pointers in result...
261
262     SOAPBody.new( data, isFault )
263   end
264   module_function :decode
265 end
266
267
268 class SOAPHeaderItem < SOAPCompoundBase
269   public
270
271   attr_reader :namespace
272   attr_reader :name
273   attr_accessor :content
274   attr_accessor :mustUnderstand
275   attr_accessor :encodingStyle
276
277   def initialize( namespace, name, content, mustUnderstand = false, encodingStyle = nil )
278     super( self.type.to_s )
279     @namespace = namespace
280     @name = name
281     @content = content
282     @mustUnderstand = mustUnderstand
283     @encodingStyle = encodingStyle
284   end
285
286   def encode( ns )
287     return nil if @name.empty?
288     attrs = []
289     attrs.push( Attr.new( ns.name( EnvelopeNamespace, AttrMustUnderstand ), ( @mustUnderstand ? '1' : '0' )))
290     attrs.push( Attr.new( ns.name( EnvelopeNamespace, AttrEncodingStyle ), @encodingStyle )) if @encodingStyle
291     Element.new( ns.name( @namespace, @name ), attrs, @content )
292   end
293
294   # Module function
295
296   public
297
298   def decode( ns, elem )
299     mustUnderstand = nil
300     encodingStyle = nil
301     elem.attributes.each do | attr |
302       name = attr.nodeName
303       if ( ns.compare( EnvelopeNamespace, AttrMustUnderstand, name ))
304         raise FormatDecodeError.new( 'Duplicated mustUnderstand in HeaderItem' ) if mustUnderstand
305         mustUnderstand = attr.nodeValue
306       elsif ( ns.compare( EnvelopeNamespace, AttrEncodingStyle, name ))
307         raise FormatDecodeError.new( 'Duplicated encodingStyle in HeaderItem' ) if encodingStyle
308         encodingStyle = attr.nodeValue
309       else
310         raise FormatDecodeError.new( 'Unknown attribute: ' << name )
311       end
312     end
313     elemNamespace, elemName = ns.parse( elem.nodeName )
314
315     # Convert NodeList to simple Array.
316     childArray = []
317     elem.childNodes.each do | child |
318       childArray.push( child )
319     end
320
321     SOAPHeaderItem.new( elemNamespace, elemName, childArray, mustUnderstand, encodingStyle )
322   end
323   module_function :decode
324 end
325
326
327 class SOAPHeader < SOAPArray
328   public
329
330   def initialize()
331     super( self.type.to_s )
332   end
333
334   def encode( ns )
335     children = @data.collect { | child |
336       child.encode( ns.clone )
337     }
338     Element.new( ns.name( EnvelopeNamespace, 'Header' ), nil, children )
339   end
340
341   # Module function
342
343   public
344
345   def decode( ns, elem )
346     s = SOAPHeader.new()
347     elem.childNodes.each do | child |
348       childNS = ns.clone
349       parseNS( childNS, child )
350       next if ( isEmptyText( child ))
351       s.add( SOAPHeaderItem.decode( childNS, child ))
352     end
353     s
354   end
355   module_function :decode
356 end
357
358
359 class SOAPEnvelope < SOAPCompoundBase
360   public
361
362   attr_reader :header
363   attr_reader :body
364
365   def initialize( initHeader, initBody )
366     super( self.type.to_s )
367     @header = initHeader
368     @body = initBody
369   end
370
371   def encode( ns )
372     # Namespace preloading.
373     attrs = ns.namespaceTag.collect { | namespace, tag |
374       if ( tag == '' )
375         Attr.new( 'xmlns' , namespace )
376       else
377         Attr.new( 'xmlns:' << tag, namespace )
378       end
379     }
380
381 #    attrs.push( Attr.new( ns.name( EnvelopeNamespace, AttrEncodingStyle ), EncodingNamespace ))
382
383     contents = []
384     contents.push( @header.encode( ns )) if @header and @header.length > 0
385     contents.push( @body.encode( ns ))
386
387     Element.new( ns.name( EnvelopeNamespace, 'Envelope' ), attrs, contents )
388   end
389
390   # Module function
391
392   public
393
394   def decode( ns, doc, method )
395     if ( doc.childNodes.size != 1 )
396       raise FormatDecodeError.new( 'Envelope must be a child.' )
397     end
398
399     elem = doc.childNodes[ 0 ]
400     parseNS( ns, elem )
401
402     if ( !ns.compare( EnvelopeNamespace, 'Envelope', elem.nodeName ))
403       raise FormatDecodeError.new( 'Envelope not found.' )
404     end
405
406     header = nil
407     body = nil
408     elem.childNodes.each do | child |
409       childNS = ns.clone
410       parseNS( childNS, child )
411       name = child.nodeName
412       if ( isEmptyText( child ))
413         # Nothing to do.
414       elsif ( childNS.compare( EnvelopeNamespace, 'Header', name ))
415         raise FormatDecodeError.new( 'Duplicated Header in Envelope' ) if header
416         header = SOAPHeader.decode( childNS, child )
417       elsif ( childNS.compare( EnvelopeNamespace, 'Body', name ))
418         raise FormatDecodeError.new( 'Duplicated Body in Envelope' ) if body
419         body = SOAPBody.decode( childNS, child, method )
420       else
421         raise FormatDecodeError.new( 'Unknown scoping element: ' << name )
422       end
423     end
424
425     SOAPEnvelope.new( header, body )
426   end
427   module_function :decode
428 end
Note: See TracBrowser for help on using the browser.