~ubuntu-branches/ubuntu/intrepid/ruby1.8/intrepid-updates

« back to all changes in this revision

Viewing changes to lib/soap/encodingstyle/soapHandler.rb

  • Committer: Bazaar Package Importer
  • Author(s): akira yamada
  • Date: 2007-03-13 22:11:58 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20070313221158-h3oql37brlaf2go2
Tags: 1.8.6-1
* new upstream version, 1.8.6.
* libruby1.8 conflicts with libopenssl-ruby1.8 (< 1.8.6) (closes: #410018)
* changed packaging style to cdbs from dbs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# SOAP4R - SOAP EncodingStyle handler library
 
2
# Copyright (C) 2001, 2003, 2005  NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
 
3
 
 
4
# This program is copyrighted free software by NAKAMURA, Hiroshi.  You can
 
5
# redistribute it and/or modify it under the same terms of Ruby's license;
 
6
# either the dual license version in 2003, or any later version.
 
7
 
 
8
 
 
9
require 'soap/encodingstyle/handler'
 
10
 
 
11
 
 
12
module SOAP
 
13
module EncodingStyle
 
14
 
 
15
 
 
16
class SOAPHandler < Handler
 
17
  Namespace = SOAP::EncodingNamespace
 
18
  add_handler
 
19
 
 
20
  def initialize(charset = nil)
 
21
    super(charset)
 
22
    @refpool = []
 
23
    @idpool = []
 
24
    @textbuf = ''
 
25
    @is_first_top_ele = true
 
26
  end
 
27
 
 
28
 
 
29
  ###
 
30
  ## encode interface.
 
31
  #
 
32
  def encode_data(generator, ns, data, parent)
 
33
    attrs = encode_attrs(generator, ns, data, parent)
 
34
    if parent && parent.is_a?(SOAPArray) && parent.position
 
35
      attrs[ns.name(AttrPositionName)] = "[#{parent.position.join(',')}]"
 
36
    end
 
37
    name = generator.encode_name(ns, data, attrs)
 
38
    case data
 
39
    when SOAPReference
 
40
      attrs['href'] = data.refidstr
 
41
      generator.encode_tag(name, attrs)
 
42
    when SOAPExternalReference
 
43
      data.referred
 
44
      attrs['href'] = data.refidstr
 
45
      generator.encode_tag(name, attrs)
 
46
    when SOAPRawString
 
47
      generator.encode_tag(name, attrs)
 
48
      generator.encode_rawstring(data.to_s)
 
49
    when XSD::XSDString
 
50
      generator.encode_tag(name, attrs)
 
51
      generator.encode_string(@charset ?
 
52
        XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
 
53
    when XSD::XSDAnySimpleType
 
54
      generator.encode_tag(name, attrs)
 
55
      generator.encode_string(data.to_s)
 
56
    when SOAPStruct
 
57
      generator.encode_tag(name, attrs)
 
58
      data.each do |key, value|
 
59
        generator.encode_child(ns, value, data)
 
60
      end
 
61
    when SOAPArray
 
62
      generator.encode_tag(name, attrs)
 
63
      data.traverse do |child, *rank|
 
64
        data.position = data.sparse ? rank : nil
 
65
        generator.encode_child(ns, child, data)
 
66
      end
 
67
    else
 
68
      raise EncodingStyleError.new(
 
69
        "unknown object:#{data} in this encodingStyle")
 
70
    end
 
71
  end
 
72
 
 
73
  def encode_data_end(generator, ns, data, parent)
 
74
    name = generator.encode_name_end(ns, data)
 
75
    cr = data.is_a?(SOAPCompoundtype)
 
76
    generator.encode_tag_end(name, cr)
 
77
  end
 
78
 
 
79
 
 
80
  ###
 
81
  ## decode interface.
 
82
  #
 
83
  class SOAPTemporalObject
 
84
    attr_accessor :parent
 
85
    attr_accessor :position
 
86
    attr_accessor :id
 
87
    attr_accessor :root
 
88
 
 
89
    def initialize
 
90
      @parent = nil
 
91
      @position = nil
 
92
      @id = nil
 
93
      @root = nil
 
94
    end
 
95
  end
 
96
 
 
97
  class SOAPUnknown < SOAPTemporalObject
 
98
    attr_reader :type
 
99
    attr_accessor :definedtype
 
100
    attr_reader :extraattr
 
101
 
 
102
    def initialize(handler, elename, type, extraattr)
 
103
      super()
 
104
      @handler = handler
 
105
      @elename = elename
 
106
      @type = type
 
107
      @extraattr = extraattr
 
108
      @definedtype = nil
 
109
    end
 
110
 
 
111
    def as_struct
 
112
      o = SOAPStruct.decode(@elename, @type)
 
113
      o.id = @id
 
114
      o.root = @root
 
115
      o.parent = @parent
 
116
      o.position = @position
 
117
      o.extraattr.update(@extraattr)
 
118
      @handler.decode_parent(@parent, o)
 
119
      o
 
120
    end
 
121
 
 
122
    def as_string
 
123
      o = SOAPString.decode(@elename)
 
124
      o.id = @id
 
125
      o.root = @root
 
126
      o.parent = @parent
 
127
      o.position = @position
 
128
      o.extraattr.update(@extraattr)
 
129
      @handler.decode_parent(@parent, o)
 
130
      o
 
131
    end
 
132
 
 
133
    def as_nil
 
134
      o = SOAPNil.decode(@elename)
 
135
      o.id = @id
 
136
      o.root = @root
 
137
      o.parent = @parent
 
138
      o.position = @position
 
139
      o.extraattr.update(@extraattr)
 
140
      @handler.decode_parent(@parent, o)
 
141
      o
 
142
    end
 
143
  end
 
144
 
 
145
  def decode_tag(ns, elename, attrs, parent)
 
146
    @textbuf = ''
 
147
    is_nil, type, arytype, root, offset, position, href, id, extraattr =
 
148
      decode_attrs(ns, attrs)
 
149
    o = nil
 
150
    if is_nil
 
151
      o = SOAPNil.decode(elename)
 
152
    elsif href
 
153
      o = SOAPReference.decode(elename, href)
 
154
      @refpool << o
 
155
    elsif @decode_typemap
 
156
      o = decode_tag_by_wsdl(ns, elename, type, parent.node, arytype, extraattr)
 
157
    else
 
158
      o = decode_tag_by_type(ns, elename, type, parent.node, arytype, extraattr)
 
159
    end
 
160
 
 
161
    if o.is_a?(SOAPArray)
 
162
      if offset
 
163
        o.offset = decode_arypos(offset)
 
164
        o.sparse = true
 
165
      else
 
166
        o.sparse = false
 
167
      end
 
168
    end
 
169
 
 
170
    o.parent = parent
 
171
    o.id = id
 
172
    o.root = root
 
173
    o.position = position
 
174
 
 
175
    unless o.is_a?(SOAPTemporalObject)
 
176
      @idpool << o if o.id
 
177
      decode_parent(parent, o)
 
178
    end
 
179
    o
 
180
  end
 
181
 
 
182
  def decode_tag_end(ns, node)
 
183
    o = node.node
 
184
    if o.is_a?(SOAPUnknown)
 
185
      newnode = if /\A\s*\z/ =~ @textbuf
 
186
        o.as_struct
 
187
      else
 
188
        o.as_string
 
189
      end
 
190
      if newnode.id
 
191
        @idpool << newnode
 
192
      end
 
193
      node.replace_node(newnode)
 
194
      o = node.node
 
195
    end
 
196
    decode_textbuf(o)
 
197
    # unlink definedtype
 
198
    o.definedtype = nil
 
199
  end
 
200
 
 
201
  def decode_text(ns, text)
 
202
    @textbuf << text
 
203
  end
 
204
 
 
205
  def decode_prologue
 
206
    @refpool.clear
 
207
    @idpool.clear
 
208
    @is_first_top_ele = true
 
209
  end
 
210
 
 
211
  def decode_epilogue
 
212
    decode_resolve_id
 
213
  end
 
214
 
 
215
  def decode_parent(parent, node)
 
216
    return unless parent.node
 
217
    case parent.node
 
218
    when SOAPUnknown
 
219
      newparent = parent.node.as_struct
 
220
      node.parent = newparent
 
221
      if newparent.id
 
222
        @idpool << newparent
 
223
      end
 
224
      parent.replace_node(newparent)
 
225
      decode_parent(parent, node)
 
226
    when SOAPStruct
 
227
      parent.node.add(node.elename.name, node)
 
228
      node.parent = parent.node
 
229
    when SOAPArray
 
230
      if node.position
 
231
        parent.node[*(decode_arypos(node.position))] = node
 
232
        parent.node.sparse = true
 
233
      else
 
234
        parent.node.add(node)
 
235
      end
 
236
      node.parent = parent.node
 
237
    else
 
238
      raise EncodingStyleError.new("illegal parent: #{parent.node}")
 
239
    end
 
240
  end
 
241
 
 
242
private
 
243
 
 
244
  def content_ranksize(typename)
 
245
    typename.scan(/\[[\d,]*\]$/)[0]
 
246
  end
 
247
 
 
248
  def content_typename(typename)
 
249
    typename.sub(/\[,*\]$/, '')
 
250
  end
 
251
 
 
252
  def create_arytype(ns, data)
 
253
    XSD::QName.new(data.arytype.namespace,
 
254
      content_typename(data.arytype.name) + "[#{data.size.join(',')}]")
 
255
  end
 
256
 
 
257
  def encode_attrs(generator, ns, data, parent)
 
258
    attrs = {}
 
259
    return attrs if data.is_a?(SOAPReference)
 
260
 
 
261
    if !parent || parent.encodingstyle != EncodingNamespace
 
262
      if @generate_explicit_type
 
263
        SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace)
 
264
        attrs[ns.name(AttrEncodingStyleName)] = EncodingNamespace
 
265
      end
 
266
      data.encodingstyle = EncodingNamespace
 
267
    end
 
268
 
 
269
    if data.is_a?(SOAPNil)
 
270
      attrs[ns.name(XSD::AttrNilName)] = XSD::NilValue
 
271
    elsif @generate_explicit_type
 
272
      if data.type.namespace
 
273
        SOAPGenerator.assign_ns(attrs, ns, data.type.namespace)
 
274
      end
 
275
      if data.is_a?(SOAPArray)
 
276
        if data.arytype.namespace
 
277
          SOAPGenerator.assign_ns(attrs, ns, data.arytype.namespace)
 
278
        end
 
279
        SOAPGenerator.assign_ns(attrs, ns, EncodingNamespace)
 
280
        attrs[ns.name(AttrArrayTypeName)] = ns.name(create_arytype(ns, data))
 
281
        if data.type.name
 
282
          attrs[ns.name(XSD::AttrTypeName)] = ns.name(data.type)
 
283
        end
 
284
      elsif parent && parent.is_a?(SOAPArray) && (parent.arytype == data.type)
 
285
        # No need to add.
 
286
      elsif !data.type.namespace
 
287
        # No need to add.
 
288
      else
 
289
        attrs[ns.name(XSD::AttrTypeName)] = ns.name(data.type)
 
290
      end
 
291
    end
 
292
 
 
293
    data.extraattr.each do |key, value|
 
294
      SOAPGenerator.assign_ns(attrs, ns, key.namespace)
 
295
      attrs[ns.name(key)] = encode_attr_value(generator, ns, key, value)
 
296
    end
 
297
    if data.id
 
298
      attrs['id'] = data.id
 
299
    end
 
300
    attrs
 
301
  end
 
302
 
 
303
  def encode_attr_value(generator, ns, qname, value)
 
304
    if value.is_a?(SOAPType)
 
305
      ref = SOAPReference.new(value)
 
306
      generator.add_reftarget(qname.name, value)
 
307
      ref.refidstr
 
308
    else
 
309
      value.to_s
 
310
    end
 
311
  end
 
312
 
 
313
  def decode_tag_by_wsdl(ns, elename, typestr, parent, arytypestr, extraattr)
 
314
    o = nil
 
315
    if parent.class == SOAPBody
 
316
      # root element: should branch by root attribute?
 
317
      if @is_first_top_ele
 
318
        # Unqualified name is allowed here.
 
319
        @is_first_top_ele = false
 
320
        type = @decode_typemap[elename] ||
 
321
          @decode_typemap.find_name(elename.name)
 
322
        if type
 
323
          o = SOAPStruct.new(elename)
 
324
          o.definedtype = type
 
325
          return o
 
326
        end
 
327
      end
 
328
      # multi-ref element.
 
329
      if typestr
 
330
        typename = ns.parse(typestr)
 
331
        typedef = @decode_typemap[typename]
 
332
        if typedef
 
333
          return decode_definedtype(elename, typename, typedef, arytypestr)
 
334
        end
 
335
      end
 
336
      return decode_tag_by_type(ns, elename, typestr, parent, arytypestr,
 
337
        extraattr)
 
338
    end
 
339
 
 
340
    if parent.type == XSD::AnyTypeName
 
341
      return decode_tag_by_type(ns, elename, typestr, parent, arytypestr,
 
342
        extraattr)
 
343
    end
 
344
 
 
345
    # parent.definedtype == nil means the parent is SOAPUnknown.  SOAPUnknown
 
346
    # is generated by decode_tag_by_type when its type is anyType.
 
347
    parenttype = parent.definedtype || @decode_typemap[parent.type]
 
348
    unless parenttype
 
349
      return decode_tag_by_type(ns, elename, typestr, parent, arytypestr,
 
350
        extraattr)
 
351
    end
 
352
 
 
353
    definedtype_name = parenttype.child_type(elename)
 
354
    if definedtype_name and (klass = TypeMap[definedtype_name])
 
355
      return decode_basetype(klass, elename)
 
356
    elsif definedtype_name == XSD::AnyTypeName
 
357
      return decode_tag_by_type(ns, elename, typestr, parent, arytypestr,
 
358
        extraattr)
 
359
    end
 
360
 
 
361
    if definedtype_name
 
362
      typedef = @decode_typemap[definedtype_name]
 
363
    else
 
364
      typedef = parenttype.child_defined_complextype(elename)
 
365
    end
 
366
    decode_definedtype(elename, definedtype_name, typedef, arytypestr)
 
367
  end
 
368
 
 
369
  def decode_definedtype(elename, typename, typedef, arytypestr)
 
370
    unless typedef
 
371
      raise EncodingStyleError.new("unknown type '#{typename}'")
 
372
    end
 
373
    if typedef.is_a?(::WSDL::XMLSchema::SimpleType)
 
374
      decode_defined_simpletype(elename, typename, typedef, arytypestr)
 
375
    else
 
376
      decode_defined_complextype(elename, typename, typedef, arytypestr)
 
377
    end
 
378
  end
 
379
 
 
380
  def decode_basetype(klass, elename)
 
381
    klass.decode(elename)
 
382
  end
 
383
 
 
384
  def decode_defined_simpletype(elename, typename, typedef, arytypestr)
 
385
    o = decode_basetype(TypeMap[typedef.base], elename)
 
386
    o.definedtype = typedef
 
387
    o
 
388
  end
 
389
 
 
390
  def decode_defined_complextype(elename, typename, typedef, arytypestr)
 
391
    case typedef.compoundtype
 
392
    when :TYPE_STRUCT, :TYPE_MAP
 
393
      o = SOAPStruct.decode(elename, typename)
 
394
      o.definedtype = typedef
 
395
      return o
 
396
    when :TYPE_ARRAY
 
397
      expected_arytype = typedef.find_arytype
 
398
      if arytypestr
 
399
        actual_arytype = XSD::QName.new(expected_arytype.namespace,
 
400
          content_typename(expected_arytype.name) <<
 
401
          content_ranksize(arytypestr))
 
402
        o = SOAPArray.decode(elename, typename, actual_arytype)
 
403
      else
 
404
        o = SOAPArray.new(typename, 1, expected_arytype)
 
405
        o.elename = elename
 
406
      end
 
407
      o.definedtype = typedef
 
408
      return o
 
409
    when :TYPE_EMPTY
 
410
      o = SOAPNil.decode(elename)
 
411
      o.definedtype = typedef
 
412
      return o
 
413
    else
 
414
      raise RuntimeError.new(
 
415
        "Unknown kind of complexType: #{typedef.compoundtype}")
 
416
    end
 
417
    nil
 
418
  end
 
419
 
 
420
  def decode_tag_by_type(ns, elename, typestr, parent, arytypestr, extraattr)
 
421
    if arytypestr
 
422
      type = typestr ? ns.parse(typestr) : ValueArrayName
 
423
      node = SOAPArray.decode(elename, type, ns.parse(arytypestr))
 
424
      node.extraattr.update(extraattr)
 
425
      return node
 
426
    end
 
427
 
 
428
    type = nil
 
429
    if typestr
 
430
      type = ns.parse(typestr)
 
431
    elsif parent.is_a?(SOAPArray)
 
432
      type = parent.arytype
 
433
    else
 
434
      # Since it's in dynamic(without any type) encoding process,
 
435
      # assumes entity as its type itself.
 
436
      #   <SOAP-ENC:Array ...> => type Array in SOAP-ENC.
 
437
      #   <Country xmlns="foo"> => type Country in foo.
 
438
      type = elename
 
439
    end
 
440
 
 
441
    if (klass = TypeMap[type])
 
442
      node = decode_basetype(klass, elename)
 
443
      node.extraattr.update(extraattr)
 
444
      return node
 
445
    end
 
446
 
 
447
    # Unknown type... Struct or String
 
448
    SOAPUnknown.new(self, elename, type, extraattr)
 
449
  end
 
450
 
 
451
  def decode_textbuf(node)
 
452
    case node
 
453
    when XSD::XSDHexBinary, XSD::XSDBase64Binary
 
454
      node.set_encoded(@textbuf)
 
455
    when XSD::XSDString
 
456
      if @charset
 
457
        @textbuf = XSD::Charset.encoding_from_xml(@textbuf, @charset)
 
458
      end
 
459
      if node.definedtype
 
460
        node.definedtype.check_lexical_format(@textbuf)
 
461
      end
 
462
      node.set(@textbuf)
 
463
    when SOAPNil
 
464
      # Nothing to do.
 
465
    when SOAPBasetype
 
466
      node.set(@textbuf)
 
467
    else
 
468
      # Nothing to do...
 
469
    end
 
470
    @textbuf = ''
 
471
  end
 
472
 
 
473
  NilLiteralMap = {
 
474
    'true' => true,
 
475
    '1' => true,
 
476
    'false' => false,
 
477
    '0' => false
 
478
  }
 
479
  RootLiteralMap = {
 
480
    '1' => 1,
 
481
    '0' => 0
 
482
  }
 
483
  def decode_attrs(ns, attrs)
 
484
    is_nil = false
 
485
    type = nil
 
486
    arytype = nil
 
487
    root = nil
 
488
    offset = nil
 
489
    position = nil
 
490
    href = nil
 
491
    id = nil
 
492
    extraattr = {}
 
493
 
 
494
    attrs.each do |key, value|
 
495
      qname = ns.parse(key)
 
496
      case qname.namespace
 
497
      when XSD::InstanceNamespace
 
498
        case qname.name
 
499
        when XSD::NilLiteral
 
500
          is_nil = NilLiteralMap[value] or
 
501
            raise EncodingStyleError.new("cannot accept attribute value: #{value} as the value of xsi:#{XSD::NilLiteral} (expected 'true', 'false', '1', or '0')")
 
502
          next
 
503
        when XSD::AttrType
 
504
          type = value
 
505
          next
 
506
        end
 
507
      when EncodingNamespace
 
508
        case qname.name
 
509
        when AttrArrayType
 
510
          arytype = value
 
511
          next
 
512
        when AttrRoot
 
513
          root = RootLiteralMap[value] or
 
514
            raise EncodingStyleError.new(
 
515
              "illegal root attribute value: #{value}")
 
516
          next
 
517
        when AttrOffset
 
518
          offset = value
 
519
          next
 
520
        when AttrPosition
 
521
          position = value
 
522
          next
 
523
        end
 
524
      end
 
525
      if key == 'href'
 
526
        href = value
 
527
        next
 
528
      elsif key == 'id'
 
529
        id = value
 
530
        next
 
531
      end
 
532
      qname = ns.parse_local(key)
 
533
      extraattr[qname] = decode_attr_value(ns, qname, value)
 
534
    end
 
535
 
 
536
    return is_nil, type, arytype, root, offset, position, href, id, extraattr
 
537
  end
 
538
 
 
539
  def decode_attr_value(ns, qname, value)
 
540
    if /\A#/ =~ value
 
541
      o = SOAPReference.decode(nil, value)
 
542
      @refpool << o
 
543
      o
 
544
    else
 
545
      value
 
546
    end
 
547
  end
 
548
 
 
549
  def decode_arypos(position)
 
550
    /^\[(.+)\]$/ =~ position
 
551
    $1.split(',').collect { |s| s.to_i }
 
552
  end
 
553
 
 
554
  def decode_resolve_id
 
555
    count = @refpool.length     # To avoid infinite loop
 
556
    while !@refpool.empty? && count > 0
 
557
      @refpool = @refpool.find_all { |ref|
 
558
        o = @idpool.find { |item|
 
559
          item.id == ref.refid
 
560
        }
 
561
        if o.is_a?(SOAPReference)
 
562
          true  # link of link.
 
563
        elsif o
 
564
          ref.__setobj__(o)
 
565
          false
 
566
        elsif o = ref.rootnode.external_content[ref.refid]
 
567
          ref.__setobj__(o)
 
568
          false
 
569
        else
 
570
          raise EncodingStyleError.new("unresolved reference: #{ref.refid}")
 
571
        end
 
572
      }
 
573
      count -= 1
 
574
    end
 
575
  end
 
576
end
 
577
 
 
578
SOAPHandler.new
 
579
 
 
580
 
 
581
end
 
582
end