From 11dbedfaad4a9a9521ece2198a8dc491678b1902 Mon Sep 17 00:00:00 2001 From: shyouhei Date: Wed, 29 Aug 2007 04:06:12 +0000 Subject: add tag v1_8_6_5001 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_8_6_5001@13304 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ruby_1_8_6/lib/soap/attachment.rb | 107 +++ ruby_1_8_6/lib/soap/baseData.rb | 942 +++++++++++++++++++++ ruby_1_8_6/lib/soap/element.rb | 258 ++++++ .../lib/soap/encodingstyle/aspDotNetHandler.rb | 213 +++++ ruby_1_8_6/lib/soap/encodingstyle/handler.rb | 100 +++ .../lib/soap/encodingstyle/literalHandler.rb | 226 +++++ ruby_1_8_6/lib/soap/encodingstyle/soapHandler.rb | 582 +++++++++++++ ruby_1_8_6/lib/soap/generator.rb | 268 ++++++ ruby_1_8_6/lib/soap/header/handler.rb | 57 ++ ruby_1_8_6/lib/soap/header/handlerset.rb | 70 ++ ruby_1_8_6/lib/soap/header/simplehandler.rb | 44 + ruby_1_8_6/lib/soap/httpconfigloader.rb | 119 +++ ruby_1_8_6/lib/soap/mapping.rb | 10 + ruby_1_8_6/lib/soap/mapping/factory.rb | 355 ++++++++ ruby_1_8_6/lib/soap/mapping/mapping.rb | 381 +++++++++ ruby_1_8_6/lib/soap/mapping/registry.rb | 541 ++++++++++++ ruby_1_8_6/lib/soap/mapping/rubytypeFactory.rb | 475 +++++++++++ ruby_1_8_6/lib/soap/mapping/typeMap.rb | 50 ++ ruby_1_8_6/lib/soap/mapping/wsdlencodedregistry.rb | 280 ++++++ ruby_1_8_6/lib/soap/mapping/wsdlliteralregistry.rb | 418 +++++++++ ruby_1_8_6/lib/soap/marshal.rb | 59 ++ ruby_1_8_6/lib/soap/mimemessage.rb | 240 ++++++ ruby_1_8_6/lib/soap/netHttpClient.rb | 190 +++++ ruby_1_8_6/lib/soap/parser.rb | 251 ++++++ ruby_1_8_6/lib/soap/processor.rb | 66 ++ ruby_1_8_6/lib/soap/property.rb | 333 ++++++++ ruby_1_8_6/lib/soap/rpc/cgistub.rb | 206 +++++ ruby_1_8_6/lib/soap/rpc/driver.rb | 254 ++++++ ruby_1_8_6/lib/soap/rpc/element.rb | 325 +++++++ ruby_1_8_6/lib/soap/rpc/httpserver.rb | 129 +++ ruby_1_8_6/lib/soap/rpc/proxy.rb | 497 +++++++++++ ruby_1_8_6/lib/soap/rpc/router.rb | 594 +++++++++++++ ruby_1_8_6/lib/soap/rpc/rpc.rb | 25 + ruby_1_8_6/lib/soap/rpc/soaplet.rb | 162 ++++ ruby_1_8_6/lib/soap/rpc/standaloneServer.rb | 43 + ruby_1_8_6/lib/soap/soap.rb | 140 +++ ruby_1_8_6/lib/soap/streamHandler.rb | 229 +++++ ruby_1_8_6/lib/soap/wsdlDriver.rb | 575 +++++++++++++ 38 files changed, 9814 insertions(+) create mode 100644 ruby_1_8_6/lib/soap/attachment.rb create mode 100644 ruby_1_8_6/lib/soap/baseData.rb create mode 100644 ruby_1_8_6/lib/soap/element.rb create mode 100644 ruby_1_8_6/lib/soap/encodingstyle/aspDotNetHandler.rb create mode 100644 ruby_1_8_6/lib/soap/encodingstyle/handler.rb create mode 100644 ruby_1_8_6/lib/soap/encodingstyle/literalHandler.rb create mode 100644 ruby_1_8_6/lib/soap/encodingstyle/soapHandler.rb create mode 100644 ruby_1_8_6/lib/soap/generator.rb create mode 100644 ruby_1_8_6/lib/soap/header/handler.rb create mode 100644 ruby_1_8_6/lib/soap/header/handlerset.rb create mode 100644 ruby_1_8_6/lib/soap/header/simplehandler.rb create mode 100644 ruby_1_8_6/lib/soap/httpconfigloader.rb create mode 100644 ruby_1_8_6/lib/soap/mapping.rb create mode 100644 ruby_1_8_6/lib/soap/mapping/factory.rb create mode 100644 ruby_1_8_6/lib/soap/mapping/mapping.rb create mode 100644 ruby_1_8_6/lib/soap/mapping/registry.rb create mode 100644 ruby_1_8_6/lib/soap/mapping/rubytypeFactory.rb create mode 100644 ruby_1_8_6/lib/soap/mapping/typeMap.rb create mode 100644 ruby_1_8_6/lib/soap/mapping/wsdlencodedregistry.rb create mode 100644 ruby_1_8_6/lib/soap/mapping/wsdlliteralregistry.rb create mode 100644 ruby_1_8_6/lib/soap/marshal.rb create mode 100644 ruby_1_8_6/lib/soap/mimemessage.rb create mode 100644 ruby_1_8_6/lib/soap/netHttpClient.rb create mode 100644 ruby_1_8_6/lib/soap/parser.rb create mode 100644 ruby_1_8_6/lib/soap/processor.rb create mode 100644 ruby_1_8_6/lib/soap/property.rb create mode 100644 ruby_1_8_6/lib/soap/rpc/cgistub.rb create mode 100644 ruby_1_8_6/lib/soap/rpc/driver.rb create mode 100644 ruby_1_8_6/lib/soap/rpc/element.rb create mode 100644 ruby_1_8_6/lib/soap/rpc/httpserver.rb create mode 100644 ruby_1_8_6/lib/soap/rpc/proxy.rb create mode 100644 ruby_1_8_6/lib/soap/rpc/router.rb create mode 100644 ruby_1_8_6/lib/soap/rpc/rpc.rb create mode 100644 ruby_1_8_6/lib/soap/rpc/soaplet.rb create mode 100644 ruby_1_8_6/lib/soap/rpc/standaloneServer.rb create mode 100644 ruby_1_8_6/lib/soap/soap.rb create mode 100644 ruby_1_8_6/lib/soap/streamHandler.rb create mode 100644 ruby_1_8_6/lib/soap/wsdlDriver.rb (limited to 'ruby_1_8_6/lib/soap') diff --git a/ruby_1_8_6/lib/soap/attachment.rb b/ruby_1_8_6/lib/soap/attachment.rb new file mode 100644 index 0000000000..1a59b14018 --- /dev/null +++ b/ruby_1_8_6/lib/soap/attachment.rb @@ -0,0 +1,107 @@ +# soap/attachment.rb: SOAP4R - SwA implementation. +# Copyright (C) 2002, 2003 Jamie Herre and NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/baseData' +require 'soap/mapping' + + +module SOAP + + +class SOAPAttachment < SOAPExternalReference + attr_reader :data + + def initialize(value) + super() + @data = value + end + +private + + def external_contentid + @data.contentid + end +end + + +class Attachment + attr_reader :io + attr_accessor :contenttype + + def initialize(string_or_readable = nil) + @string_or_readable = string_or_readable + @contenttype = "application/octet-stream" + @contentid = nil + end + + def contentid + @contentid ||= Attachment.contentid(self) + end + + def contentid=(contentid) + @contentid = contentid + end + + def mime_contentid + '<' + contentid + '>' + end + + def content + if @content == nil and @string_or_readable != nil + @content = @string_or_readable.respond_to?(:read) ? + @string_or_readable.read : @string_or_readable + end + @content + end + + def to_s + content + end + + def write(out) + out.write(content) + end + + def save(filename) + File.open(filename, "wb") do |f| + write(f) + end + end + + def self.contentid(obj) + # this needs to be fixed + [obj.__id__.to_s, Process.pid.to_s].join('.') + end + + def self.mime_contentid(obj) + '<' + contentid(obj) + '>' + end +end + + +module Mapping + class AttachmentFactory < SOAP::Mapping::Factory + def obj2soap(soap_class, obj, info, map) + soap_obj = soap_class.new(obj) + mark_marshalled_obj(obj, soap_obj) + soap_obj + end + + def soap2obj(obj_class, node, info, map) + obj = node.data + mark_unmarshalled_obj(node, obj) + return true, obj + end + end + + DefaultRegistry.add(::SOAP::Attachment, ::SOAP::SOAPAttachment, + AttachmentFactory.new, nil) +end + + +end diff --git a/ruby_1_8_6/lib/soap/baseData.rb b/ruby_1_8_6/lib/soap/baseData.rb new file mode 100644 index 0000000000..0e8b00d450 --- /dev/null +++ b/ruby_1_8_6/lib/soap/baseData.rb @@ -0,0 +1,942 @@ +# soap/baseData.rb: SOAP4R - Base type library +# Copyright (C) 2000, 2001, 2003-2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'xsd/datatypes' +require 'soap/soap' + + +module SOAP + + +### +## Mix-in module for SOAP base type classes. +# +module SOAPModuleUtils + include SOAP + +public + + def decode(elename) + d = self.new + d.elename = elename + d + end +end + + +### +## for SOAP type(base and compound) +# +module SOAPType + attr_accessor :encodingstyle + attr_accessor :elename + attr_accessor :id + attr_reader :precedents + attr_accessor :root + attr_accessor :parent + attr_accessor :position + attr_reader :extraattr + attr_accessor :definedtype + + def initialize(*arg) + super + @encodingstyle = nil + @elename = XSD::QName::EMPTY + @id = nil + @precedents = [] + @root = false + @parent = nil + @position = nil + @definedtype = nil + @extraattr = {} + end + + def inspect + if self.is_a?(XSD::NSDBase) + sprintf("#<%s:0x%x %s %s>", self.class.name, __id__, self.elename, self.type) + else + sprintf("#<%s:0x%x %s>", self.class.name, __id__, self.elename) + end + end + + def rootnode + node = self + while node = node.parent + break if SOAPEnvelope === node + end + node + end +end + + +### +## for SOAP base type +# +module SOAPBasetype + include SOAPType + include SOAP + + def initialize(*arg) + super + end +end + + +### +## for SOAP compound type +# +module SOAPCompoundtype + include SOAPType + include SOAP + + def initialize(*arg) + super + end +end + + +### +## Convenience datatypes. +# +class SOAPReference < XSD::NSDBase + include SOAPBasetype + extend SOAPModuleUtils + +public + + attr_accessor :refid + + # Override the definition in SOAPBasetype. + def initialize(obj = nil) + super() + @type = XSD::QName::EMPTY + @refid = nil + @obj = nil + __setobj__(obj) if obj + end + + def __getobj__ + @obj + end + + def __setobj__(obj) + @obj = obj + @refid = @obj.id || SOAPReference.create_refid(@obj) + @obj.id = @refid unless @obj.id + @obj.precedents << self + # Copies NSDBase information + @obj.type = @type unless @obj.type + end + + # Why don't I use delegate.rb? + # -> delegate requires target object type at initialize time. + # Why don't I use forwardable.rb? + # -> forwardable requires a list of forwarding methods. + # + # ToDo: Maybe I should use forwardable.rb and give it a methods list like + # delegate.rb... + # + def method_missing(msg_id, *params) + if @obj + @obj.send(msg_id, *params) + else + nil + end + end + + def refidstr + '#' + @refid + end + + def self.create_refid(obj) + 'id' + obj.__id__.to_s + end + + def self.decode(elename, refidstr) + if /\A#(.*)\z/ =~ refidstr + refid = $1 + elsif /\Acid:(.*)\z/ =~ refidstr + refid = $1 + else + raise ArgumentError.new("illegal refid #{refidstr}") + end + d = super(elename) + d.refid = refid + d + end +end + + +class SOAPExternalReference < XSD::NSDBase + include SOAPBasetype + extend SOAPModuleUtils + + def initialize + super() + @type = XSD::QName::EMPTY + end + + def referred + rootnode.external_content[external_contentid] = self + end + + def refidstr + 'cid:' + external_contentid + end + +private + + def external_contentid + raise NotImplementedError.new + end +end + + +class SOAPNil < XSD::XSDNil + include SOAPBasetype + extend SOAPModuleUtils +end + +# SOAPRawString is for sending raw string. In contrast to SOAPString, +# SOAP4R does not do XML encoding and does not convert its CES. The string it +# holds is embedded to XML instance directly as a 'xsd:string'. +class SOAPRawString < XSD::XSDString + include SOAPBasetype + extend SOAPModuleUtils +end + + +### +## Basic datatypes. +# +class SOAPAnySimpleType < XSD::XSDAnySimpleType + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPString < XSD::XSDString + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPBoolean < XSD::XSDBoolean + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPDecimal < XSD::XSDDecimal + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPFloat < XSD::XSDFloat + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPDouble < XSD::XSDDouble + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPDuration < XSD::XSDDuration + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPDateTime < XSD::XSDDateTime + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPTime < XSD::XSDTime + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPDate < XSD::XSDDate + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPGYearMonth < XSD::XSDGYearMonth + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPGYear < XSD::XSDGYear + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPGMonthDay < XSD::XSDGMonthDay + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPGDay < XSD::XSDGDay + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPGMonth < XSD::XSDGMonth + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPHexBinary < XSD::XSDHexBinary + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPBase64 < XSD::XSDBase64Binary + include SOAPBasetype + extend SOAPModuleUtils + Type = QName.new(EncodingNamespace, Base64Literal) + +public + # Override the definition in SOAPBasetype. + def initialize(value = nil) + super(value) + @type = Type + end + + def as_xsd + @type = XSD::XSDBase64Binary::Type + end +end + +class SOAPAnyURI < XSD::XSDAnyURI + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPQName < XSD::XSDQName + include SOAPBasetype + extend SOAPModuleUtils +end + + +class SOAPInteger < XSD::XSDInteger + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPNonPositiveInteger < XSD::XSDNonPositiveInteger + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPNegativeInteger < XSD::XSDNegativeInteger + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPLong < XSD::XSDLong + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPInt < XSD::XSDInt + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPShort < XSD::XSDShort + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPByte < XSD::XSDByte + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPNonNegativeInteger < XSD::XSDNonNegativeInteger + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPUnsignedLong < XSD::XSDUnsignedLong + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPUnsignedInt < XSD::XSDUnsignedInt + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPUnsignedShort < XSD::XSDUnsignedShort + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPUnsignedByte < XSD::XSDUnsignedByte + include SOAPBasetype + extend SOAPModuleUtils +end + +class SOAPPositiveInteger < XSD::XSDPositiveInteger + include SOAPBasetype + extend SOAPModuleUtils +end + + +### +## Compound datatypes. +# +class SOAPStruct < XSD::NSDBase + include SOAPCompoundtype + include Enumerable + +public + + def initialize(type = nil) + super() + @type = type || XSD::QName::EMPTY + @array = [] + @data = [] + end + + def to_s() + str = '' + self.each do |key, data| + str << "#{key}: #{data}\n" + end + str + end + + def add(name, value) + add_member(name, value) + end + + def [](idx) + if idx.is_a?(Range) + @data[idx] + elsif idx.is_a?(Integer) + if (idx > @array.size) + raise ArrayIndexOutOfBoundsError.new('In ' << @type.name) + end + @data[idx] + else + if @array.include?(idx) + @data[@array.index(idx)] + else + nil + end + end + end + + def []=(idx, data) + if @array.include?(idx) + data.parent = self if data.respond_to?(:parent=) + @data[@array.index(idx)] = data + else + add(idx, data) + end + end + + def key?(name) + @array.include?(name) + end + + def members + @array + end + + def to_obj + hash = {} + proptype = {} + each do |k, v| + value = v.respond_to?(:to_obj) ? v.to_obj : v.to_s + case proptype[k] + when :single + hash[k] = [hash[k], value] + proptype[k] = :multi + when :multi + hash[k] << value + else + hash[k] = value + proptype[k] = :single + end + end + hash + end + + def each + idx = 0 + while idx < @array.length + yield(@array[idx], @data[idx]) + idx += 1 + end + end + + def replace + members.each do |member| + self[member] = yield(self[member]) + end + end + + def self.decode(elename, type) + s = SOAPStruct.new(type) + s.elename = elename + s + end + +private + + def add_member(name, value = nil) + value = SOAPNil.new() if value.nil? + @array.push(name) + value.elename = value.elename.dup_name(name) + @data.push(value) + value.parent = self if value.respond_to?(:parent=) + value + end +end + + +# SOAPElement is not typed so it is not derived from NSDBase. +class SOAPElement + include Enumerable + + attr_accessor :encodingstyle + + attr_accessor :elename + attr_accessor :id + attr_reader :precedents + attr_accessor :root + attr_accessor :parent + attr_accessor :position + attr_accessor :extraattr + + attr_accessor :qualified + + def initialize(elename, text = nil) + if !elename.is_a?(XSD::QName) + elename = XSD::QName.new(nil, elename) + end + @encodingstyle = LiteralNamespace + @elename = elename + @id = nil + @precedents = [] + @root = false + @parent = nil + @position = nil + @extraattr = {} + + @qualified = nil + + @array = [] + @data = [] + @text = text + end + + def inspect + sprintf("#<%s:0x%x %s>", self.class.name, __id__, self.elename) + end + + # Text interface. + attr_accessor :text + alias data text + + # Element interfaces. + def add(value) + add_member(value.elename.name, value) + end + + def [](idx) + if @array.include?(idx) + @data[@array.index(idx)] + else + nil + end + end + + def []=(idx, data) + if @array.include?(idx) + data.parent = self if data.respond_to?(:parent=) + @data[@array.index(idx)] = data + else + add(data) + end + end + + def key?(name) + @array.include?(name) + end + + def members + @array + end + + def to_obj + if members.empty? + @text + else + hash = {} + proptype = {} + each do |k, v| + value = v.respond_to?(:to_obj) ? v.to_obj : v.to_s + case proptype[k] + when :single + hash[k] = [hash[k], value] + proptype[k] = :multi + when :multi + hash[k] << value + else + hash[k] = value + proptype[k] = :single + end + end + hash + end + end + + def each + idx = 0 + while idx < @array.length + yield(@array[idx], @data[idx]) + idx += 1 + end + end + + def self.decode(elename) + o = SOAPElement.new(elename) + o + end + + def self.from_obj(obj, namespace = nil) + o = SOAPElement.new(nil) + case obj + when nil + o.text = nil + when Hash + obj.each do |elename, value| + if value.is_a?(Array) + value.each do |subvalue| + child = from_obj(subvalue, namespace) + child.elename = to_elename(elename, namespace) + o.add(child) + end + else + child = from_obj(value, namespace) + child.elename = to_elename(elename, namespace) + o.add(child) + end + end + else + o.text = obj.to_s + end + o + end + + def self.to_elename(obj, namespace = nil) + if obj.is_a?(XSD::QName) + obj + elsif /\A(.+):([^:]+)\z/ =~ obj.to_s + XSD::QName.new($1, $2) + else + XSD::QName.new(namespace, obj.to_s) + end + end + +private + + def add_member(name, value) + add_accessor(name) + @array.push(name) + @data.push(value) + value.parent = self if value.respond_to?(:parent=) + value + end + + if RUBY_VERSION > "1.7.0" + def add_accessor(name) + methodname = name + if self.respond_to?(methodname) + methodname = safe_accessor_name(methodname) + end + Mapping.define_singleton_method(self, methodname) do + @data[@array.index(name)] + end + Mapping.define_singleton_method(self, methodname + '=') do |value| + @data[@array.index(name)] = value + end + end + else + def add_accessor(name) + methodname = safe_accessor_name(name) + instance_eval <<-EOS + def #{methodname} + @data[@array.index(#{name.dump})] + end + + def #{methodname}=(value) + @data[@array.index(#{name.dump})] = value + end + EOS + end + end + + def safe_accessor_name(name) + "var_" << name.gsub(/[^a-zA-Z0-9_]/, '') + end +end + + +class SOAPArray < XSD::NSDBase + include SOAPCompoundtype + include Enumerable + +public + + attr_accessor :sparse + + attr_reader :offset, :rank + attr_accessor :size, :size_fixed + attr_reader :arytype + + def initialize(type = nil, rank = 1, arytype = nil) + super() + @type = type || ValueArrayName + @rank = rank + @data = Array.new + @sparse = false + @offset = Array.new(rank, 0) + @size = Array.new(rank, 0) + @size_fixed = false + @position = nil + @arytype = arytype + end + + def offset=(var) + @offset = var + @sparse = true + end + + def add(value) + self[*(@offset)] = value + end + + def [](*idxary) + if idxary.size != @rank + raise ArgumentError.new("given #{idxary.size} params does not match rank: #{@rank}") + end + + retrieve(idxary) + end + + def []=(*idxary) + value = idxary.slice!(-1) + + if idxary.size != @rank + raise ArgumentError.new("given #{idxary.size} params(#{idxary})" + + " does not match rank: #{@rank}") + end + + idx = 0 + while idx < idxary.size + if idxary[idx] + 1 > @size[idx] + @size[idx] = idxary[idx] + 1 + end + idx += 1 + end + + data = retrieve(idxary[0, idxary.size - 1]) + data[idxary.last] = value + + if value.is_a?(SOAPType) + value.elename = ITEM_NAME + # Sync type + unless @type.name + @type = XSD::QName.new(value.type.namespace, + SOAPArray.create_arytype(value.type.name, @rank)) + end + value.type ||= @type + end + + @offset = idxary + value.parent = self if value.respond_to?(:parent=) + offsetnext + end + + def each + @data.each do |data| + yield(data) + end + end + + def to_a + @data.dup + end + + def replace + @data = deep_map(@data) do |ele| + yield(ele) + end + end + + def deep_map(ary, &block) + ary.collect do |ele| + if ele.is_a?(Array) + deep_map(ele, &block) + else + new_obj = block.call(ele) + new_obj.elename = ITEM_NAME + new_obj + end + end + end + + def include?(var) + traverse_data(@data) do |v, *rank| + if v.is_a?(SOAPBasetype) && v.data == var + return true + end + end + false + end + + def traverse + traverse_data(@data) do |v, *rank| + unless @sparse + yield(v) + else + yield(v, *rank) if v && !v.is_a?(SOAPNil) + end + end + end + + def soap2array(ary) + traverse_data(@data) do |v, *position| + iteary = ary + rank = 1 + while rank < position.size + idx = position[rank - 1] + if iteary[idx].nil? + iteary = iteary[idx] = Array.new + else + iteary = iteary[idx] + end + rank += 1 + end + if block_given? + iteary[position.last] = yield(v) + else + iteary[position.last] = v + end + end + end + + def position + @position + end + +private + + ITEM_NAME = XSD::QName.new(nil, 'item') + + def retrieve(idxary) + data = @data + rank = 1 + while rank <= idxary.size + idx = idxary[rank - 1] + if data[idx].nil? + data = data[idx] = Array.new + else + data = data[idx] + end + rank += 1 + end + data + end + + def traverse_data(data, rank = 1) + idx = 0 + while idx < ranksize(rank) + if rank < @rank + traverse_data(data[idx], rank + 1) do |*v| + v[1, 0] = idx + yield(*v) + end + else + yield(data[idx], idx) + end + idx += 1 + end + end + + def ranksize(rank) + @size[rank - 1] + end + + def offsetnext + move = false + idx = @offset.size - 1 + while !move && idx >= 0 + @offset[idx] += 1 + if @size_fixed + if @offset[idx] < @size[idx] + move = true + else + @offset[idx] = 0 + idx -= 1 + end + else + move = true + end + end + end + + # Module function + +public + + def self.decode(elename, type, arytype) + typestr, nofary = parse_type(arytype.name) + rank = nofary.count(',') + 1 + plain_arytype = XSD::QName.new(arytype.namespace, typestr) + o = SOAPArray.new(type, rank, plain_arytype) + size = [] + nofary.split(',').each do |s| + if s.empty? + size.clear + break + else + size << s.to_i + end + end + unless size.empty? + o.size = size + o.size_fixed = true + end + o.elename = elename + o + end + +private + + def self.create_arytype(typename, rank) + "#{typename}[" << ',' * (rank - 1) << ']' + end + + TypeParseRegexp = Regexp.new('^(.+)\[([\d,]*)\]$') + + def self.parse_type(string) + TypeParseRegexp =~ string + return $1, $2 + end +end + + +require 'soap/mapping/typeMap' + + +end diff --git a/ruby_1_8_6/lib/soap/element.rb b/ruby_1_8_6/lib/soap/element.rb new file mode 100644 index 0000000000..cc58b5d341 --- /dev/null +++ b/ruby_1_8_6/lib/soap/element.rb @@ -0,0 +1,258 @@ +# SOAP4R - SOAP elements library +# Copyright (C) 2000, 2001, 2003-2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'xsd/qname' +require 'soap/baseData' + + +module SOAP + + +### +## SOAP elements +# +module SOAPEnvelopeElement; end + +class SOAPFault < SOAPStruct + include SOAPEnvelopeElement + include SOAPCompoundtype + +public + + def faultcode + self['faultcode'] + end + + def faultstring + self['faultstring'] + end + + def faultactor + self['faultactor'] + end + + def detail + self['detail'] + end + + def faultcode=(rhs) + self['faultcode'] = rhs + end + + def faultstring=(rhs) + self['faultstring'] = rhs + end + + def faultactor=(rhs) + self['faultactor'] = rhs + end + + def detail=(rhs) + self['detail'] = rhs + end + + def initialize(faultcode = nil, faultstring = nil, faultactor = nil, detail = nil) + super(EleFaultName) + @elename = EleFaultName + @encodingstyle = EncodingNamespace + + if faultcode + self.faultcode = faultcode + self.faultstring = faultstring + self.faultactor = faultactor + self.detail = detail + self.faultcode.elename = EleFaultCodeName if self.faultcode + self.faultstring.elename = EleFaultStringName if self.faultstring + self.faultactor.elename = EleFaultActorName if self.faultactor + self.detail.elename = EleFaultDetailName if self.detail + end + faultcode.parent = self if faultcode + faultstring.parent = self if faultstring + faultactor.parent = self if faultactor + detail.parent = self if detail + end + + def encode(generator, ns, attrs = {}) + SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace) + SOAPGenerator.assign_ns(attrs, ns, EncodingNamespace) + attrs[ns.name(AttrEncodingStyleName)] = EncodingNamespace + name = ns.name(@elename) + generator.encode_tag(name, attrs) + yield(self.faultcode) + yield(self.faultstring) + yield(self.faultactor) + yield(self.detail) if self.detail + generator.encode_tag_end(name, true) + end +end + + +class SOAPBody < SOAPStruct + include SOAPEnvelopeElement + + def initialize(data = nil, is_fault = false) + super(nil) + @elename = EleBodyName + @encodingstyle = nil + if data + if data.respond_to?(:elename) + add(data.elename.name, data) + else + data.to_a.each do |datum| + add(datum.elename.name, datum) + end + end + end + @is_fault = is_fault + end + + def encode(generator, ns, attrs = {}) + name = ns.name(@elename) + generator.encode_tag(name, attrs) + if @is_fault + yield(@data) + else + @data.each do |data| + yield(data) + end + end + generator.encode_tag_end(name, true) + end + + def root_node + @data.each do |node| + if node.root == 1 + return node + end + end + # No specified root... + @data.each do |node| + if node.root != 0 + return node + end + end + + raise Parser::FormatDecodeError.new('no root element') + end +end + + +class SOAPHeaderItem < XSD::NSDBase + include SOAPEnvelopeElement + include SOAPCompoundtype + +public + + attr_accessor :element + attr_accessor :mustunderstand + attr_accessor :encodingstyle + + def initialize(element, mustunderstand = true, encodingstyle = nil) + super() + @type = nil + @element = element + @mustunderstand = mustunderstand + @encodingstyle = encodingstyle + element.parent = self if element + end + + def encode(generator, ns, attrs = {}) + attrs.each do |key, value| + @element.extraattr[key] = value + end + @element.extraattr[ns.name(AttrMustUnderstandName)] = + (@mustunderstand ? '1' : '0') + if @encodingstyle + @element.extraattr[ns.name(AttrEncodingStyleName)] = @encodingstyle + end + @element.encodingstyle = @encodingstyle if !@element.encodingstyle + yield(@element) + end +end + + +class SOAPHeader < SOAPStruct + include SOAPEnvelopeElement + + def initialize + super(nil) + @elename = EleHeaderName + @encodingstyle = nil + end + + def encode(generator, ns, attrs = {}) + name = ns.name(@elename) + generator.encode_tag(name, attrs) + @data.each do |data| + yield(data) + end + generator.encode_tag_end(name, true) + end + + def add(name, value) + mu = (value.extraattr[AttrMustUnderstandName] == '1') + encstyle = value.extraattr[AttrEncodingStyleName] + item = SOAPHeaderItem.new(value, mu, encstyle) + super(name, item) + end + + def length + @data.length + end + alias size length +end + + +class SOAPEnvelope < XSD::NSDBase + include SOAPEnvelopeElement + include SOAPCompoundtype + + attr_reader :header + attr_reader :body + attr_reader :external_content + + def initialize(header = nil, body = nil) + super() + @type = nil + @elename = EleEnvelopeName + @encodingstyle = nil + @header = header + @body = body + @external_content = {} + header.parent = self if header + body.parent = self if body + end + + def header=(header) + header.parent = self + @header = header + end + + def body=(body) + body.parent = self + @body = body + end + + def encode(generator, ns, attrs = {}) + SOAPGenerator.assign_ns(attrs, ns, elename.namespace, SOAPNamespaceTag) + name = ns.name(@elename) + generator.encode_tag(name, attrs) + + yield(@header) if @header and @header.length > 0 + yield(@body) + + generator.encode_tag_end(name, true) + end + + def to_ary + [header, body] + end +end + + +end diff --git a/ruby_1_8_6/lib/soap/encodingstyle/aspDotNetHandler.rb b/ruby_1_8_6/lib/soap/encodingstyle/aspDotNetHandler.rb new file mode 100644 index 0000000000..fd7e0fa217 --- /dev/null +++ b/ruby_1_8_6/lib/soap/encodingstyle/aspDotNetHandler.rb @@ -0,0 +1,213 @@ +# SOAP4R - ASP.NET EncodingStyle handler library +# Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/encodingstyle/handler' + + +module SOAP +module EncodingStyle + + +class ASPDotNetHandler < Handler + Namespace = 'http://tempuri.org/ASP.NET' + add_handler + + def initialize(charset = nil) + super(charset) + @textbuf = '' + @decode_typemap = nil + end + + + ### + ## encode interface. + # + def encode_data(generator, ns, data, parent) + attrs = {} + # ASPDotNetHandler is intended to be used for accessing an ASP.NET doc/lit + # service as an rpc/encoded service. in the situation, local elements + # should be qualified. propagate parent's namespace to children. + if data.elename.namespace.nil? + data.elename.namespace = parent.elename.namespace + end + name = generator.encode_name(ns, data, attrs) + case data + when SOAPRawString + generator.encode_tag(name, attrs) + generator.encode_rawstring(data.to_s) + when XSD::XSDString + generator.encode_tag(name, attrs) + generator.encode_string(@charset ? + XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s) + when XSD::XSDAnySimpleType + generator.encode_tag(name, attrs) + generator.encode_string(data.to_s) + when SOAPStruct + generator.encode_tag(name, attrs) + data.each do |key, value| + generator.encode_child(ns, value, data) + end + when SOAPArray + generator.encode_tag(name, attrs) + data.traverse do |child, *rank| + data.position = nil + generator.encode_child(ns, child, data) + end + else + raise EncodingStyleError.new( + "unknown object:#{data} in this encodingStyle") + end + end + + def encode_data_end(generator, ns, data, parent) + name = generator.encode_name_end(ns, data) + cr = data.is_a?(SOAPCompoundtype) + generator.encode_tag_end(name, cr) + end + + + ### + ## decode interface. + # + class SOAPTemporalObject + attr_accessor :parent + + def initialize + @parent = nil + end + end + + class SOAPUnknown < SOAPTemporalObject + def initialize(handler, elename) + super() + @handler = handler + @elename = elename + end + + def as_struct + o = SOAPStruct.decode(@elename, XSD::AnyTypeName) + o.parent = @parent + o.type.name = @name + @handler.decode_parent(@parent, o) + o + end + + def as_string + o = SOAPString.decode(@elename) + o.parent = @parent + @handler.decode_parent(@parent, o) + o + end + + def as_nil + o = SOAPNil.decode(@elename) + o.parent = @parent + @handler.decode_parent(@parent, o) + o + end + end + + def decode_tag(ns, elename, attrs, parent) + @textbuf = '' + o = SOAPUnknown.new(self, elename) + o.parent = parent + o + end + + def decode_tag_end(ns, node) + o = node.node + if o.is_a?(SOAPUnknown) + newnode = o.as_string +# if /\A\s*\z/ =~ @textbuf +# o.as_struct +# else +# o.as_string +# end + node.replace_node(newnode) + o = node.node + end + + decode_textbuf(o) + @textbuf = '' + end + + def decode_text(ns, text) + # @textbuf is set at decode_tag_end. + @textbuf << text + end + + def decode_prologue + end + + def decode_epilogue + end + + def decode_parent(parent, node) + case parent.node + when SOAPUnknown + newparent = parent.node.as_struct + node.parent = newparent + parent.replace_node(newparent) + decode_parent(parent, node) + + when SOAPStruct + data = parent.node[node.elename.name] + case data + when nil + parent.node.add(node.elename.name, node) + when SOAPArray + name, type_ns = node.elename.name, node.type.namespace + data.add(node) + node.elename, node.type.namespace = name, type_ns + else + parent.node[node.elename.name] = SOAPArray.new + name, type_ns = data.elename.name, data.type.namespace + parent.node[node.elename.name].add(data) + data.elename.name, data.type.namespace = name, type_ns + name, type_ns = node.elename.name, node.type.namespace + parent.node[node.elename.name].add(node) + node.elename.name, node.type.namespace = name, type_ns + end + + when SOAPArray + if node.position + parent.node[*(decode_arypos(node.position))] = node + parent.node.sparse = true + else + parent.node.add(node) + end + + when SOAPBasetype + raise EncodingStyleError.new("SOAP base type must not have a child") + + else + # SOAPUnknown does not have parent. + # raise EncodingStyleError.new("illegal parent: #{parent}") + end + end + +private + + def decode_textbuf(node) + if node.is_a?(XSD::XSDString) + if @charset + node.set(XSD::Charset.encoding_from_xml(@textbuf, @charset)) + else + node.set(@textbuf) + end + else + # Nothing to do... + end + end +end + +ASPDotNetHandler.new + + +end +end diff --git a/ruby_1_8_6/lib/soap/encodingstyle/handler.rb b/ruby_1_8_6/lib/soap/encodingstyle/handler.rb new file mode 100644 index 0000000000..c015417435 --- /dev/null +++ b/ruby_1_8_6/lib/soap/encodingstyle/handler.rb @@ -0,0 +1,100 @@ +# SOAP4R - EncodingStyle handler library +# Copyright (C) 2001, 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/soap' +require 'soap/baseData' +require 'soap/element' + + +module SOAP +module EncodingStyle + + +class Handler + @@handlers = {} + + class EncodingStyleError < Error; end + + class << self + def uri + self::Namespace + end + + def handler(uri) + @@handlers[uri] + end + + def each + @@handlers.each do |key, value| + yield(value) + end + end + + private + + def add_handler + @@handlers[self.uri] = self + end + end + + attr_reader :charset + attr_accessor :generate_explicit_type + def decode_typemap=(definedtypes) + @decode_typemap = definedtypes + end + + def initialize(charset) + @charset = charset + @generate_explicit_type = true + @decode_typemap = nil + end + + ### + ## encode interface. + # + # Returns a XML instance as a string. + def encode_data(generator, ns, data, parent) + raise NotImplementError + end + + def encode_data_end(generator, ns, data, parent) + raise NotImplementError + end + + def encode_prologue + end + + def encode_epilogue + end + + ### + ## decode interface. + # + # Returns SOAP/OM data. + def decode_tag(ns, name, attrs, parent) + raise NotImplementError.new('Method decode_tag must be defined in derived class.') + end + + def decode_tag_end(ns, name) + raise NotImplementError.new('Method decode_tag_end must be defined in derived class.') + end + + def decode_text(ns, text) + raise NotImplementError.new('Method decode_text must be defined in derived class.') + end + + def decode_prologue + end + + def decode_epilogue + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/encodingstyle/literalHandler.rb b/ruby_1_8_6/lib/soap/encodingstyle/literalHandler.rb new file mode 100644 index 0000000000..59c7205366 --- /dev/null +++ b/ruby_1_8_6/lib/soap/encodingstyle/literalHandler.rb @@ -0,0 +1,226 @@ +# SOAP4R - XML Literal EncodingStyle handler library +# Copyright (C) 2001, 2003-2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/encodingstyle/handler' + + +module SOAP +module EncodingStyle + + +class LiteralHandler < Handler + Namespace = SOAP::LiteralNamespace + add_handler + + def initialize(charset = nil) + super(charset) + @textbuf = '' + end + + + ### + ## encode interface. + # + def encode_data(generator, ns, data, parent) + attrs = {} + name = generator.encode_name(ns, data, attrs) + data.extraattr.each do |k, v| + # ToDo: check generator.attributeformdefault here + if k.is_a?(XSD::QName) + if k.namespace + SOAPGenerator.assign_ns(attrs, ns, k.namespace) + k = ns.name(k) + else + k = k.name + end + end + attrs[k] = v + end + case data + when SOAPRawString + generator.encode_tag(name, attrs) + generator.encode_rawstring(data.to_s) + when XSD::XSDString + generator.encode_tag(name, attrs) + str = data.to_s + str = XSD::Charset.encoding_to_xml(str, @charset) if @charset + generator.encode_string(str) + when XSD::XSDAnySimpleType + generator.encode_tag(name, attrs) + generator.encode_string(data.to_s) + when SOAPStruct + generator.encode_tag(name, attrs) + data.each do |key, value| + generator.encode_child(ns, value, data) + end + when SOAPArray + generator.encode_tag(name, attrs) + data.traverse do |child, *rank| + data.position = nil + generator.encode_child(ns, child, data) + end + when SOAPElement + # passes 2 times for simplifying namespace definition + data.each do |key, value| + if value.elename.namespace + SOAPGenerator.assign_ns(attrs, ns, value.elename.namespace) + end + end + generator.encode_tag(name, attrs) + generator.encode_rawstring(data.text) if data.text + data.each do |key, value| + generator.encode_child(ns, value, data) + end + else + raise EncodingStyleError.new( + "unknown object:#{data} in this encodingStyle") + end + end + + def encode_data_end(generator, ns, data, parent) + name = generator.encode_name_end(ns, data) + cr = (data.is_a?(SOAPCompoundtype) or + (data.is_a?(SOAPElement) and !data.text)) + generator.encode_tag_end(name, cr) + end + + + ### + ## decode interface. + # + class SOAPTemporalObject + attr_accessor :parent + + def initialize + @parent = nil + end + end + + class SOAPUnknown < SOAPTemporalObject + def initialize(handler, elename, extraattr) + super() + @handler = handler + @elename = elename + @extraattr = extraattr + end + + def as_element + o = SOAPElement.decode(@elename) + o.parent = @parent + o.extraattr.update(@extraattr) + @handler.decode_parent(@parent, o) + o + end + + def as_string + o = SOAPString.decode(@elename) + o.parent = @parent + o.extraattr.update(@extraattr) + @handler.decode_parent(@parent, o) + o + end + + def as_nil + o = SOAPNil.decode(@elename) + o.parent = @parent + o.extraattr.update(@extraattr) + @handler.decode_parent(@parent, o) + o + end + end + + def decode_tag(ns, elename, attrs, parent) + @textbuf = '' + o = SOAPUnknown.new(self, elename, decode_attrs(ns, attrs)) + o.parent = parent + o + end + + def decode_tag_end(ns, node) + o = node.node + if o.is_a?(SOAPUnknown) + newnode = if /\A\s*\z/ =~ @textbuf + o.as_element + else + o.as_string + end + node.replace_node(newnode) + o = node.node + end + + decode_textbuf(o) + @textbuf = '' + end + + def decode_text(ns, text) + # @textbuf is set at decode_tag_end. + @textbuf << text + end + + def decode_attrs(ns, attrs) + extraattr = {} + attrs.each do |key, value| + qname = ns.parse_local(key) + extraattr[qname] = value + end + extraattr + end + + def decode_prologue + end + + def decode_epilogue + end + + def decode_parent(parent, node) + return unless parent.node + case parent.node + when SOAPUnknown + newparent = parent.node.as_element + node.parent = newparent + parent.replace_node(newparent) + decode_parent(parent, node) + when SOAPElement + parent.node.add(node) + node.parent = parent.node + when SOAPStruct + parent.node.add(node.elename.name, node) + node.parent = parent.node + when SOAPArray + if node.position + parent.node[*(decode_arypos(node.position))] = node + parent.node.sparse = true + else + parent.node.add(node) + end + node.parent = parent.node + else + raise EncodingStyleError.new("illegal parent: #{parent.node}") + end + end + +private + + def decode_textbuf(node) + if node.is_a?(XSD::XSDString) + if @charset + node.set(XSD::Charset.encoding_from_xml(@textbuf, @charset)) + else + node.set(@textbuf) + end + else + # Nothing to do... + end + end +end + +LiteralHandler.new + + +end +end diff --git a/ruby_1_8_6/lib/soap/encodingstyle/soapHandler.rb b/ruby_1_8_6/lib/soap/encodingstyle/soapHandler.rb new file mode 100644 index 0000000000..a522392625 --- /dev/null +++ b/ruby_1_8_6/lib/soap/encodingstyle/soapHandler.rb @@ -0,0 +1,582 @@ +# SOAP4R - SOAP EncodingStyle handler library +# Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/encodingstyle/handler' + + +module SOAP +module EncodingStyle + + +class SOAPHandler < Handler + Namespace = SOAP::EncodingNamespace + add_handler + + def initialize(charset = nil) + super(charset) + @refpool = [] + @idpool = [] + @textbuf = '' + @is_first_top_ele = true + end + + + ### + ## encode interface. + # + def encode_data(generator, ns, data, parent) + attrs = encode_attrs(generator, ns, data, parent) + if parent && parent.is_a?(SOAPArray) && parent.position + attrs[ns.name(AttrPositionName)] = "[#{parent.position.join(',')}]" + end + name = generator.encode_name(ns, data, attrs) + case data + when SOAPReference + attrs['href'] = data.refidstr + generator.encode_tag(name, attrs) + when SOAPExternalReference + data.referred + attrs['href'] = data.refidstr + generator.encode_tag(name, attrs) + when SOAPRawString + generator.encode_tag(name, attrs) + generator.encode_rawstring(data.to_s) + when XSD::XSDString + generator.encode_tag(name, attrs) + generator.encode_string(@charset ? + XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s) + when XSD::XSDAnySimpleType + generator.encode_tag(name, attrs) + generator.encode_string(data.to_s) + when SOAPStruct + generator.encode_tag(name, attrs) + data.each do |key, value| + generator.encode_child(ns, value, data) + end + when SOAPArray + generator.encode_tag(name, attrs) + data.traverse do |child, *rank| + data.position = data.sparse ? rank : nil + generator.encode_child(ns, child, data) + end + else + raise EncodingStyleError.new( + "unknown object:#{data} in this encodingStyle") + end + end + + def encode_data_end(generator, ns, data, parent) + name = generator.encode_name_end(ns, data) + cr = data.is_a?(SOAPCompoundtype) + generator.encode_tag_end(name, cr) + end + + + ### + ## decode interface. + # + class SOAPTemporalObject + attr_accessor :parent + attr_accessor :position + attr_accessor :id + attr_accessor :root + + def initialize + @parent = nil + @position = nil + @id = nil + @root = nil + end + end + + class SOAPUnknown < SOAPTemporalObject + attr_reader :type + attr_accessor :definedtype + attr_reader :extraattr + + def initialize(handler, elename, type, extraattr) + super() + @handler = handler + @elename = elename + @type = type + @extraattr = extraattr + @definedtype = nil + end + + def as_struct + o = SOAPStruct.decode(@elename, @type) + o.id = @id + o.root = @root + o.parent = @parent + o.position = @position + o.extraattr.update(@extraattr) + @handler.decode_parent(@parent, o) + o + end + + def as_string + o = SOAPString.decode(@elename) + o.id = @id + o.root = @root + o.parent = @parent + o.position = @position + o.extraattr.update(@extraattr) + @handler.decode_parent(@parent, o) + o + end + + def as_nil + o = SOAPNil.decode(@elename) + o.id = @id + o.root = @root + o.parent = @parent + o.position = @position + o.extraattr.update(@extraattr) + @handler.decode_parent(@parent, o) + o + end + end + + def decode_tag(ns, elename, attrs, parent) + @textbuf = '' + is_nil, type, arytype, root, offset, position, href, id, extraattr = + decode_attrs(ns, attrs) + o = nil + if is_nil + o = SOAPNil.decode(elename) + elsif href + o = SOAPReference.decode(elename, href) + @refpool << o + elsif @decode_typemap + o = decode_tag_by_wsdl(ns, elename, type, parent.node, arytype, extraattr) + else + o = decode_tag_by_type(ns, elename, type, parent.node, arytype, extraattr) + end + + if o.is_a?(SOAPArray) + if offset + o.offset = decode_arypos(offset) + o.sparse = true + else + o.sparse = false + end + end + + o.parent = parent + o.id = id + o.root = root + o.position = position + + unless o.is_a?(SOAPTemporalObject) + @idpool << o if o.id + decode_parent(parent, o) + end + o + end + + def decode_tag_end(ns, node) + o = node.node + if o.is_a?(SOAPUnknown) + newnode = if /\A\s*\z/ =~ @textbuf + o.as_struct + else + o.as_string + end + if newnode.id + @idpool << newnode + end + node.replace_node(newnode) + o = node.node + end + decode_textbuf(o) + # unlink definedtype + o.definedtype = nil + end + + def decode_text(ns, text) + @textbuf << text + end + + def decode_prologue + @refpool.clear + @idpool.clear + @is_first_top_ele = true + end + + def decode_epilogue + decode_resolve_id + end + + def decode_parent(parent, node) + return unless parent.node + case parent.node + when SOAPUnknown + newparent = parent.node.as_struct + node.parent = newparent + if newparent.id + @idpool << newparent + end + parent.replace_node(newparent) + decode_parent(parent, node) + when SOAPStruct + parent.node.add(node.elename.name, node) + node.parent = parent.node + when SOAPArray + if node.position + parent.node[*(decode_arypos(node.position))] = node + parent.node.sparse = true + else + parent.node.add(node) + end + node.parent = parent.node + else + raise EncodingStyleError.new("illegal parent: #{parent.node}") + end + end + +private + + def content_ranksize(typename) + typename.scan(/\[[\d,]*\]$/)[0] + end + + def content_typename(typename) + typename.sub(/\[,*\]$/, '') + end + + def create_arytype(ns, data) + XSD::QName.new(data.arytype.namespace, + content_typename(data.arytype.name) + "[#{data.size.join(',')}]") + end + + def encode_attrs(generator, ns, data, parent) + attrs = {} + return attrs if data.is_a?(SOAPReference) + + if !parent || parent.encodingstyle != EncodingNamespace + if @generate_explicit_type + SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace) + attrs[ns.name(AttrEncodingStyleName)] = EncodingNamespace + end + data.encodingstyle = EncodingNamespace + end + + if data.is_a?(SOAPNil) + attrs[ns.name(XSD::AttrNilName)] = XSD::NilValue + elsif @generate_explicit_type + if data.type.namespace + SOAPGenerator.assign_ns(attrs, ns, data.type.namespace) + end + if data.is_a?(SOAPArray) + if data.arytype.namespace + SOAPGenerator.assign_ns(attrs, ns, data.arytype.namespace) + end + SOAPGenerator.assign_ns(attrs, ns, EncodingNamespace) + attrs[ns.name(AttrArrayTypeName)] = ns.name(create_arytype(ns, data)) + if data.type.name + attrs[ns.name(XSD::AttrTypeName)] = ns.name(data.type) + end + elsif parent && parent.is_a?(SOAPArray) && (parent.arytype == data.type) + # No need to add. + elsif !data.type.namespace + # No need to add. + else + attrs[ns.name(XSD::AttrTypeName)] = ns.name(data.type) + end + end + + data.extraattr.each do |key, value| + SOAPGenerator.assign_ns(attrs, ns, key.namespace) + attrs[ns.name(key)] = encode_attr_value(generator, ns, key, value) + end + if data.id + attrs['id'] = data.id + end + attrs + end + + def encode_attr_value(generator, ns, qname, value) + if value.is_a?(SOAPType) + ref = SOAPReference.new(value) + generator.add_reftarget(qname.name, value) + ref.refidstr + else + value.to_s + end + end + + def decode_tag_by_wsdl(ns, elename, typestr, parent, arytypestr, extraattr) + o = nil + if parent.class == SOAPBody + # root element: should branch by root attribute? + if @is_first_top_ele + # Unqualified name is allowed here. + @is_first_top_ele = false + type = @decode_typemap[elename] || + @decode_typemap.find_name(elename.name) + if type + o = SOAPStruct.new(elename) + o.definedtype = type + return o + end + end + # multi-ref element. + if typestr + typename = ns.parse(typestr) + typedef = @decode_typemap[typename] + if typedef + return decode_definedtype(elename, typename, typedef, arytypestr) + end + end + return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, + extraattr) + end + + if parent.type == XSD::AnyTypeName + return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, + extraattr) + end + + # parent.definedtype == nil means the parent is SOAPUnknown. SOAPUnknown + # is generated by decode_tag_by_type when its type is anyType. + parenttype = parent.definedtype || @decode_typemap[parent.type] + unless parenttype + return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, + extraattr) + end + + definedtype_name = parenttype.child_type(elename) + if definedtype_name and (klass = TypeMap[definedtype_name]) + return decode_basetype(klass, elename) + elsif definedtype_name == XSD::AnyTypeName + return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, + extraattr) + end + + if definedtype_name + typedef = @decode_typemap[definedtype_name] + else + typedef = parenttype.child_defined_complextype(elename) + end + decode_definedtype(elename, definedtype_name, typedef, arytypestr) + end + + def decode_definedtype(elename, typename, typedef, arytypestr) + unless typedef + raise EncodingStyleError.new("unknown type '#{typename}'") + end + if typedef.is_a?(::WSDL::XMLSchema::SimpleType) + decode_defined_simpletype(elename, typename, typedef, arytypestr) + else + decode_defined_complextype(elename, typename, typedef, arytypestr) + end + end + + def decode_basetype(klass, elename) + klass.decode(elename) + end + + def decode_defined_simpletype(elename, typename, typedef, arytypestr) + o = decode_basetype(TypeMap[typedef.base], elename) + o.definedtype = typedef + o + end + + def decode_defined_complextype(elename, typename, typedef, arytypestr) + case typedef.compoundtype + when :TYPE_STRUCT, :TYPE_MAP + o = SOAPStruct.decode(elename, typename) + o.definedtype = typedef + return o + when :TYPE_ARRAY + expected_arytype = typedef.find_arytype + if arytypestr + actual_arytype = XSD::QName.new(expected_arytype.namespace, + content_typename(expected_arytype.name) << + content_ranksize(arytypestr)) + o = SOAPArray.decode(elename, typename, actual_arytype) + else + o = SOAPArray.new(typename, 1, expected_arytype) + o.elename = elename + end + o.definedtype = typedef + return o + when :TYPE_EMPTY + o = SOAPNil.decode(elename) + o.definedtype = typedef + return o + else + raise RuntimeError.new( + "Unknown kind of complexType: #{typedef.compoundtype}") + end + nil + end + + def decode_tag_by_type(ns, elename, typestr, parent, arytypestr, extraattr) + if arytypestr + type = typestr ? ns.parse(typestr) : ValueArrayName + node = SOAPArray.decode(elename, type, ns.parse(arytypestr)) + node.extraattr.update(extraattr) + return node + end + + type = nil + if typestr + type = ns.parse(typestr) + elsif parent.is_a?(SOAPArray) + type = parent.arytype + else + # Since it's in dynamic(without any type) encoding process, + # assumes entity as its type itself. + # => type Array in SOAP-ENC. + # => type Country in foo. + type = elename + end + + if (klass = TypeMap[type]) + node = decode_basetype(klass, elename) + node.extraattr.update(extraattr) + return node + end + + # Unknown type... Struct or String + SOAPUnknown.new(self, elename, type, extraattr) + end + + def decode_textbuf(node) + case node + when XSD::XSDHexBinary, XSD::XSDBase64Binary + node.set_encoded(@textbuf) + when XSD::XSDString + if @charset + @textbuf = XSD::Charset.encoding_from_xml(@textbuf, @charset) + end + if node.definedtype + node.definedtype.check_lexical_format(@textbuf) + end + node.set(@textbuf) + when SOAPNil + # Nothing to do. + when SOAPBasetype + node.set(@textbuf) + else + # Nothing to do... + end + @textbuf = '' + end + + NilLiteralMap = { + 'true' => true, + '1' => true, + 'false' => false, + '0' => false + } + RootLiteralMap = { + '1' => 1, + '0' => 0 + } + def decode_attrs(ns, attrs) + is_nil = false + type = nil + arytype = nil + root = nil + offset = nil + position = nil + href = nil + id = nil + extraattr = {} + + attrs.each do |key, value| + qname = ns.parse(key) + case qname.namespace + when XSD::InstanceNamespace + case qname.name + when XSD::NilLiteral + is_nil = NilLiteralMap[value] or + raise EncodingStyleError.new("cannot accept attribute value: #{value} as the value of xsi:#{XSD::NilLiteral} (expected 'true', 'false', '1', or '0')") + next + when XSD::AttrType + type = value + next + end + when EncodingNamespace + case qname.name + when AttrArrayType + arytype = value + next + when AttrRoot + root = RootLiteralMap[value] or + raise EncodingStyleError.new( + "illegal root attribute value: #{value}") + next + when AttrOffset + offset = value + next + when AttrPosition + position = value + next + end + end + if key == 'href' + href = value + next + elsif key == 'id' + id = value + next + end + qname = ns.parse_local(key) + extraattr[qname] = decode_attr_value(ns, qname, value) + end + + return is_nil, type, arytype, root, offset, position, href, id, extraattr + end + + def decode_attr_value(ns, qname, value) + if /\A#/ =~ value + o = SOAPReference.decode(nil, value) + @refpool << o + o + else + value + end + end + + def decode_arypos(position) + /^\[(.+)\]$/ =~ position + $1.split(',').collect { |s| s.to_i } + end + + def decode_resolve_id + count = @refpool.length # To avoid infinite loop + while !@refpool.empty? && count > 0 + @refpool = @refpool.find_all { |ref| + o = @idpool.find { |item| + item.id == ref.refid + } + if o.is_a?(SOAPReference) + true # link of link. + elsif o + ref.__setobj__(o) + false + elsif o = ref.rootnode.external_content[ref.refid] + ref.__setobj__(o) + false + else + raise EncodingStyleError.new("unresolved reference: #{ref.refid}") + end + } + count -= 1 + end + end +end + +SOAPHandler.new + + +end +end diff --git a/ruby_1_8_6/lib/soap/generator.rb b/ruby_1_8_6/lib/soap/generator.rb new file mode 100644 index 0000000000..f179555e1d --- /dev/null +++ b/ruby_1_8_6/lib/soap/generator.rb @@ -0,0 +1,268 @@ +# SOAP4R - SOAP XML Instance Generator library. +# Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'xsd/ns' +require 'soap/soap' +require 'soap/baseData' +require 'soap/encodingstyle/handler' + + +module SOAP + + +### +## CAUTION: MT-unsafe +# +class SOAPGenerator + include SOAP + + class FormatEncodeError < Error; end + +public + + attr_accessor :charset + attr_accessor :default_encodingstyle + attr_accessor :generate_explicit_type + attr_accessor :use_numeric_character_reference + + def initialize(opt = {}) + @reftarget = nil + @handlers = {} + @charset = opt[:charset] || XSD::Charset.xml_encoding_label + @default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace + @generate_explicit_type = + opt.key?(:generate_explicit_type) ? opt[:generate_explicit_type] : true + @elementformdefault = opt[:elementformdefault] + @attributeformdefault = opt[:attributeformdefault] + @use_numeric_character_reference = opt[:use_numeric_character_reference] + @indentstr = opt[:no_indent] ? '' : ' ' + @buf = @indent = @curr = nil + end + + def generate(obj, io = nil) + @buf = io || '' + @indent = '' + + prologue + @handlers.each do |uri, handler| + handler.encode_prologue + end + + ns = XSD::NS.new + @buf << xmldecl + encode_data(ns, obj, nil) + + @handlers.each do |uri, handler| + handler.encode_epilogue + end + epilogue + + @buf + end + + def encode_data(ns, obj, parent) + if obj.is_a?(SOAPEnvelopeElement) + encode_element(ns, obj, parent) + return + end + if @reftarget && !obj.precedents.empty? + add_reftarget(obj.elename.name, obj) + ref = SOAPReference.new(obj) + ref.elename = ref.elename.dup_name(obj.elename.name) + obj.precedents.clear # Avoid cyclic delay. + obj.encodingstyle = parent.encodingstyle + # SOAPReference is encoded here. + obj = ref + end + encodingstyle = obj.encodingstyle + # Children's encodingstyle is derived from its parent. + encodingstyle ||= parent.encodingstyle if parent + obj.encodingstyle = encodingstyle + handler = find_handler(encodingstyle || @default_encodingstyle) + unless handler + raise FormatEncodeError.new("Unknown encodingStyle: #{ encodingstyle }.") + end + if !obj.elename.name + raise FormatEncodeError.new("Element name not defined: #{ obj }.") + end + handler.encode_data(self, ns, obj, parent) + handler.encode_data_end(self, ns, obj, parent) + end + + def add_reftarget(name, node) + unless @reftarget + raise FormatEncodeError.new("Reftarget is not defined.") + end + @reftarget.add(name, node) + end + + def encode_child(ns, child, parent) + indent_backup, @indent = @indent, @indent + @indentstr + encode_data(ns.clone_ns, child, parent) + @indent = indent_backup + end + + def encode_element(ns, obj, parent) + attrs = {} + if obj.is_a?(SOAPBody) + @reftarget = obj + obj.encode(self, ns, attrs) do |child| + indent_backup, @indent = @indent, @indent + @indentstr + encode_data(ns.clone_ns, child, obj) + @indent = indent_backup + end + @reftarget = nil + else + if obj.is_a?(SOAPEnvelope) + # xsi:nil="true" can appear even if dumping without explicit type. + SOAPGenerator.assign_ns(attrs, ns, + XSD::InstanceNamespace, XSINamespaceTag) + if @generate_explicit_type + SOAPGenerator.assign_ns(attrs, ns, XSD::Namespace, XSDNamespaceTag) + end + end + obj.encode(self, ns, attrs) do |child| + indent_backup, @indent = @indent, @indent + @indentstr + encode_data(ns.clone_ns, child, obj) + @indent = indent_backup + end + end + end + + def encode_name(ns, data, attrs) + if element_local?(data) + data.elename.name + else + if element_qualified?(data) + SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace, '') + else + SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace) + end + ns.name(data.elename) + end + end + + def encode_name_end(ns, data) + if element_local?(data) + data.elename.name + else + ns.name(data.elename) + end + end + + def encode_tag(elename, attrs = nil) + if !attrs or attrs.empty? + @buf << "\n#{ @indent }<#{ elename }>" + elsif attrs.size == 1 + key, value = attrs.shift + @buf << %Q[\n#{ @indent }<#{ elename } #{ key }="#{ value }">] + else + @buf << "\n#{ @indent }<#{ elename } " << + attrs.collect { |key, value| + %Q[#{ key }="#{ value }"] + }.join("\n#{ @indent }#{ @indentstr * 2 }") << + '>' + end + end + + def encode_tag_end(elename, cr = nil) + if cr + @buf << "\n#{ @indent }" + else + @buf << "" + end + end + + def encode_rawstring(str) + @buf << str + end + + EncodeMap = { + '&' => '&', + '<' => '<', + '>' => '>', + '"' => '"', + '\'' => ''', + "\r" => ' ' + } + EncodeCharRegexp = Regexp.new("[#{EncodeMap.keys.join}]") + def encode_string(str) + if @use_numeric_character_reference and !XSD::Charset.is_us_ascii(str) + str.gsub!(EncodeCharRegexp) { |c| EncodeMap[c] } + @buf << str.unpack("U*").collect { |c| + if c == 0x9 or c == 0xa or c == 0xd or (c >= 0x20 and c <= 0x7f) + c.chr + else + sprintf("&#x%x;", c) + end + }.join + else + @buf << str.gsub(EncodeCharRegexp) { |c| EncodeMap[c] } + end + end + + def element_local?(element) + element.elename.namespace.nil? + end + + def element_qualified?(element) + if element.respond_to?(:qualified) + if element.qualified.nil? + @elementformdefault + else + element.qualified + end + else + @elementformdefault + end + end + + def self.assign_ns(attrs, ns, namespace, tag = nil) + if namespace.nil? + raise FormatEncodeError.new("empty namespace") + end + unless ns.assigned?(namespace) + tag = ns.assign(namespace, tag) + if tag == '' + attr = 'xmlns' + else + attr = "xmlns:#{tag}" + end + attrs[attr] = namespace + end + end + +private + + def prologue + end + + def epilogue + end + + def find_handler(encodingstyle) + unless @handlers.key?(encodingstyle) + handler = SOAP::EncodingStyle::Handler.handler(encodingstyle).new(@charset) + handler.generate_explicit_type = @generate_explicit_type + handler.encode_prologue + @handlers[encodingstyle] = handler + end + @handlers[encodingstyle] + end + + def xmldecl + if @charset + %Q[] + else + %Q[] + end + end +end + + +end diff --git a/ruby_1_8_6/lib/soap/header/handler.rb b/ruby_1_8_6/lib/soap/header/handler.rb new file mode 100644 index 0000000000..7da2836e24 --- /dev/null +++ b/ruby_1_8_6/lib/soap/header/handler.rb @@ -0,0 +1,57 @@ +# SOAP4R - SOAP Header handler item +# Copyright (C) 2003, 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/element' + + +module SOAP +module Header + + +class Handler + attr_reader :elename + attr_reader :mustunderstand + attr_reader :encodingstyle + + def initialize(elename) + @elename = elename + @mustunderstand = false + @encodingstyle = nil + end + + # Should return a SOAP/OM, a SOAPHeaderItem or nil. + def on_outbound + nil + end + + # Given header is a SOAPHeaderItem or nil. + def on_inbound(header, mustunderstand = false) + # do something. + end + + def on_outbound_headeritem + item = on_outbound + if item.nil? + nil + elsif item.is_a?(::SOAP::SOAPHeaderItem) + item.elename = @elename + item + else + item.elename = @elename + ::SOAP::SOAPHeaderItem.new(item, @mustunderstand, @encodingstyle) + end + end + + def on_inbound_headeritem(header) + on_inbound(header.element, header.mustunderstand) + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/header/handlerset.rb b/ruby_1_8_6/lib/soap/header/handlerset.rb new file mode 100644 index 0000000000..a8eee03023 --- /dev/null +++ b/ruby_1_8_6/lib/soap/header/handlerset.rb @@ -0,0 +1,70 @@ +# SOAP4R - SOAP Header handler set +# Copyright (C) 2003, 2004 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'xsd/namedelements' + + +module SOAP +module Header + + +class HandlerSet + def initialize + @store = XSD::NamedElements.new + end + + def dup + obj = HandlerSet.new + obj.store = @store.dup + obj + end + + def add(handler) + @store << handler + end + alias << add + + def delete(handler) + @store.delete(handler) + end + + def include?(handler) + @store.include?(handler) + end + + # returns: Array of SOAPHeaderItem + def on_outbound + @store.collect { |handler| + handler.on_outbound_headeritem + }.compact + end + + # headers: SOAPHeaderItem enumerable object + def on_inbound(headers) + headers.each do |name, item| + handler = @store.find { |handler| + handler.elename == item.element.elename + } + if handler + handler.on_inbound_headeritem(item) + elsif item.mustunderstand + raise UnhandledMustUnderstandHeaderError.new(item.element.elename.to_s) + end + end + end + +protected + + def store=(store) + @store = store + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/header/simplehandler.rb b/ruby_1_8_6/lib/soap/header/simplehandler.rb new file mode 100644 index 0000000000..7b206f77db --- /dev/null +++ b/ruby_1_8_6/lib/soap/header/simplehandler.rb @@ -0,0 +1,44 @@ +# SOAP4R - SOAP Simple header item handler +# Copyright (C) 2003-2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/header/handler' +require 'soap/baseData' + + +module SOAP +module Header + + +class SimpleHandler < SOAP::Header::Handler + def initialize(elename) + super(elename) + end + + # Should return a Hash, String or nil. + def on_simple_outbound + nil + end + + # Given header is a Hash, String or nil. + def on_simple_inbound(header, mustunderstand) + end + + def on_outbound + h = on_simple_outbound + h ? SOAPElement.from_obj(h, elename.namespace) : nil + end + + def on_inbound(header, mustunderstand) + h = header.respond_to?(:to_obj) ? header.to_obj : header.data + on_simple_inbound(h, mustunderstand) + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/httpconfigloader.rb b/ruby_1_8_6/lib/soap/httpconfigloader.rb new file mode 100644 index 0000000000..cd7bca8a65 --- /dev/null +++ b/ruby_1_8_6/lib/soap/httpconfigloader.rb @@ -0,0 +1,119 @@ +# SOAP4R - HTTP config loader. +# Copyright (C) 2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/property' + + +module SOAP + + +module HTTPConfigLoader +module_function + + def set_options(client, options) + client.proxy = options["proxy"] + options.add_hook("proxy") do |key, value| + client.proxy = value + end + client.no_proxy = options["no_proxy"] + options.add_hook("no_proxy") do |key, value| + client.no_proxy = value + end + if client.respond_to?(:protocol_version=) + client.protocol_version = options["protocol_version"] + options.add_hook("protocol_version") do |key, value| + client.protocol_version = value + end + end + ssl_config = options["ssl_config"] ||= ::SOAP::Property.new + set_ssl_config(client, ssl_config) + ssl_config.add_hook(true) do |key, value| + set_ssl_config(client, ssl_config) + end + basic_auth = options["basic_auth"] ||= ::SOAP::Property.new + set_basic_auth(client, basic_auth) + basic_auth.add_hook do |key, value| + set_basic_auth(client, basic_auth) + end + options.add_hook("connect_timeout") do |key, value| + client.connect_timeout = value + end + options.add_hook("send_timeout") do |key, value| + client.send_timeout = value + end + options.add_hook("receive_timeout") do |key, value| + client.receive_timeout = value + end + end + + def set_basic_auth(client, basic_auth) + basic_auth.values.each do |url, userid, passwd| + client.set_basic_auth(url, userid, passwd) + end + end + + def set_ssl_config(client, ssl_config) + ssl_config.each do |key, value| + cfg = client.ssl_config + if cfg.nil? + raise NotImplementedError.new("SSL not supported") + end + case key + when 'client_cert' + cfg.client_cert = cert_from_file(value) + when 'client_key' + cfg.client_key = key_from_file(value) + when 'client_ca' + cfg.client_ca = value + when 'ca_path' + cfg.set_trust_ca(value) + when 'ca_file' + cfg.set_trust_ca(value) + when 'crl' + cfg.set_crl(value) + when 'verify_mode' + cfg.verify_mode = ssl_config_int(value) + when 'verify_depth' + cfg.verify_depth = ssl_config_int(value) + when 'options' + cfg.options = value + when 'ciphers' + cfg.ciphers = value + when 'verify_callback' + cfg.verify_callback = value + when 'cert_store' + cfg.cert_store = value + else + raise ArgumentError.new("unknown ssl_config property #{key}") + end + end + end + + def ssl_config_int(value) + if value.nil? or value.to_s.empty? + nil + else + begin + Integer(value) + rescue ArgumentError + ::SOAP::Property::Util.const_from_name(value.to_s) + end + end + end + + def cert_from_file(filename) + OpenSSL::X509::Certificate.new(File.open(filename) { |f| f.read }) + end + + def key_from_file(filename) + OpenSSL::PKey::RSA.new(File.open(filename) { |f| f.read }) + end +end + + +end diff --git a/ruby_1_8_6/lib/soap/mapping.rb b/ruby_1_8_6/lib/soap/mapping.rb new file mode 100644 index 0000000000..b83f8b484a --- /dev/null +++ b/ruby_1_8_6/lib/soap/mapping.rb @@ -0,0 +1,10 @@ +# SOAP4R - Ruby type mapping utility. +# Copyright (C) 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/mapping/mapping' +require 'soap/mapping/registry' diff --git a/ruby_1_8_6/lib/soap/mapping/factory.rb b/ruby_1_8_6/lib/soap/mapping/factory.rb new file mode 100644 index 0000000000..978b303b3d --- /dev/null +++ b/ruby_1_8_6/lib/soap/mapping/factory.rb @@ -0,0 +1,355 @@ +# SOAP4R - Mapping factory. +# Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +module SOAP +module Mapping + + +class Factory + include TraverseSupport + + def initialize + # nothing to do + end + + def obj2soap(soap_class, obj, info, map) + raise NotImplementError.new + # return soap_obj + end + + def soap2obj(obj_class, node, info, map) + raise NotImplementError.new + # return convert_succeeded_or_not, obj + end + + def setiv2obj(obj, node, map) + return if node.nil? + if obj.is_a?(Array) + setiv2ary(obj, node, map) + else + setiv2struct(obj, node, map) + end + end + + def setiv2soap(node, obj, map) + if obj.class.class_variables.include?('@@schema_element') + obj.class.class_eval('@@schema_element').each do |name, info| + type, qname = info + if qname + elename = qname.name + else + elename = Mapping.name2elename(name) + end + node.add(elename, + Mapping._obj2soap(obj.instance_variable_get('@' + name), map)) + end + else + # should we sort instance_variables? + obj.instance_variables.each do |var| + name = var.sub(/^@/, '') + elename = Mapping.name2elename(name) + node.add(elename, + Mapping._obj2soap(obj.instance_variable_get(var), map)) + end + end + end + +private + + def setiv2ary(obj, node, map) + node.each do |name, value| + Array.instance_method(:<<).bind(obj).call(Mapping._soap2obj(value, map)) + end + end + + def setiv2struct(obj, node, map) + vars = {} + node.each do |name, value| + vars[Mapping.elename2name(name)] = Mapping._soap2obj(value, map) + end + Mapping.set_attributes(obj, vars) + end +end + +class StringFactory_ < Factory + def initialize(allow_original_mapping = false) + super() + @allow_original_mapping = allow_original_mapping + end + + def obj2soap(soap_class, obj, info, map) + if !@allow_original_mapping and !obj.instance_variables.empty? + return nil + end + begin + unless XSD::Charset.is_ces(obj, Thread.current[:SOAPExternalCES]) + return nil + end + encoded = XSD::Charset.encoding_conv(obj, + Thread.current[:SOAPExternalCES], XSD::Charset.encoding) + soap_obj = soap_class.new(encoded) + rescue XSD::ValueSpaceError + return nil + end + mark_marshalled_obj(obj, soap_obj) + soap_obj + end + + def soap2obj(obj_class, node, info, map) + obj = Mapping.create_empty_object(obj_class) + decoded = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding, + Thread.current[:SOAPExternalCES]) + obj.replace(decoded) + mark_unmarshalled_obj(node, obj) + return true, obj + end +end + +class BasetypeFactory_ < Factory + def initialize(allow_original_mapping = false) + super() + @allow_original_mapping = allow_original_mapping + end + + def obj2soap(soap_class, obj, info, map) + if !@allow_original_mapping and !obj.instance_variables.empty? + return nil + end + soap_obj = nil + begin + soap_obj = soap_class.new(obj) + rescue XSD::ValueSpaceError + return nil + end + if @allow_original_mapping + # Basetype except String should not be multiref-ed in SOAP/1.1. + mark_marshalled_obj(obj, soap_obj) + end + soap_obj + end + + def soap2obj(obj_class, node, info, map) + obj = node.data + mark_unmarshalled_obj(node, obj) + return true, obj + end +end + +class DateTimeFactory_ < Factory + def initialize(allow_original_mapping = false) + super() + @allow_original_mapping = allow_original_mapping + end + + def obj2soap(soap_class, obj, info, map) + if !@allow_original_mapping and + Time === obj and !obj.instance_variables.empty? + return nil + end + soap_obj = nil + begin + soap_obj = soap_class.new(obj) + rescue XSD::ValueSpaceError + return nil + end + mark_marshalled_obj(obj, soap_obj) + soap_obj + end + + def soap2obj(obj_class, node, info, map) + if node.respond_to?(:to_obj) + obj = node.to_obj(obj_class) + return false if obj.nil? + mark_unmarshalled_obj(node, obj) + return true, obj + else + return false + end + end +end + +class Base64Factory_ < Factory + def obj2soap(soap_class, obj, info, map) + return nil unless obj.instance_variables.empty? + soap_obj = soap_class.new(obj) + mark_marshalled_obj(obj, soap_obj) if soap_obj + soap_obj + end + + def soap2obj(obj_class, node, info, map) + obj = node.string + mark_unmarshalled_obj(node, obj) + return true, obj + end +end + +class URIFactory_ < Factory + def obj2soap(soap_class, obj, info, map) + soap_obj = soap_class.new(obj) + mark_marshalled_obj(obj, soap_obj) if soap_obj + soap_obj + end + + def soap2obj(obj_class, node, info, map) + obj = node.data + mark_unmarshalled_obj(node, obj) + return true, obj + end +end + +class ArrayFactory_ < Factory + def initialize(allow_original_mapping = false) + super() + @allow_original_mapping = allow_original_mapping + end + + # [[1], [2]] is converted to Array of Array, not 2-D Array. + # To create M-D Array, you must call Mapping.ary2md. + def obj2soap(soap_class, obj, info, map) + if !@allow_original_mapping and !obj.instance_variables.empty? + return nil + end + arytype = Mapping.obj2element(obj) + if arytype.name + arytype.namespace ||= RubyTypeNamespace + else + arytype = XSD::AnyTypeName + end + soap_obj = SOAPArray.new(ValueArrayName, 1, arytype) + mark_marshalled_obj(obj, soap_obj) + obj.each do |item| + soap_obj.add(Mapping._obj2soap(item, map)) + end + soap_obj + end + + def soap2obj(obj_class, node, info, map) + obj = Mapping.create_empty_object(obj_class) + mark_unmarshalled_obj(node, obj) + node.soap2array(obj) do |elem| + elem ? Mapping._soap2obj(elem, map) : nil + end + return true, obj + end +end + +class TypedArrayFactory_ < Factory + def initialize(allow_original_mapping = false) + super() + @allow_original_mapping = allow_original_mapping + end + + def obj2soap(soap_class, obj, info, map) + if !@allow_original_mapping and !obj.instance_variables.empty? + return nil + end + arytype = info[:type] || info[0] + soap_obj = SOAPArray.new(ValueArrayName, 1, arytype) + mark_marshalled_obj(obj, soap_obj) + obj.each do |var| + soap_obj.add(Mapping._obj2soap(var, map)) + end + soap_obj + end + + def soap2obj(obj_class, node, info, map) + if node.rank > 1 + return false + end + arytype = info[:type] || info[0] + unless node.arytype == arytype + return false + end + obj = Mapping.create_empty_object(obj_class) + mark_unmarshalled_obj(node, obj) + node.soap2array(obj) do |elem| + elem ? Mapping._soap2obj(elem, map) : nil + end + return true, obj + end +end + +class TypedStructFactory_ < Factory + def obj2soap(soap_class, obj, info, map) + type = info[:type] || info[0] + soap_obj = soap_class.new(type) + mark_marshalled_obj(obj, soap_obj) + if obj.class <= SOAP::Marshallable + setiv2soap(soap_obj, obj, map) + else + setiv2soap(soap_obj, obj, map) + end + soap_obj + end + + def soap2obj(obj_class, node, info, map) + type = info[:type] || info[0] + unless node.type == type + return false + end + obj = Mapping.create_empty_object(obj_class) + mark_unmarshalled_obj(node, obj) + setiv2obj(obj, node, map) + return true, obj + end +end + +MapQName = XSD::QName.new(ApacheSOAPTypeNamespace, 'Map') +class HashFactory_ < Factory + def initialize(allow_original_mapping = false) + super() + @allow_original_mapping = allow_original_mapping + end + + def obj2soap(soap_class, obj, info, map) + if !@allow_original_mapping and !obj.instance_variables.empty? + return nil + end + if !obj.default.nil? or + (obj.respond_to?(:default_proc) and obj.default_proc) + return nil + end + soap_obj = SOAPStruct.new(MapQName) + mark_marshalled_obj(obj, soap_obj) + obj.each do |key, value| + elem = SOAPStruct.new + elem.add("key", Mapping._obj2soap(key, map)) + elem.add("value", Mapping._obj2soap(value, map)) + # ApacheAxis allows only 'item' here. + soap_obj.add("item", elem) + end + soap_obj + end + + def soap2obj(obj_class, node, info, map) + unless node.type == MapQName + return false + end + if node.class == SOAPStruct and node.key?('default') + return false + end + obj = Mapping.create_empty_object(obj_class) + mark_unmarshalled_obj(node, obj) + if node.class == SOAPStruct + node.each do |key, value| + obj[Mapping._soap2obj(value['key'], map)] = + Mapping._soap2obj(value['value'], map) + end + else + node.each do |value| + obj[Mapping._soap2obj(value['key'], map)] = + Mapping._soap2obj(value['value'], map) + end + end + return true, obj + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/mapping/mapping.rb b/ruby_1_8_6/lib/soap/mapping/mapping.rb new file mode 100644 index 0000000000..65d6bb4d5b --- /dev/null +++ b/ruby_1_8_6/lib/soap/mapping/mapping.rb @@ -0,0 +1,381 @@ +# SOAP4R - Ruby type mapping utility. +# Copyright (C) 2000, 2001, 2003-2005 NAKAMURA Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'xsd/codegen/gensupport' + + +module SOAP + + +module Mapping + RubyTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/1.6' + RubyTypeInstanceNamespace = + 'http://www.ruby-lang.org/xmlns/ruby/type-instance' + RubyCustomTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/custom' + ApacheSOAPTypeNamespace = 'http://xml.apache.org/xml-soap' + + + # TraverseSupport breaks following thread variables. + # Thread.current[:SOAPMarshalDataKey] + module TraverseSupport + def mark_marshalled_obj(obj, soap_obj) + raise if obj.nil? + Thread.current[:SOAPMarshalDataKey][obj.__id__] = soap_obj + end + + def mark_unmarshalled_obj(node, obj) + return if obj.nil? + # node.id is not Object#id but SOAPReference#id + Thread.current[:SOAPMarshalDataKey][node.id] = obj + end + end + + + EMPTY_OPT = {} + def self.obj2soap(obj, registry = nil, type = nil, opt = EMPTY_OPT) + registry ||= Mapping::DefaultRegistry + soap_obj = nil + protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do + Thread.current[:SOAPMarshalDataKey] = {} + Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE + Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] + soap_obj = _obj2soap(obj, registry, type) + end + soap_obj + end + + def self.soap2obj(node, registry = nil, klass = nil, opt = EMPTY_OPT) + registry ||= Mapping::DefaultRegistry + obj = nil + protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do + Thread.current[:SOAPMarshalDataKey] = {} + Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE + Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] + obj = _soap2obj(node, registry, klass) + end + obj + end + + def self.ary2soap(ary, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil, opt = EMPTY_OPT) + registry ||= Mapping::DefaultRegistry + type = XSD::QName.new(type_ns, typename) + soap_ary = SOAPArray.new(ValueArrayName, 1, type) + protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do + Thread.current[:SOAPMarshalDataKey] = {} + Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE + Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] + ary.each do |ele| + soap_ary.add(_obj2soap(ele, registry, type)) + end + end + soap_ary + end + + def self.ary2md(ary, rank, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil, opt = EMPTY_OPT) + registry ||= Mapping::DefaultRegistry + type = XSD::QName.new(type_ns, typename) + md_ary = SOAPArray.new(ValueArrayName, rank, type) + protect_threadvars(:SOAPMarshalDataKey, :SOAPExternalCES, :SOAPMarshalNoReference) do + Thread.current[:SOAPMarshalDataKey] = {} + Thread.current[:SOAPExternalCES] = opt[:external_ces] || $KCODE + Thread.current[:SOAPMarshalNoReference] = opt[:no_reference] + add_md_ary(md_ary, ary, [], registry) + end + md_ary + end + + def self.fault2exception(fault, registry = nil) + registry ||= Mapping::DefaultRegistry + detail = if fault.detail + soap2obj(fault.detail, registry) || "" + else + "" + end + if detail.is_a?(Mapping::SOAPException) + begin + e = detail.to_e + remote_backtrace = e.backtrace + e.set_backtrace(nil) + raise e # ruby sets current caller as local backtrace of e => e2. + rescue Exception => e + e.set_backtrace(remote_backtrace + e.backtrace[1..-1]) + raise + end + else + fault.detail = detail + fault.set_backtrace( + if detail.is_a?(Array) + detail + else + [detail.to_s] + end + ) + raise + end + end + + def self._obj2soap(obj, registry, type = nil) + if referent = Thread.current[:SOAPMarshalDataKey][obj.__id__] and + !Thread.current[:SOAPMarshalNoReference] + SOAPReference.new(referent) + elsif registry + registry.obj2soap(obj, type) + else + raise MappingError.new("no mapping registry given") + end + end + + def self._soap2obj(node, registry, klass = nil) + if node.nil? + return nil + elsif node.is_a?(SOAPReference) + target = node.__getobj__ + # target.id is not Object#id but SOAPReference#id + if referent = Thread.current[:SOAPMarshalDataKey][target.id] and + !Thread.current[:SOAPMarshalNoReference] + return referent + else + return _soap2obj(target, registry, klass) + end + end + return registry.soap2obj(node, klass) + end + + if Object.respond_to?(:allocate) + # ruby/1.7 or later. + def self.create_empty_object(klass) + klass.allocate + end + else + MARSHAL_TAG = { + String => ['"', 1], + Regexp => ['/', 2], + Array => ['[', 1], + Hash => ['{', 1] + } + def self.create_empty_object(klass) + if klass <= Struct + name = klass.name + return ::Marshal.load(sprintf("\004\006S:%c%s\000", name.length + 5, name)) + end + if MARSHAL_TAG.has_key?(klass) + tag, terminate = MARSHAL_TAG[klass] + return ::Marshal.load(sprintf("\004\006%s%s", tag, "\000" * terminate)) + end + MARSHAL_TAG.each do |k, v| + if klass < k + name = klass.name + tag, terminate = v + return ::Marshal.load(sprintf("\004\006C:%c%s%s%s", name.length + 5, name, tag, "\000" * terminate)) + end + end + name = klass.name + ::Marshal.load(sprintf("\004\006o:%c%s\000", name.length + 5, name)) + end + end + + # Allow only (Letter | '_') (Letter | Digit | '-' | '_')* here. + # Caution: '.' is not allowed here. + # To follow XML spec., it should be NCName. + # (denied chars) => .[0-F][0-F] + # ex. a.b => a.2eb + # + def self.name2elename(name) + name.gsub(/([^a-zA-Z0-9:_\-]+)/n) { + '.' << $1.unpack('H2' * $1.size).join('.') + }.gsub(/::/n, '..') + end + + def self.elename2name(name) + name.gsub(/\.\./n, '::').gsub(/((?:\.[0-9a-fA-F]{2})+)/n) { + [$1.delete('.')].pack('H*') + } + end + + def self.const_from_name(name, lenient = false) + const = ::Object + name.sub(/\A::/, '').split('::').each do |const_str| + if XSD::CodeGen::GenSupport.safeconstname?(const_str) + if const.const_defined?(const_str) + const = const.const_get(const_str) + next + end + elsif lenient + const_str = XSD::CodeGen::GenSupport.safeconstname(const_str) + if const.const_defined?(const_str) + const = const.const_get(const_str) + next + end + end + return nil + end + const + end + + def self.class_from_name(name, lenient = false) + const = const_from_name(name, lenient) + if const.is_a?(::Class) + const + else + nil + end + end + + def self.module_from_name(name, lenient = false) + const = const_from_name(name, lenient) + if const.is_a?(::Module) + const + else + nil + end + end + + def self.class2qname(klass) + name = schema_type_definition(klass) + namespace = schema_ns_definition(klass) + XSD::QName.new(namespace, name) + end + + def self.class2element(klass) + type = Mapping.class2qname(klass) + type.name ||= Mapping.name2elename(klass.name) + type.namespace ||= RubyCustomTypeNamespace + type + end + + def self.obj2element(obj) + name = namespace = nil + ivars = obj.instance_variables + if ivars.include?('@schema_type') + name = obj.instance_variable_get('@schema_type') + end + if ivars.include?('@schema_ns') + namespace = obj.instance_variable_get('@schema_ns') + end + if !name or !namespace + class2qname(obj.class) + else + XSD::QName.new(namespace, name) + end + end + + def self.define_singleton_method(obj, name, &block) + sclass = (class << obj; self; end) + sclass.class_eval { + define_method(name, &block) + } + end + + def self.get_attribute(obj, attr_name) + if obj.is_a?(::Hash) + obj[attr_name] || obj[attr_name.intern] + else + name = XSD::CodeGen::GenSupport.safevarname(attr_name) + if obj.instance_variables.include?('@' + name) + obj.instance_variable_get('@' + name) + elsif ((obj.is_a?(::Struct) or obj.is_a?(Marshallable)) and + obj.respond_to?(name)) + obj.__send__(name) + end + end + end + + def self.set_attributes(obj, values) + if obj.is_a?(::SOAP::Mapping::Object) + values.each do |attr_name, value| + obj.__add_xmlele_value(attr_name, value) + end + else + values.each do |attr_name, value| + name = XSD::CodeGen::GenSupport.safevarname(attr_name) + setter = name + "=" + if obj.respond_to?(setter) + obj.__send__(setter, value) + else + obj.instance_variable_set('@' + name, value) + begin + define_attr_accessor(obj, name, + proc { instance_variable_get('@' + name) }, + proc { |value| instance_variable_set('@' + name, value) }) + rescue TypeError + # singleton class may not exist (e.g. Float) + end + end + end + end + end + + def self.define_attr_accessor(obj, name, getterproc, setterproc = nil) + define_singleton_method(obj, name, &getterproc) + define_singleton_method(obj, name + '=', &setterproc) if setterproc + end + + def self.schema_type_definition(klass) + class_schema_variable(:schema_type, klass) + end + + def self.schema_ns_definition(klass) + class_schema_variable(:schema_ns, klass) + end + + def self.schema_element_definition(klass) + schema_element = class_schema_variable(:schema_element, klass) or return nil + schema_ns = schema_ns_definition(klass) + elements = [] + as_array = [] + schema_element.each do |varname, definition| + class_name, name = definition + if /\[\]$/ =~ class_name + class_name = class_name.sub(/\[\]$/, '') + as_array << (name ? name.name : varname) + end + elements << [name || XSD::QName.new(schema_ns, varname), class_name] + end + [elements, as_array] + end + + def self.schema_attribute_definition(klass) + class_schema_variable(:schema_attribute, klass) + end + + class << Mapping + private + + def class_schema_variable(sym, klass) + var = "@@#{sym}" + klass.class_variables.include?(var) ? klass.class_eval(var) : nil + end + + def protect_threadvars(*symbols) + backup = {} + begin + symbols.each do |sym| + backup[sym] = Thread.current[sym] + end + yield + ensure + symbols.each do |sym| + Thread.current[sym] = backup[sym] + end + end + end + + def add_md_ary(md_ary, ary, indices, registry) + for idx in 0..(ary.size - 1) + if ary[idx].is_a?(Array) + add_md_ary(md_ary, ary[idx], indices + [idx], registry) + else + md_ary[*(indices + [idx])] = _obj2soap(ary[idx], registry) + end + end + end + end +end + + +end diff --git a/ruby_1_8_6/lib/soap/mapping/registry.rb b/ruby_1_8_6/lib/soap/mapping/registry.rb new file mode 100644 index 0000000000..823e80666d --- /dev/null +++ b/ruby_1_8_6/lib/soap/mapping/registry.rb @@ -0,0 +1,541 @@ +# SOAP4R - Mapping registry. +# Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/baseData' +require 'soap/mapping/mapping' +require 'soap/mapping/typeMap' +require 'soap/mapping/factory' +require 'soap/mapping/rubytypeFactory' + + +module SOAP + + +module Marshallable + # @@type_ns = Mapping::RubyCustomTypeNamespace +end + + +module Mapping + + +module MappedException; end + + +RubyTypeName = XSD::QName.new(RubyTypeInstanceNamespace, 'rubyType') +RubyExtendName = XSD::QName.new(RubyTypeInstanceNamespace, 'extends') +RubyIVarName = XSD::QName.new(RubyTypeInstanceNamespace, 'ivars') + + +# Inner class to pass an exception. +class SOAPException; include Marshallable + attr_reader :excn_type_name, :cause + def initialize(e) + @excn_type_name = Mapping.name2elename(e.class.to_s) + @cause = e + end + + def to_e + if @cause.is_a?(::Exception) + @cause.extend(::SOAP::Mapping::MappedException) + return @cause + elsif @cause.respond_to?(:message) and @cause.respond_to?(:backtrace) + e = RuntimeError.new(@cause.message) + e.set_backtrace(@cause.backtrace) + return e + end + klass = Mapping.class_from_name(Mapping.elename2name(@excn_type_name.to_s)) + if klass.nil? or not klass <= ::Exception + return RuntimeError.new(@cause.inspect) + end + obj = klass.new(@cause.message) + obj.extend(::SOAP::Mapping::MappedException) + obj + end +end + + +# For anyType object: SOAP::Mapping::Object not ::Object +class Object; include Marshallable + def initialize + @__xmlele_type = {} + @__xmlele = [] + @__xmlattr = {} + end + + def inspect + sprintf("#<%s:0x%x%s>", self.class.name, __id__, + @__xmlele.collect { |name, value| " #{name}=#{value.inspect}" }.join) + end + + def __xmlattr + @__xmlattr + end + + def __xmlele + @__xmlele + end + + def [](qname) + unless qname.is_a?(XSD::QName) + qname = XSD::QName.new(nil, qname) + end + @__xmlele.each do |k, v| + return v if k == qname + end + # fallback + @__xmlele.each do |k, v| + return v if k.name == qname.name + end + nil + end + + def []=(qname, value) + unless qname.is_a?(XSD::QName) + qname = XSD::QName.new(nil, qname) + end + found = false + @__xmlele.each do |pair| + if pair[0] == qname + found = true + pair[1] = value + end + end + unless found + __define_attr_accessor(qname) + @__xmlele << [qname, value] + end + @__xmlele_type[qname] = :single + end + + def __add_xmlele_value(qname, value) + found = false + @__xmlele.map! do |k, v| + if k == qname + found = true + [k, __set_xmlele_value(k, v, value)] + else + [k, v] + end + end + unless found + __define_attr_accessor(qname) + @__xmlele << [qname, value] + @__xmlele_type[qname] = :single + end + value + end + +private + + if RUBY_VERSION > "1.7.0" + def __define_attr_accessor(qname) + name = XSD::CodeGen::GenSupport.safemethodname(qname.name) + Mapping.define_attr_accessor(self, name, + proc { self[qname] }, + proc { |value| self[qname] = value }) + end + else + def __define_attr_accessor(qname) + name = XSD::CodeGen::GenSupport.safemethodname(qname.name) + instance_eval <<-EOS + def #{name} + self[#{qname.dump}] + end + + def #{name}=(value) + self[#{qname.dump}] = value + end + EOS + end + end + + def __set_xmlele_value(key, org, value) + case @__xmlele_type[key] + when :multi + org << value + org + when :single + @__xmlele_type[key] = :multi + [org, value] + else + raise RuntimeError.new("unknown type") + end + end +end + + +class MappingError < Error; end + + +class Registry + class Map + def initialize(registry) + @obj2soap = {} + @soap2obj = {} + @registry = registry + end + + def obj2soap(obj) + klass = obj.class + if map = @obj2soap[klass] + map.each do |soap_class, factory, info| + ret = factory.obj2soap(soap_class, obj, info, @registry) + return ret if ret + end + end + ancestors = klass.ancestors + ancestors.delete(klass) + ancestors.delete(::Object) + ancestors.delete(::Kernel) + ancestors.each do |klass| + if map = @obj2soap[klass] + map.each do |soap_class, factory, info| + if info[:derived_class] + ret = factory.obj2soap(soap_class, obj, info, @registry) + return ret if ret + end + end + end + end + nil + end + + def soap2obj(node, klass = nil) + if map = @soap2obj[node.class] + map.each do |obj_class, factory, info| + next if klass and obj_class != klass + conv, obj = factory.soap2obj(obj_class, node, info, @registry) + return true, obj if conv + end + end + return false, nil + end + + # Give priority to former entry. + def init(init_map = []) + clear + init_map.reverse_each do |obj_class, soap_class, factory, info| + add(obj_class, soap_class, factory, info) + end + end + + # Give priority to latter entry. + def add(obj_class, soap_class, factory, info) + info ||= {} + (@obj2soap[obj_class] ||= []).unshift([soap_class, factory, info]) + (@soap2obj[soap_class] ||= []).unshift([obj_class, factory, info]) + end + + def clear + @obj2soap.clear + @soap2obj.clear + end + + def find_mapped_soap_class(target_obj_class) + map = @obj2soap[target_obj_class] + map.empty? ? nil : map[0][1] + end + + def find_mapped_obj_class(target_soap_class) + map = @soap2obj[target_soap_class] + map.empty? ? nil : map[0][0] + end + end + + StringFactory = StringFactory_.new + BasetypeFactory = BasetypeFactory_.new + DateTimeFactory = DateTimeFactory_.new + ArrayFactory = ArrayFactory_.new + Base64Factory = Base64Factory_.new + URIFactory = URIFactory_.new + TypedArrayFactory = TypedArrayFactory_.new + TypedStructFactory = TypedStructFactory_.new + + HashFactory = HashFactory_.new + + SOAPBaseMap = [ + [::NilClass, ::SOAP::SOAPNil, BasetypeFactory], + [::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory], + [::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory], + [::String, ::SOAP::SOAPString, StringFactory], + [::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory], + [::Date, ::SOAP::SOAPDate, DateTimeFactory], + [::Time, ::SOAP::SOAPDateTime, DateTimeFactory], + [::Time, ::SOAP::SOAPTime, DateTimeFactory], + [::Float, ::SOAP::SOAPDouble, BasetypeFactory, + {:derived_class => true}], + [::Float, ::SOAP::SOAPFloat, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPInt, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPLong, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPInteger, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPShort, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPByte, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPNonPositiveInteger, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPNegativeInteger, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPNonNegativeInteger, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPPositiveInteger, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPUnsignedLong, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPUnsignedInt, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPUnsignedShort, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPUnsignedByte, BasetypeFactory, + {:derived_class => true}], + [::URI::Generic, ::SOAP::SOAPAnyURI, URIFactory, + {:derived_class => true}], + [::String, ::SOAP::SOAPBase64, Base64Factory], + [::String, ::SOAP::SOAPHexBinary, Base64Factory], + [::String, ::SOAP::SOAPDecimal, BasetypeFactory], + [::String, ::SOAP::SOAPDuration, BasetypeFactory], + [::String, ::SOAP::SOAPGYearMonth, BasetypeFactory], + [::String, ::SOAP::SOAPGYear, BasetypeFactory], + [::String, ::SOAP::SOAPGMonthDay, BasetypeFactory], + [::String, ::SOAP::SOAPGDay, BasetypeFactory], + [::String, ::SOAP::SOAPGMonth, BasetypeFactory], + [::String, ::SOAP::SOAPQName, BasetypeFactory], + + [::Hash, ::SOAP::SOAPArray, HashFactory], + [::Hash, ::SOAP::SOAPStruct, HashFactory], + + [::Array, ::SOAP::SOAPArray, ArrayFactory, + {:derived_class => true}], + + [::SOAP::Mapping::SOAPException, + ::SOAP::SOAPStruct, TypedStructFactory, + {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}], + ] + + RubyOriginalMap = [ + [::NilClass, ::SOAP::SOAPNil, BasetypeFactory], + [::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory], + [::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory], + [::String, ::SOAP::SOAPString, StringFactory], + [::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory], + [::Date, ::SOAP::SOAPDate, DateTimeFactory], + [::Time, ::SOAP::SOAPDateTime, DateTimeFactory], + [::Time, ::SOAP::SOAPTime, DateTimeFactory], + [::Float, ::SOAP::SOAPDouble, BasetypeFactory, + {:derived_class => true}], + [::Float, ::SOAP::SOAPFloat, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPInt, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPLong, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPInteger, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPShort, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPByte, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPNonPositiveInteger, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPNegativeInteger, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPNonNegativeInteger, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPPositiveInteger, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPUnsignedLong, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPUnsignedInt, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPUnsignedShort, BasetypeFactory, + {:derived_class => true}], + [::Integer, ::SOAP::SOAPUnsignedByte, BasetypeFactory, + {:derived_class => true}], + [::URI::Generic, ::SOAP::SOAPAnyURI, URIFactory, + {:derived_class => true}], + [::String, ::SOAP::SOAPBase64, Base64Factory], + [::String, ::SOAP::SOAPHexBinary, Base64Factory], + [::String, ::SOAP::SOAPDecimal, BasetypeFactory], + [::String, ::SOAP::SOAPDuration, BasetypeFactory], + [::String, ::SOAP::SOAPGYearMonth, BasetypeFactory], + [::String, ::SOAP::SOAPGYear, BasetypeFactory], + [::String, ::SOAP::SOAPGMonthDay, BasetypeFactory], + [::String, ::SOAP::SOAPGDay, BasetypeFactory], + [::String, ::SOAP::SOAPGMonth, BasetypeFactory], + [::String, ::SOAP::SOAPQName, BasetypeFactory], + + [::Hash, ::SOAP::SOAPArray, HashFactory], + [::Hash, ::SOAP::SOAPStruct, HashFactory], + + # Does not allow Array's subclass here. + [::Array, ::SOAP::SOAPArray, ArrayFactory], + + [::SOAP::Mapping::SOAPException, + ::SOAP::SOAPStruct, TypedStructFactory, + {:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}], + ] + + attr_accessor :default_factory + attr_accessor :excn_handler_obj2soap + attr_accessor :excn_handler_soap2obj + + def initialize(config = {}) + @config = config + @map = Map.new(self) + if @config[:allow_original_mapping] + @allow_original_mapping = true + @map.init(RubyOriginalMap) + else + @allow_original_mapping = false + @map.init(SOAPBaseMap) + end + @allow_untyped_struct = @config.key?(:allow_untyped_struct) ? + @config[:allow_untyped_struct] : true + @rubytype_factory = RubytypeFactory.new( + :allow_untyped_struct => @allow_untyped_struct, + :allow_original_mapping => @allow_original_mapping + ) + @default_factory = @rubytype_factory + @excn_handler_obj2soap = nil + @excn_handler_soap2obj = nil + end + + def add(obj_class, soap_class, factory, info = nil) + @map.add(obj_class, soap_class, factory, info) + end + alias set add + + # general Registry ignores type_qname + def obj2soap(obj, type_qname = nil) + soap = _obj2soap(obj) + if @allow_original_mapping + addextend2soap(soap, obj) + end + soap + end + + def soap2obj(node, klass = nil) + obj = _soap2obj(node, klass) + if @allow_original_mapping + addextend2obj(obj, node.extraattr[RubyExtendName]) + addiv2obj(obj, node.extraattr[RubyIVarName]) + end + obj + end + + def find_mapped_soap_class(obj_class) + @map.find_mapped_soap_class(obj_class) + end + + def find_mapped_obj_class(soap_class) + @map.find_mapped_obj_class(soap_class) + end + +private + + def _obj2soap(obj) + ret = nil + if obj.is_a?(SOAPStruct) or obj.is_a?(SOAPArray) + obj.replace do |ele| + Mapping._obj2soap(ele, self) + end + return obj + elsif obj.is_a?(SOAPBasetype) + return obj + end + begin + ret = @map.obj2soap(obj) || + @default_factory.obj2soap(nil, obj, nil, self) + return ret if ret + rescue MappingError + end + if @excn_handler_obj2soap + ret = @excn_handler_obj2soap.call(obj) { |yield_obj| + Mapping._obj2soap(yield_obj, self) + } + return ret if ret + end + raise MappingError.new("Cannot map #{ obj.class.name } to SOAP/OM.") + end + + # Might return nil as a mapping result. + def _soap2obj(node, klass = nil) + if node.extraattr.key?(RubyTypeName) + conv, obj = @rubytype_factory.soap2obj(nil, node, nil, self) + return obj if conv + else + conv, obj = @map.soap2obj(node, klass) + return obj if conv + conv, obj = @default_factory.soap2obj(nil, node, nil, self) + return obj if conv + end + if @excn_handler_soap2obj + begin + return @excn_handler_soap2obj.call(node) { |yield_node| + Mapping._soap2obj(yield_node, self) + } + rescue Exception + end + end + raise MappingError.new("Cannot map #{ node.type.name } to Ruby object.") + end + + def addiv2obj(obj, attr) + return unless attr + vars = {} + attr.__getobj__.each do |name, value| + vars[name] = Mapping._soap2obj(value, self) + end + Mapping.set_attributes(obj, vars) + end + + if RUBY_VERSION >= '1.8.0' + def addextend2obj(obj, attr) + return unless attr + attr.split(/ /).reverse_each do |mstr| + obj.extend(Mapping.module_from_name(mstr)) + end + end + else + # (class < false; self; end).ancestors includes "TrueClass" under 1.6... + def addextend2obj(obj, attr) + return unless attr + attr.split(/ /).reverse_each do |mstr| + m = Mapping.module_from_name(mstr) + obj.extend(m) + end + end + end + + def addextend2soap(node, obj) + return if obj.is_a?(Symbol) or obj.is_a?(Fixnum) + list = (class << obj; self; end).ancestors - obj.class.ancestors + unless list.empty? + node.extraattr[RubyExtendName] = list.collect { |c| + if c.name.empty? + raise TypeError.new("singleton can't be dumped #{ obj }") + end + c.name + }.join(" ") + end + end + +end + + +DefaultRegistry = Registry.new +RubyOriginalRegistry = Registry.new(:allow_original_mapping => true) + + +end +end diff --git a/ruby_1_8_6/lib/soap/mapping/rubytypeFactory.rb b/ruby_1_8_6/lib/soap/mapping/rubytypeFactory.rb new file mode 100644 index 0000000000..61c21d8b20 --- /dev/null +++ b/ruby_1_8_6/lib/soap/mapping/rubytypeFactory.rb @@ -0,0 +1,475 @@ +# SOAP4R - Ruby type mapping factory. +# Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +module SOAP +module Mapping + + +class RubytypeFactory < Factory + TYPE_STRING = XSD::QName.new(RubyTypeNamespace, 'String') + TYPE_TIME = XSD::QName.new(RubyTypeNamespace, 'Time') + TYPE_ARRAY = XSD::QName.new(RubyTypeNamespace, 'Array') + TYPE_REGEXP = XSD::QName.new(RubyTypeNamespace, 'Regexp') + TYPE_RANGE = XSD::QName.new(RubyTypeNamespace, 'Range') + TYPE_CLASS = XSD::QName.new(RubyTypeNamespace, 'Class') + TYPE_MODULE = XSD::QName.new(RubyTypeNamespace, 'Module') + TYPE_SYMBOL = XSD::QName.new(RubyTypeNamespace, 'Symbol') + TYPE_STRUCT = XSD::QName.new(RubyTypeNamespace, 'Struct') + TYPE_HASH = XSD::QName.new(RubyTypeNamespace, 'Map') + + def initialize(config = {}) + @config = config + @allow_untyped_struct = @config.key?(:allow_untyped_struct) ? + @config[:allow_untyped_struct] : true + @allow_original_mapping = @config.key?(:allow_original_mapping) ? + @config[:allow_original_mapping] : false + @string_factory = StringFactory_.new(true) + @basetype_factory = BasetypeFactory_.new(true) + @datetime_factory = DateTimeFactory_.new(true) + @array_factory = ArrayFactory_.new(true) + @hash_factory = HashFactory_.new(true) + end + + def obj2soap(soap_class, obj, info, map) + param = nil + case obj + when ::String + unless @allow_original_mapping + return nil + end + param = @string_factory.obj2soap(SOAPString, obj, info, map) + if obj.class != String + param.extraattr[RubyTypeName] = obj.class.name + end + addiv2soapattr(param, obj, map) + when ::Time + unless @allow_original_mapping + return nil + end + param = @datetime_factory.obj2soap(SOAPDateTime, obj, info, map) + if obj.class != Time + param.extraattr[RubyTypeName] = obj.class.name + end + addiv2soapattr(param, obj, map) + when ::Array + unless @allow_original_mapping + return nil + end + param = @array_factory.obj2soap(nil, obj, info, map) + if obj.class != Array + param.extraattr[RubyTypeName] = obj.class.name + end + addiv2soapattr(param, obj, map) + when ::NilClass + unless @allow_original_mapping + return nil + end + param = @basetype_factory.obj2soap(SOAPNil, obj, info, map) + addiv2soapattr(param, obj, map) + when ::FalseClass, ::TrueClass + unless @allow_original_mapping + return nil + end + param = @basetype_factory.obj2soap(SOAPBoolean, obj, info, map) + addiv2soapattr(param, obj, map) + when ::Integer + unless @allow_original_mapping + return nil + end + param = @basetype_factory.obj2soap(SOAPInt, obj, info, map) + param ||= @basetype_factory.obj2soap(SOAPInteger, obj, info, map) + param ||= @basetype_factory.obj2soap(SOAPDecimal, obj, info, map) + addiv2soapattr(param, obj, map) + when ::Float + unless @allow_original_mapping + return nil + end + param = @basetype_factory.obj2soap(SOAPDouble, obj, info, map) + if obj.class != Float + param.extraattr[RubyTypeName] = obj.class.name + end + addiv2soapattr(param, obj, map) + when ::Hash + unless @allow_original_mapping + return nil + end + if obj.respond_to?(:default_proc) && obj.default_proc + raise TypeError.new("cannot dump hash with default proc") + end + param = SOAPStruct.new(TYPE_HASH) + mark_marshalled_obj(obj, param) + if obj.class != Hash + param.extraattr[RubyTypeName] = obj.class.name + end + obj.each do |key, value| + elem = SOAPStruct.new # Undefined type. + elem.add("key", Mapping._obj2soap(key, map)) + elem.add("value", Mapping._obj2soap(value, map)) + param.add("item", elem) + end + param.add('default', Mapping._obj2soap(obj.default, map)) + addiv2soapattr(param, obj, map) + when ::Regexp + unless @allow_original_mapping + return nil + end + param = SOAPStruct.new(TYPE_REGEXP) + mark_marshalled_obj(obj, param) + if obj.class != Regexp + param.extraattr[RubyTypeName] = obj.class.name + end + param.add('source', SOAPBase64.new(obj.source)) + if obj.respond_to?('options') + # Regexp#options is from Ruby/1.7 + options = obj.options + else + options = 0 + obj.inspect.sub(/^.*\//, '').each_byte do |c| + options += case c + when ?i + 1 + when ?x + 2 + when ?m + 4 + when ?n + 16 + when ?e + 32 + when ?s + 48 + when ?u + 64 + end + end + end + param.add('options', SOAPInt.new(options)) + addiv2soapattr(param, obj, map) + when ::Range + unless @allow_original_mapping + return nil + end + param = SOAPStruct.new(TYPE_RANGE) + mark_marshalled_obj(obj, param) + if obj.class != Range + param.extraattr[RubyTypeName] = obj.class.name + end + param.add('begin', Mapping._obj2soap(obj.begin, map)) + param.add('end', Mapping._obj2soap(obj.end, map)) + param.add('exclude_end', SOAP::SOAPBoolean.new(obj.exclude_end?)) + addiv2soapattr(param, obj, map) + when ::Class + unless @allow_original_mapping + return nil + end + if obj.to_s[0] == ?# + raise TypeError.new("can't dump anonymous class #{obj}") + end + param = SOAPStruct.new(TYPE_CLASS) + mark_marshalled_obj(obj, param) + param.add('name', SOAPString.new(obj.name)) + addiv2soapattr(param, obj, map) + when ::Module + unless @allow_original_mapping + return nil + end + if obj.to_s[0] == ?# + raise TypeError.new("can't dump anonymous module #{obj}") + end + param = SOAPStruct.new(TYPE_MODULE) + mark_marshalled_obj(obj, param) + param.add('name', SOAPString.new(obj.name)) + addiv2soapattr(param, obj, map) + when ::Symbol + unless @allow_original_mapping + return nil + end + param = SOAPStruct.new(TYPE_SYMBOL) + mark_marshalled_obj(obj, param) + param.add('id', SOAPString.new(obj.id2name)) + addiv2soapattr(param, obj, map) + when ::Struct + unless @allow_original_mapping + # treat it as an user defined class. [ruby-talk:104980] + #param = unknownobj2soap(soap_class, obj, info, map) + param = SOAPStruct.new(XSD::AnyTypeName) + mark_marshalled_obj(obj, param) + obj.members.each do |member| + param.add(Mapping.name2elename(member), + Mapping._obj2soap(obj[member], map)) + end + else + param = SOAPStruct.new(TYPE_STRUCT) + mark_marshalled_obj(obj, param) + param.add('type', ele_type = SOAPString.new(obj.class.to_s)) + ele_member = SOAPStruct.new + obj.members.each do |member| + ele_member.add(Mapping.name2elename(member), + Mapping._obj2soap(obj[member], map)) + end + param.add('member', ele_member) + addiv2soapattr(param, obj, map) + end + when ::IO, ::Binding, ::Continuation, ::Data, ::Dir, ::File::Stat, + ::MatchData, Method, ::Proc, ::Thread, ::ThreadGroup + # from 1.8: Process::Status, UnboundMethod + return nil + when ::SOAP::Mapping::Object + param = SOAPStruct.new(XSD::AnyTypeName) + mark_marshalled_obj(obj, param) + obj.__xmlele.each do |key, value| + param.add(key.name, Mapping._obj2soap(value, map)) + end + obj.__xmlattr.each do |key, value| + param.extraattr[key] = value + end + when ::Exception + typestr = Mapping.name2elename(obj.class.to_s) + param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, typestr)) + mark_marshalled_obj(obj, param) + param.add('message', Mapping._obj2soap(obj.message, map)) + param.add('backtrace', Mapping._obj2soap(obj.backtrace, map)) + addiv2soapattr(param, obj, map) + else + param = unknownobj2soap(soap_class, obj, info, map) + end + param + end + + def soap2obj(obj_class, node, info, map) + rubytype = node.extraattr[RubyTypeName] + if rubytype or node.type.namespace == RubyTypeNamespace + rubytype2obj(node, info, map, rubytype) + elsif node.type == XSD::AnyTypeName or node.type == XSD::AnySimpleTypeName + anytype2obj(node, info, map) + else + unknowntype2obj(node, info, map) + end + end + +private + + def addiv2soapattr(node, obj, map) + return if obj.instance_variables.empty? + ivars = SOAPStruct.new # Undefined type. + setiv2soap(ivars, obj, map) + node.extraattr[RubyIVarName] = ivars + end + + def unknownobj2soap(soap_class, obj, info, map) + if obj.class.name.empty? + raise TypeError.new("can't dump anonymous class #{obj}") + end + singleton_class = class << obj; self; end + if !singleton_methods_true(obj).empty? or + !singleton_class.instance_variables.empty? + raise TypeError.new("singleton can't be dumped #{obj}") + end + if !(singleton_class.ancestors - obj.class.ancestors).empty? + typestr = Mapping.name2elename(obj.class.to_s) + type = XSD::QName.new(RubyTypeNamespace, typestr) + else + type = Mapping.class2element(obj.class) + end + param = SOAPStruct.new(type) + mark_marshalled_obj(obj, param) + setiv2soap(param, obj, map) + param + end + + if RUBY_VERSION >= '1.8.0' + def singleton_methods_true(obj) + obj.singleton_methods(true) + end + else + def singleton_methods_true(obj) + obj.singleton_methods + end + end + + def rubytype2obj(node, info, map, rubytype) + klass = rubytype ? Mapping.class_from_name(rubytype) : nil + obj = nil + case node + when SOAPString + return @string_factory.soap2obj(klass || String, node, info, map) + when SOAPDateTime + #return @datetime_factory.soap2obj(klass || Time, node, info, map) + klass ||= Time + t = node.to_time + arg = [t.year, t.month, t.mday, t.hour, t.min, t.sec, t.usec] + obj = t.gmt? ? klass.gm(*arg) : klass.local(*arg) + mark_unmarshalled_obj(node, obj) + return true, obj + when SOAPArray + return @array_factory.soap2obj(klass || Array, node, info, map) + when SOAPNil, SOAPBoolean, SOAPInt, SOAPInteger, SOAPDecimal, SOAPDouble + return @basetype_factory.soap2obj(nil, node, info, map) + when SOAPStruct + return rubytypestruct2obj(node, info, map, rubytype) + else + raise + end + end + + def rubytypestruct2obj(node, info, map, rubytype) + klass = rubytype ? Mapping.class_from_name(rubytype) : nil + obj = nil + case node.type + when TYPE_HASH + klass = rubytype ? Mapping.class_from_name(rubytype) : Hash + obj = Mapping.create_empty_object(klass) + mark_unmarshalled_obj(node, obj) + node.each do |key, value| + next unless key == 'item' + obj[Mapping._soap2obj(value['key'], map)] = + Mapping._soap2obj(value['value'], map) + end + if node.key?('default') + obj.default = Mapping._soap2obj(node['default'], map) + end + when TYPE_REGEXP + klass = rubytype ? Mapping.class_from_name(rubytype) : Regexp + obj = Mapping.create_empty_object(klass) + mark_unmarshalled_obj(node, obj) + source = node['source'].string + options = node['options'].data || 0 + Regexp.instance_method(:initialize).bind(obj).call(source, options) + when TYPE_RANGE + klass = rubytype ? Mapping.class_from_name(rubytype) : Range + obj = Mapping.create_empty_object(klass) + mark_unmarshalled_obj(node, obj) + first = Mapping._soap2obj(node['begin'], map) + last = Mapping._soap2obj(node['end'], map) + exclude_end = node['exclude_end'].data + Range.instance_method(:initialize).bind(obj).call(first, last, exclude_end) + when TYPE_CLASS + obj = Mapping.class_from_name(node['name'].data) + when TYPE_MODULE + obj = Mapping.class_from_name(node['name'].data) + when TYPE_SYMBOL + obj = node['id'].data.intern + when TYPE_STRUCT + typestr = Mapping.elename2name(node['type'].data) + klass = Mapping.class_from_name(typestr) + if klass.nil? + return false + end + unless klass <= ::Struct + return false + end + obj = Mapping.create_empty_object(klass) + mark_unmarshalled_obj(node, obj) + node['member'].each do |name, value| + obj[Mapping.elename2name(name)] = Mapping._soap2obj(value, map) + end + else + return unknowntype2obj(node, info, map) + end + return true, obj + end + + def anytype2obj(node, info, map) + case node + when SOAPBasetype + return true, node.data + when SOAPStruct + klass = ::SOAP::Mapping::Object + obj = klass.new + mark_unmarshalled_obj(node, obj) + node.each do |name, value| + obj.__add_xmlele_value(XSD::QName.new(nil, name), + Mapping._soap2obj(value, map)) + end + unless node.extraattr.empty? + obj.instance_variable_set('@__xmlattr', node.extraattr) + end + return true, obj + else + return false + end + end + + def unknowntype2obj(node, info, map) + case node + when SOAPBasetype + return true, node.data + when SOAPArray + return @array_factory.soap2obj(Array, node, info, map) + when SOAPStruct + obj = unknownstruct2obj(node, info, map) + return true, obj if obj + if !@allow_untyped_struct + return false + end + return anytype2obj(node, info, map) + else + # Basetype which is not defined... + return false + end + end + + def unknownstruct2obj(node, info, map) + unless node.type.name + return nil + end + typestr = Mapping.elename2name(node.type.name) + klass = Mapping.class_from_name(typestr) + if klass.nil? and @allow_untyped_struct + klass = Mapping.class_from_name(typestr, true) # lenient + end + if klass.nil? + return nil + end + if klass <= ::Exception + return exception2obj(klass, node, map) + end + klass_type = Mapping.class2qname(klass) + return nil unless node.type.match(klass_type) + obj = nil + begin + obj = Mapping.create_empty_object(klass) + rescue + # type name "data" tries Data.new which raises TypeError + nil + end + mark_unmarshalled_obj(node, obj) + setiv2obj(obj, node, map) + obj + end + + def exception2obj(klass, node, map) + message = Mapping._soap2obj(node['message'], map) + backtrace = Mapping._soap2obj(node['backtrace'], map) + obj = Mapping.create_empty_object(klass) + obj = obj.exception(message) + mark_unmarshalled_obj(node, obj) + obj.set_backtrace(backtrace) + obj + end + + # Only creates empty array. Do String#replace it with real string. + def array2obj(node, map, rubytype) + klass = rubytype ? Mapping.class_from_name(rubytype) : Array + obj = Mapping.create_empty_object(klass) + mark_unmarshalled_obj(node, obj) + obj + end + + # Only creates empty string. Do String#replace it with real string. + def string2obj(node, map, rubytype) + klass = rubytype ? Mapping.class_from_name(rubytype) : String + obj = Mapping.create_empty_object(klass) + mark_unmarshalled_obj(node, obj) + obj + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/mapping/typeMap.rb b/ruby_1_8_6/lib/soap/mapping/typeMap.rb new file mode 100644 index 0000000000..34db19a5b6 --- /dev/null +++ b/ruby_1_8_6/lib/soap/mapping/typeMap.rb @@ -0,0 +1,50 @@ +# SOAP4R - Base type mapping definition +# Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +module SOAP + + +TypeMap = { + XSD::XSDAnySimpleType::Type => SOAPAnySimpleType, + XSD::XSDString::Type => SOAPString, + XSD::XSDBoolean::Type => SOAPBoolean, + XSD::XSDDecimal::Type => SOAPDecimal, + XSD::XSDFloat::Type => SOAPFloat, + XSD::XSDDouble::Type => SOAPDouble, + XSD::XSDDuration::Type => SOAPDuration, + XSD::XSDDateTime::Type => SOAPDateTime, + XSD::XSDTime::Type => SOAPTime, + XSD::XSDDate::Type => SOAPDate, + XSD::XSDGYearMonth::Type => SOAPGYearMonth, + XSD::XSDGYear::Type => SOAPGYear, + XSD::XSDGMonthDay::Type => SOAPGMonthDay, + XSD::XSDGDay::Type => SOAPGDay, + XSD::XSDGMonth::Type => SOAPGMonth, + XSD::XSDHexBinary::Type => SOAPHexBinary, + XSD::XSDBase64Binary::Type => SOAPBase64, + XSD::XSDAnyURI::Type => SOAPAnyURI, + XSD::XSDQName::Type => SOAPQName, + XSD::XSDInteger::Type => SOAPInteger, + XSD::XSDNonPositiveInteger::Type => SOAPNonPositiveInteger, + XSD::XSDNegativeInteger::Type => SOAPNegativeInteger, + XSD::XSDLong::Type => SOAPLong, + XSD::XSDInt::Type => SOAPInt, + XSD::XSDShort::Type => SOAPShort, + XSD::XSDByte::Type => SOAPByte, + XSD::XSDNonNegativeInteger::Type => SOAPNonNegativeInteger, + XSD::XSDUnsignedLong::Type => SOAPUnsignedLong, + XSD::XSDUnsignedInt::Type => SOAPUnsignedInt, + XSD::XSDUnsignedShort::Type => SOAPUnsignedShort, + XSD::XSDUnsignedByte::Type => SOAPUnsignedByte, + XSD::XSDPositiveInteger::Type => SOAPPositiveInteger, + + SOAP::SOAPBase64::Type => SOAPBase64, +} + + +end diff --git a/ruby_1_8_6/lib/soap/mapping/wsdlencodedregistry.rb b/ruby_1_8_6/lib/soap/mapping/wsdlencodedregistry.rb new file mode 100644 index 0000000000..4efb60188f --- /dev/null +++ b/ruby_1_8_6/lib/soap/mapping/wsdlencodedregistry.rb @@ -0,0 +1,280 @@ +# SOAP4R - WSDL encoded mapping registry. +# Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'xsd/qname' +require 'xsd/namedelements' +require 'soap/baseData' +require 'soap/mapping/mapping' +require 'soap/mapping/typeMap' + + +module SOAP +module Mapping + + +class WSDLEncodedRegistry < Registry + include TraverseSupport + + attr_reader :definedelements + attr_reader :definedtypes + attr_accessor :excn_handler_obj2soap + attr_accessor :excn_handler_soap2obj + + def initialize(definedtypes = XSD::NamedElements::Empty) + @definedtypes = definedtypes + # @definedelements = definedelements needed? + @excn_handler_obj2soap = nil + @excn_handler_soap2obj = nil + # For mapping AnyType element. + @rubytype_factory = RubytypeFactory.new( + :allow_untyped_struct => true, + :allow_original_mapping => true + ) + @schema_element_cache = {} + end + + def obj2soap(obj, qname = nil) + soap_obj = nil + if type = @definedtypes[qname] + soap_obj = obj2typesoap(obj, type) + else + soap_obj = any2soap(obj, qname) + end + return soap_obj if soap_obj + if @excn_handler_obj2soap + soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj| + Mapping._obj2soap(yield_obj, self) + } + return soap_obj if soap_obj + end + if qname + raise MappingError.new("cannot map #{obj.class.name} as #{qname}") + else + raise MappingError.new("cannot map #{obj.class.name} to SOAP/OM") + end + end + + # map anything for now: must refer WSDL while mapping. [ToDo] + def soap2obj(node, obj_class = nil) + begin + return any2obj(node, obj_class) + rescue MappingError + end + if @excn_handler_soap2obj + begin + return @excn_handler_soap2obj.call(node) { |yield_node| + Mapping._soap2obj(yield_node, self) + } + rescue Exception + end + end + raise MappingError.new("cannot map #{node.type.name} to Ruby object") + end + +private + + def any2soap(obj, qname) + if obj.nil? + SOAPNil.new + elsif qname.nil? or qname == XSD::AnyTypeName + @rubytype_factory.obj2soap(nil, obj, nil, self) + elsif obj.is_a?(XSD::NSDBase) + soap2soap(obj, qname) + elsif (type = TypeMap[qname]) + base2soap(obj, type) + else + nil + end + end + + def soap2soap(obj, type_qname) + if obj.is_a?(SOAPBasetype) + obj + elsif obj.is_a?(SOAPStruct) && (type = @definedtypes[type_qname]) + soap_obj = obj + mark_marshalled_obj(obj, soap_obj) + elements2soap(obj, soap_obj, type.content.elements) + soap_obj + elsif obj.is_a?(SOAPArray) && (type = @definedtypes[type_qname]) + soap_obj = obj + contenttype = type.child_type + mark_marshalled_obj(obj, soap_obj) + obj.replace do |ele| + Mapping._obj2soap(ele, self, contenttype) + end + soap_obj + else + nil + end + end + + def obj2typesoap(obj, type) + if type.is_a?(::WSDL::XMLSchema::SimpleType) + simpleobj2soap(obj, type) + else + complexobj2soap(obj, type) + end + end + + def simpleobj2soap(obj, type) + type.check_lexical_format(obj) + return SOAPNil.new if obj.nil? # ToDo: check nillable. + o = base2soap(obj, TypeMap[type.base]) + o + end + + def complexobj2soap(obj, type) + case type.compoundtype + when :TYPE_STRUCT + struct2soap(obj, type.name, type) + when :TYPE_ARRAY + array2soap(obj, type.name, type) + when :TYPE_MAP + map2soap(obj, type.name, type) + when :TYPE_SIMPLE + simpleobj2soap(obj, type.simplecontent) + when :TYPE_EMPTY + raise MappingError.new("should be empty") unless obj.nil? + SOAPNil.new + else + raise MappingError.new("unknown compound type: #{type.compoundtype}") + end + end + + def base2soap(obj, type) + soap_obj = nil + if type <= XSD::XSDString + str = XSD::Charset.encoding_conv(obj.to_s, + Thread.current[:SOAPExternalCES], XSD::Charset.encoding) + soap_obj = type.new(str) + mark_marshalled_obj(obj, soap_obj) + else + soap_obj = type.new(obj) + end + soap_obj + end + + def struct2soap(obj, type_qname, type) + return SOAPNil.new if obj.nil? # ToDo: check nillable. + soap_obj = SOAPStruct.new(type_qname) + unless obj.nil? + mark_marshalled_obj(obj, soap_obj) + elements2soap(obj, soap_obj, type.content.elements) + end + soap_obj + end + + def array2soap(obj, type_qname, type) + return SOAPNil.new if obj.nil? # ToDo: check nillable. + arytype = type.child_type + soap_obj = SOAPArray.new(ValueArrayName, 1, arytype) + unless obj.nil? + mark_marshalled_obj(obj, soap_obj) + obj.each do |item| + soap_obj.add(Mapping._obj2soap(item, self, arytype)) + end + end + soap_obj + end + + MapKeyName = XSD::QName.new(nil, "key") + MapValueName = XSD::QName.new(nil, "value") + def map2soap(obj, type_qname, type) + return SOAPNil.new if obj.nil? # ToDo: check nillable. + keytype = type.child_type(MapKeyName) || XSD::AnyTypeName + valuetype = type.child_type(MapValueName) || XSD::AnyTypeName + soap_obj = SOAPStruct.new(MapQName) + unless obj.nil? + mark_marshalled_obj(obj, soap_obj) + obj.each do |key, value| + elem = SOAPStruct.new + elem.add("key", Mapping._obj2soap(key, self, keytype)) + elem.add("value", Mapping._obj2soap(value, self, valuetype)) + # ApacheAxis allows only 'item' here. + soap_obj.add("item", elem) + end + end + soap_obj + end + + def elements2soap(obj, soap_obj, elements) + elements.each do |element| + name = element.name.name + child_obj = Mapping.get_attribute(obj, name) + soap_obj.add(name, + Mapping._obj2soap(child_obj, self, element.type || element.name)) + end + end + + def any2obj(node, obj_class) + unless obj_class + typestr = XSD::CodeGen::GenSupport.safeconstname(node.elename.name) + obj_class = Mapping.class_from_name(typestr) + end + if obj_class and obj_class.class_variables.include?('@@schema_element') + soap2stubobj(node, obj_class) + else + Mapping._soap2obj(node, Mapping::DefaultRegistry, obj_class) + end + end + + def soap2stubobj(node, obj_class) + obj = Mapping.create_empty_object(obj_class) + unless node.is_a?(SOAPNil) + add_elements2stubobj(node, obj) + end + obj + end + + def add_elements2stubobj(node, obj) + elements, as_array = schema_element_definition(obj.class) + vars = {} + node.each do |name, value| + item = elements.find { |k, v| k.name == name } + if item + elename, class_name = item + if klass = Mapping.class_from_name(class_name) + # klass must be a SOAPBasetype or a class + if klass.ancestors.include?(::SOAP::SOAPBasetype) + if value.respond_to?(:data) + child = klass.new(value.data).data + else + child = klass.new(nil).data + end + else + child = Mapping._soap2obj(value, self, klass) + end + elsif klass = Mapping.module_from_name(class_name) + # simpletype + if value.respond_to?(:data) + child = value.data + else + raise MappingError.new( + "cannot map to a module value: #{class_name}") + end + else + raise MappingError.new("unknown class: #{class_name}") + end + else # untyped element is treated as anyType. + child = Mapping._soap2obj(value, self) + end + vars[name] = child + end + Mapping.set_attributes(obj, vars) + end + + # it caches @@schema_element. this means that @@schema_element must not be + # changed while a lifetime of a WSDLLiteralRegistry. + def schema_element_definition(klass) + @schema_element_cache[klass] ||= Mapping.schema_element_definition(klass) + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/mapping/wsdlliteralregistry.rb b/ruby_1_8_6/lib/soap/mapping/wsdlliteralregistry.rb new file mode 100644 index 0000000000..7bb8e12203 --- /dev/null +++ b/ruby_1_8_6/lib/soap/mapping/wsdlliteralregistry.rb @@ -0,0 +1,418 @@ +# SOAP4R - WSDL literal mapping registry. +# Copyright (C) 2004, 2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/baseData' +require 'soap/mapping/mapping' +require 'soap/mapping/typeMap' +require 'xsd/codegen/gensupport' +require 'xsd/namedelements' + + +module SOAP +module Mapping + + +class WSDLLiteralRegistry < Registry + attr_reader :definedelements + attr_reader :definedtypes + attr_accessor :excn_handler_obj2soap + attr_accessor :excn_handler_soap2obj + + def initialize(definedtypes = XSD::NamedElements::Empty, + definedelements = XSD::NamedElements::Empty) + @definedtypes = definedtypes + @definedelements = definedelements + @excn_handler_obj2soap = nil + @excn_handler_soap2obj = nil + @schema_element_cache = {} + @schema_attribute_cache = {} + end + + def obj2soap(obj, qname) + soap_obj = nil + if ele = @definedelements[qname] + soap_obj = obj2elesoap(obj, ele) + elsif type = @definedtypes[qname] + soap_obj = obj2typesoap(obj, type, true) + else + soap_obj = any2soap(obj, qname) + end + return soap_obj if soap_obj + if @excn_handler_obj2soap + soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj| + Mapping.obj2soap(yield_obj, nil, nil, MAPPING_OPT) + } + return soap_obj if soap_obj + end + raise MappingError.new("cannot map #{obj.class.name} as #{qname}") + end + + # node should be a SOAPElement + def soap2obj(node, obj_class = nil) + # obj_class is given when rpc/literal service. but ignored for now. + begin + return any2obj(node) + rescue MappingError + end + if @excn_handler_soap2obj + begin + return @excn_handler_soap2obj.call(node) { |yield_node| + Mapping.soap2obj(yield_node, nil, nil, MAPPING_OPT) + } + rescue Exception + end + end + if node.respond_to?(:type) + raise MappingError.new("cannot map #{node.type.name} to Ruby object") + else + raise MappingError.new("cannot map #{node.elename.name} to Ruby object") + end + end + +private + + MAPPING_OPT = { :no_reference => true } + + def obj2elesoap(obj, ele) + o = nil + qualified = (ele.elementform == 'qualified') + if ele.type + if type = @definedtypes[ele.type] + o = obj2typesoap(obj, type, qualified) + elsif type = TypeMap[ele.type] + o = base2soap(obj, type) + else + raise MappingError.new("cannot find type #{ele.type}") + end + elsif ele.local_complextype + o = obj2typesoap(obj, ele.local_complextype, qualified) + add_attributes2soap(obj, o) + elsif ele.local_simpletype + o = obj2typesoap(obj, ele.local_simpletype, qualified) + else + raise MappingError.new('illegal schema?') + end + o.elename = ele.name + o + end + + def obj2typesoap(obj, type, qualified) + if type.is_a?(::WSDL::XMLSchema::SimpleType) + simpleobj2soap(obj, type) + else + complexobj2soap(obj, type, qualified) + end + end + + def simpleobj2soap(obj, type) + type.check_lexical_format(obj) + return SOAPNil.new if obj.nil? # ToDo: check nillable. + o = base2soap(obj, TypeMap[type.base]) + o + end + + def complexobj2soap(obj, type, qualified) + o = SOAPElement.new(type.name) + o.qualified = qualified + type.each_element do |child_ele| + child = Mapping.get_attribute(obj, child_ele.name.name) + if child.nil? + if child_ele.nillable + # ToDo: test + # add empty element + child_soap = obj2elesoap(nil, child_ele) + o.add(child_soap) + elsif Integer(child_ele.minoccurs) == 0 + # nothing to do + else + raise MappingError.new("nil not allowed: #{child_ele.name.name}") + end + elsif child_ele.map_as_array? + child.each do |item| + child_soap = obj2elesoap(item, child_ele) + o.add(child_soap) + end + else + child_soap = obj2elesoap(child, child_ele) + o.add(child_soap) + end + end + o + end + + def any2soap(obj, qname) + if obj.is_a?(SOAPElement) + obj + elsif obj.class.class_variables.include?('@@schema_element') + stubobj2soap(obj, qname) + elsif obj.is_a?(SOAP::Mapping::Object) + mappingobj2soap(obj, qname) + elsif obj.is_a?(Hash) + ele = SOAPElement.from_obj(obj) + ele.elename = qname + ele + else + # expected to be a basetype or an anyType. + # SOAPStruct, etc. is used instead of SOAPElement. + begin + ele = Mapping.obj2soap(obj, nil, nil, MAPPING_OPT) + ele.elename = qname + ele + rescue MappingError + ele = SOAPElement.new(qname, obj.to_s) + end + if obj.respond_to?(:__xmlattr) + obj.__xmlattr.each do |key, value| + ele.extraattr[key] = value + end + end + ele + end + end + + def stubobj2soap(obj, qname) + ele = SOAPElement.new(qname) + ele.qualified = + (obj.class.class_variables.include?('@@schema_qualified') and + obj.class.class_eval('@@schema_qualified')) + add_elements2soap(obj, ele) + add_attributes2soap(obj, ele) + ele + end + + def mappingobj2soap(obj, qname) + ele = SOAPElement.new(qname) + obj.__xmlele.each do |key, value| + if value.is_a?(::Array) + value.each do |item| + ele.add(obj2soap(item, key)) + end + else + ele.add(obj2soap(value, key)) + end + end + obj.__xmlattr.each do |key, value| + ele.extraattr[key] = value + end + ele + end + + def add_elements2soap(obj, ele) + elements, as_array = schema_element_definition(obj.class) + if elements + elements.each do |elename, type| + if child = Mapping.get_attribute(obj, elename.name) + if as_array.include?(elename.name) + child.each do |item| + ele.add(obj2soap(item, elename)) + end + else + ele.add(obj2soap(child, elename)) + end + elsif obj.is_a?(::Array) and as_array.include?(elename.name) + obj.each do |item| + ele.add(obj2soap(item, elename)) + end + end + end + end + end + + def add_attributes2soap(obj, ele) + attributes = schema_attribute_definition(obj.class) + if attributes + attributes.each do |qname, param| + attr = obj.__send__('xmlattr_' + + XSD::CodeGen::GenSupport.safevarname(qname.name)) + ele.extraattr[qname] = attr + end + end + end + + def base2soap(obj, type) + soap_obj = nil + if type <= XSD::XSDString + str = XSD::Charset.encoding_conv(obj.to_s, + Thread.current[:SOAPExternalCES], XSD::Charset.encoding) + soap_obj = type.new(str) + else + soap_obj = type.new(obj) + end + soap_obj + end + + def anytype2obj(node) + if node.is_a?(::SOAP::SOAPBasetype) + return node.data + end + klass = ::SOAP::Mapping::Object + obj = klass.new + obj + end + + def any2obj(node, obj_class = nil) + unless obj_class + typestr = XSD::CodeGen::GenSupport.safeconstname(node.elename.name) + obj_class = Mapping.class_from_name(typestr) + end + if obj_class and obj_class.class_variables.include?('@@schema_element') + soapele2stubobj(node, obj_class) + elsif node.is_a?(SOAPElement) or node.is_a?(SOAPStruct) + # SOAPArray for literal? + soapele2plainobj(node) + else + obj = Mapping.soap2obj(node, nil, obj_class, MAPPING_OPT) + add_attributes2plainobj(node, obj) + obj + end + end + + def soapele2stubobj(node, obj_class) + obj = Mapping.create_empty_object(obj_class) + add_elements2stubobj(node, obj) + add_attributes2stubobj(node, obj) + obj + end + + def soapele2plainobj(node) + obj = anytype2obj(node) + add_elements2plainobj(node, obj) + add_attributes2plainobj(node, obj) + obj + end + + def add_elements2stubobj(node, obj) + elements, as_array = schema_element_definition(obj.class) + vars = {} + node.each do |name, value| + item = elements.find { |k, v| k.name == name } + if item + elename, class_name = item + if klass = Mapping.class_from_name(class_name) + # klass must be a SOAPBasetype or a class + if klass.ancestors.include?(::SOAP::SOAPBasetype) + if value.respond_to?(:data) + child = klass.new(value.data).data + else + child = klass.new(nil).data + end + else + child = any2obj(value, klass) + end + elsif klass = Mapping.module_from_name(class_name) + # simpletype + if value.respond_to?(:data) + child = value.data + else + raise MappingError.new( + "cannot map to a module value: #{class_name}") + end + else + raise MappingError.new("unknown class/module: #{class_name}") + end + else # untyped element is treated as anyType. + child = any2obj(value) + end + if as_array.include?(elename.name) + (vars[name] ||= []) << child + else + vars[name] = child + end + end + Mapping.set_attributes(obj, vars) + end + + def add_attributes2stubobj(node, obj) + if attributes = schema_attribute_definition(obj.class) + define_xmlattr(obj) + attributes.each do |qname, class_name| + attr = node.extraattr[qname] + next if attr.nil? or attr.empty? + klass = Mapping.class_from_name(class_name) + if klass.ancestors.include?(::SOAP::SOAPBasetype) + child = klass.new(attr).data + else + child = attr + end + obj.__xmlattr[qname] = child + define_xmlattr_accessor(obj, qname) + end + end + end + + def add_elements2plainobj(node, obj) + node.each do |name, value| + obj.__add_xmlele_value(value.elename, any2obj(value)) + end + end + + def add_attributes2plainobj(node, obj) + return if node.extraattr.empty? + define_xmlattr(obj) + node.extraattr.each do |qname, value| + obj.__xmlattr[qname] = value + define_xmlattr_accessor(obj, qname) + end + end + + if RUBY_VERSION > "1.7.0" + def define_xmlattr_accessor(obj, qname) + name = XSD::CodeGen::GenSupport.safemethodname(qname.name) + Mapping.define_attr_accessor(obj, 'xmlattr_' + name, + proc { @__xmlattr[qname] }, + proc { |value| @__xmlattr[qname] = value }) + end + else + def define_xmlattr_accessor(obj, qname) + name = XSD::CodeGen::GenSupport.safemethodname(qname.name) + obj.instance_eval <<-EOS + def #{name} + @__xmlattr[#{qname.dump}] + end + + def #{name}=(value) + @__xmlattr[#{qname.dump}] = value + end + EOS + end + end + + if RUBY_VERSION > "1.7.0" + def define_xmlattr(obj) + obj.instance_variable_set('@__xmlattr', {}) + unless obj.respond_to?(:__xmlattr) + Mapping.define_attr_accessor(obj, :__xmlattr, proc { @__xmlattr }) + end + end + else + def define_xmlattr(obj) + obj.instance_variable_set('@__xmlattr', {}) + unless obj.respond_to?(:__xmlattr) + obj.instance_eval <<-EOS + def __xmlattr + @__xmlattr + end + EOS + end + end + end + + # it caches @@schema_element. this means that @@schema_element must not be + # changed while a lifetime of a WSDLLiteralRegistry. + def schema_element_definition(klass) + @schema_element_cache[klass] ||= Mapping.schema_element_definition(klass) + end + + def schema_attribute_definition(klass) + @schema_attribute_cache[klass] ||= Mapping.schema_attribute_definition(klass) + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/marshal.rb b/ruby_1_8_6/lib/soap/marshal.rb new file mode 100644 index 0000000000..1c3d5b01db --- /dev/null +++ b/ruby_1_8_6/lib/soap/marshal.rb @@ -0,0 +1,59 @@ +# SOAP4R - Marshalling/Unmarshalling Ruby's object using SOAP Encoding. +# Copyright (C) 2001, 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require "soap/mapping" +require "soap/processor" + + +module SOAP + + +module Marshal + # Trying xsd:dateTime data to be recovered as aTime. + MarshalMappingRegistry = Mapping::Registry.new( + :allow_original_mapping => true) + MarshalMappingRegistry.add( + Time, + ::SOAP::SOAPDateTime, + ::SOAP::Mapping::Registry::DateTimeFactory + ) + + class << self + public + def dump(obj, io = nil) + marshal(obj, MarshalMappingRegistry, io) + end + + def load(stream) + unmarshal(stream, MarshalMappingRegistry) + end + + def marshal(obj, mapping_registry = MarshalMappingRegistry, io = nil) + elename = Mapping.name2elename(obj.class.to_s) + soap_obj = Mapping.obj2soap(obj, mapping_registry) + body = SOAPBody.new + body.add(elename, soap_obj) + env = SOAPEnvelope.new(nil, body) + SOAP::Processor.marshal(env, {}, io) + end + + def unmarshal(stream, mapping_registry = MarshalMappingRegistry) + env = SOAP::Processor.unmarshal(stream) + if env.nil? + raise ArgumentError.new("Illegal SOAP marshal format.") + end + Mapping.soap2obj(env.body.root_node, mapping_registry) + end + end +end + + +end + + +SOAPMarshal = SOAP::Marshal diff --git a/ruby_1_8_6/lib/soap/mimemessage.rb b/ruby_1_8_6/lib/soap/mimemessage.rb new file mode 100644 index 0000000000..acb4322e11 --- /dev/null +++ b/ruby_1_8_6/lib/soap/mimemessage.rb @@ -0,0 +1,240 @@ +# SOAP4R - MIME Message implementation. +# Copyright (C) 2002 Jamie Herre. + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/attachment' + + +module SOAP + + +# Classes for MIME message handling. Should be put somewhere else! +# Tried using the 'tmail' module but found that I needed something +# lighter in weight. + + +class MIMEMessage + class MIMEMessageError < StandardError; end + + MultipartContentType = 'multipart/\w+' + + class Header + attr_accessor :str, :key, :root + + def initialize + @attrs = {} + end + + def [](key) + @attrs[key] + end + + def []=(key, value) + @attrs[key] = value + end + + def to_s + @key + ": " + @str + end + end + + class Headers < Hash + def self.parse(str) + new.parse(str) + end + + def parse(str) + header_cache = nil + str.each do |line| + case line + when /^\A[^\: \t]+:\s*.+$/ + parse_line(header_cache) if header_cache + header_cache = line.sub(/\r?\n\z/, '') + when /^\A\s+(.*)$/ + # a continuous line at the beginning line crashes here. + header_cache << line + else + raise RuntimeError.new("unexpected header: #{line.inspect}") + end + end + parse_line(header_cache) if header_cache + self + end + + def parse_line(line) + if /^\A([^\: \t]+):\s*(.+)\z/ =~ line + header = parse_rhs($2.strip) + header.key = $1.strip + self[header.key.downcase] = header + else + raise RuntimeError.new("unexpected header line: #{line.inspect}") + end + end + + def parse_rhs(str) + a = str.split(/;+\s+/) + header = Header.new + header.str = str + header.root = a.shift + a.each do |pair| + if pair =~ /(\w+)\s*=\s*"?([^"]+)"?/ + header[$1.downcase] = $2 + else + raise RuntimeError.new("unexpected header component: #{pair.inspect}") + end + end + header + end + + def add(key, value) + if key != nil and value != nil + header = parse_rhs(value) + header.key = key + self[key.downcase] = header + end + end + + def to_s + self.values.collect { |hdr| + hdr.to_s + }.join("\r\n") + end + end + + class Part + attr_accessor :headers, :body + + def initialize + @headers = Headers.new + @headers.add("Content-Transfer-Encoding", "8bit") + @body = nil + @contentid = nil + end + + def self.parse(str) + new.parse(str) + end + + def parse(str) + headers, body = str.split(/\r\n\r\n/s) + if headers != nil and body != nil + @headers = Headers.parse(headers) + @body = body.sub(/\r\n\z/, '') + else + raise RuntimeError.new("unexpected part: #{str.inspect}") + end + self + end + + def contentid + if @contentid == nil and @headers.key?('content-id') + @contentid = @headers['content-id'].str + @contentid = $1 if @contentid =~ /^<(.+)>$/ + end + @contentid + end + + alias content body + + def to_s + @headers.to_s + "\r\n\r\n" + @body + end + end + + def initialize + @parts = [] + @headers = Headers.new + @root = nil + end + + def self.parse(head, str) + new.parse(head, str) + end + + attr_reader :parts, :headers + + def close + @headers.add( + "Content-Type", + "multipart/related; type=\"text/xml\"; boundary=\"#{boundary}\"; start=\"#{@parts[0].contentid}\"" + ) + end + + def parse(head, str) + @headers = Headers.parse(head + "\r\n" + "From: jfh\r\n") + boundary = @headers['content-type']['boundary'] + if boundary != nil + parts = str.split(/--#{Regexp.quote(boundary)}\s*(?:\r\n|--\r\n)/) + part = parts.shift # preamble must be ignored. + @parts = parts.collect { |part| Part.parse(part) } + else + @parts = [Part.parse(str)] + end + if @parts.length < 1 + raise MIMEMessageError.new("This message contains no valid parts!") + end + self + end + + def root + if @root == nil + start = @headers['content-type']['start'] + @root = (start && @parts.find { |prt| prt.contentid == start }) || + @parts[0] + end + @root + end + + def boundary + if @boundary == nil + @boundary = "----=Part_" + __id__.to_s + rand.to_s + end + @boundary + end + + def add_part(content) + part = Part.new + part.headers.add("Content-Type", + "text/xml; charset=" + XSD::Charset.xml_encoding_label) + part.headers.add("Content-ID", Attachment.contentid(part)) + part.body = content + @parts.unshift(part) + end + + def add_attachment(attach) + part = Part.new + part.headers.add("Content-Type", attach.contenttype) + part.headers.add("Content-ID", attach.mime_contentid) + part.body = attach.content + @parts.unshift(part) + end + + def has_parts? + (@parts.length > 0) + end + + def headers_str + @headers.to_s + end + + def content_str + str = '' + @parts.each do |prt| + str << "--" + boundary + "\r\n" + str << prt.to_s + "\r\n" + end + str << '--' + boundary + "--\r\n" + str + end + + def to_s + str = headers_str + "\r\n\r\n" + conent_str + end +end + + +end diff --git a/ruby_1_8_6/lib/soap/netHttpClient.rb b/ruby_1_8_6/lib/soap/netHttpClient.rb new file mode 100644 index 0000000000..10d68e2a4c --- /dev/null +++ b/ruby_1_8_6/lib/soap/netHttpClient.rb @@ -0,0 +1,190 @@ +# SOAP4R - net/http wrapper +# Copyright (C) 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'net/http' + + +module SOAP + + +class NetHttpClient + + SSLEnabled = begin + require 'net/https' + true + rescue LoadError + false + end + + attr_reader :proxy + attr_accessor :no_proxy + attr_accessor :debug_dev + attr_accessor :ssl_config # ignored for now. + attr_accessor :protocol_version # ignored for now. + attr_accessor :connect_timeout + attr_accessor :send_timeout # ignored for now. + attr_accessor :receive_timeout + + def initialize(proxy = nil, agent = nil) + @proxy = proxy ? URI.parse(proxy) : nil + @agent = agent + @debug_dev = nil + @session_manager = SessionManager.new + @no_proxy = @ssl_config = @protocol_version = nil + @connect_timeout = @send_timeout = @receive_timeout = nil + end + + def test_loopback_response + raise NotImplementedError.new("not supported for now") + end + + def proxy=(proxy) + if proxy.nil? + @proxy = nil + else + if proxy.is_a?(URI) + @proxy = proxy + else + @proxy = URI.parse(proxy) + end + if @proxy.scheme == nil or @proxy.scheme.downcase != 'http' or + @proxy.host == nil or @proxy.port == nil + raise ArgumentError.new("unsupported proxy `#{proxy}'") + end + end + reset_all + @proxy + end + + def set_basic_auth(uri, user_id, passwd) + # net/http does not handle url. + @basic_auth = [user_id, passwd] + raise NotImplementedError.new("basic_auth is not supported under soap4r + net/http.") + end + + def set_cookie_store(filename) + raise NotImplementedError.new + end + + def save_cookie_store(filename) + raise NotImplementedError.new + end + + def reset(url) + # no persistent connection. ignored. + end + + def reset_all + # no persistent connection. ignored. + end + + def post(url, req_body, header = {}) + unless url.is_a?(URI) + url = URI.parse(url) + end + extra = header.dup + extra['User-Agent'] = @agent if @agent + res = start(url) { |http| + http.post(url.request_uri, req_body, extra) + } + Response.new(res) + end + + def get_content(url, header = {}) + unless url.is_a?(URI) + url = URI.parse(url) + end + extra = header.dup + extra['User-Agent'] = @agent if @agent + res = start(url) { |http| + http.get(url.request_uri, extra) + } + res.body + end + +private + + def start(url) + http = create_connection(url) + response = nil + http.start { |worker| + response = yield(worker) + worker.finish + } + @debug_dev << response.body if @debug_dev + response + end + + def create_connection(url) + proxy_host = proxy_port = nil + unless no_proxy?(url) + proxy_host = @proxy.host + proxy_port = @proxy.port + end + http = Net::HTTP::Proxy(proxy_host, proxy_port).new(url.host, url.port) + if http.respond_to?(:set_debug_output) + http.set_debug_output(@debug_dev) + end + http.open_timeout = @connect_timeout if @connect_timeout + http.read_timeout = @receive_timeout if @receive_timeout + case url + when URI::HTTPS + if SSLEnabled + http.use_ssl = true + else + raise RuntimeError.new("Cannot connect to #{url} (OpenSSL is not installed.)") + end + when URI::HTTP + # OK + else + raise RuntimeError.new("Cannot connect to #{url} (Not HTTP.)") + end + http + end + + NO_PROXY_HOSTS = ['localhost'] + + def no_proxy?(uri) + if !@proxy or NO_PROXY_HOSTS.include?(uri.host) + return true + end + if @no_proxy + @no_proxy.scan(/([^:,]*)(?::(\d+))?/) do |host, port| + if /(\A|\.)#{Regexp.quote(host)}\z/i =~ uri.host && + (!port || uri.port == port.to_i) + return true + end + end + else + false + end + end + + class SessionManager + attr_accessor :connect_timeout + attr_accessor :send_timeout + attr_accessor :receive_timeout + end + + class Response + attr_reader :content + attr_reader :status + attr_reader :reason + attr_reader :contenttype + + def initialize(res) + @status = res.code.to_i + @reason = res.message + @contenttype = res['content-type'] + @content = res.body + end + end +end + + +end diff --git a/ruby_1_8_6/lib/soap/parser.rb b/ruby_1_8_6/lib/soap/parser.rb new file mode 100644 index 0000000000..412fd4855a --- /dev/null +++ b/ruby_1_8_6/lib/soap/parser.rb @@ -0,0 +1,251 @@ +# SOAP4R - SOAP XML Instance Parser library. +# Copyright (C) 2001, 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'xsd/ns' +require 'xsd/xmlparser' +require 'soap/soap' +require 'soap/baseData' +require 'soap/encodingstyle/handler' + + +module SOAP + + +class Parser + include SOAP + + class ParseError < Error; end + class FormatDecodeError < ParseError; end + class UnexpectedElementError < ParseError; end + +private + + class ParseFrame + attr_reader :node + attr_reader :name + attr_reader :ns, :encodingstyle + + class NodeContainer + def initialize(node) + @node = node + end + + def node + @node + end + + def replace_node(node) + @node = node + end + end + + public + + def initialize(ns, name, node, encodingstyle) + @ns = ns + @name = name + self.node = node + @encodingstyle = encodingstyle + end + + def node=(node) + @node = NodeContainer.new(node) + end + end + +public + + attr_accessor :envelopenamespace + attr_accessor :default_encodingstyle + attr_accessor :decode_typemap + attr_accessor :allow_unqualified_element + + def initialize(opt = {}) + @opt = opt + @parser = XSD::XMLParser.create_parser(self, opt) + @parsestack = nil + @lastnode = nil + @handlers = {} + @envelopenamespace = opt[:envelopenamespace] || EnvelopeNamespace + @default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace + @decode_typemap = opt[:decode_typemap] || nil + @allow_unqualified_element = opt[:allow_unqualified_element] || false + end + + def charset + @parser.charset + end + + def parse(string_or_readable) + @parsestack = [] + @lastnode = nil + + @handlers.each do |uri, handler| + handler.decode_prologue + end + + @parser.do_parse(string_or_readable) + + unless @parsestack.empty? + raise FormatDecodeError.new("Unbalanced tag in XML.") + end + + @handlers.each do |uri, handler| + handler.decode_epilogue + end + + @lastnode + end + + def start_element(name, attrs) + lastframe = @parsestack.last + ns = parent = parent_encodingstyle = nil + if lastframe + ns = lastframe.ns.clone_ns + parent = lastframe.node + parent_encodingstyle = lastframe.encodingstyle + else + ns = XSD::NS.new + parent = ParseFrame::NodeContainer.new(nil) + parent_encodingstyle = nil + end + + attrs = XSD::XMLParser.filter_ns(ns, attrs) + encodingstyle = find_encodingstyle(ns, attrs) + + # Children's encodingstyle is derived from its parent. + if encodingstyle.nil? + if parent.node.is_a?(SOAPHeader) + encodingstyle = LiteralNamespace + else + encodingstyle = parent_encodingstyle || @default_encodingstyle + end + end + + node = decode_tag(ns, name, attrs, parent, encodingstyle) + + @parsestack << ParseFrame.new(ns, name, node, encodingstyle) + end + + def characters(text) + lastframe = @parsestack.last + if lastframe + # Need not to be cloned because character does not have attr. + decode_text(lastframe.ns, text, lastframe.encodingstyle) + else + # Ignore Text outside of SOAP Envelope. + p text if $DEBUG + end + end + + def end_element(name) + lastframe = @parsestack.pop + unless name == lastframe.name + raise UnexpectedElementError.new("Closing element name '#{ name }' does not match with opening element '#{ lastframe.name }'.") + end + decode_tag_end(lastframe.ns, lastframe.node, lastframe.encodingstyle) + @lastnode = lastframe.node.node + end + +private + + def find_encodingstyle(ns, attrs) + attrs.each do |key, value| + if (ns.compare(@envelopenamespace, AttrEncodingStyle, key)) + return value + end + end + nil + end + + def decode_tag(ns, name, attrs, parent, encodingstyle) + ele = ns.parse(name) + + # Envelope based parsing. + if ((ele.namespace == @envelopenamespace) || + (@allow_unqualified_element && ele.namespace.nil?)) + o = decode_soap_envelope(ns, ele, attrs, parent) + return o if o + end + + # Encoding based parsing. + handler = find_handler(encodingstyle) + if handler + return handler.decode_tag(ns, ele, attrs, parent) + else + raise FormatDecodeError.new("Unknown encodingStyle: #{ encodingstyle }.") + end + end + + def decode_tag_end(ns, node, encodingstyle) + return unless encodingstyle + + handler = find_handler(encodingstyle) + if handler + return handler.decode_tag_end(ns, node) + else + raise FormatDecodeError.new("Unknown encodingStyle: #{ encodingstyle }.") + end + end + + def decode_text(ns, text, encodingstyle) + handler = find_handler(encodingstyle) + + if handler + handler.decode_text(ns, text) + else + # How should I do? + end + end + + def decode_soap_envelope(ns, ele, attrs, parent) + o = nil + if ele.name == EleEnvelope + o = SOAPEnvelope.new + if ext = @opt[:external_content] + ext.each do |k, v| + o.external_content[k] = v + end + end + elsif ele.name == EleHeader + unless parent.node.is_a?(SOAPEnvelope) + raise FormatDecodeError.new("Header should be a child of Envelope.") + end + o = SOAPHeader.new + parent.node.header = o + elsif ele.name == EleBody + unless parent.node.is_a?(SOAPEnvelope) + raise FormatDecodeError.new("Body should be a child of Envelope.") + end + o = SOAPBody.new + parent.node.body = o + elsif ele.name == EleFault + unless parent.node.is_a?(SOAPBody) + raise FormatDecodeError.new("Fault should be a child of Body.") + end + o = SOAPFault.new + parent.node.fault = o + end + o + end + + def find_handler(encodingstyle) + unless @handlers.key?(encodingstyle) + handler_factory = SOAP::EncodingStyle::Handler.handler(encodingstyle) || + SOAP::EncodingStyle::Handler.handler(EncodingNamespace) + handler = handler_factory.new(@parser.charset) + handler.decode_typemap = @decode_typemap + handler.decode_prologue + @handlers[encodingstyle] = handler + end + @handlers[encodingstyle] + end +end + + +end diff --git a/ruby_1_8_6/lib/soap/processor.rb b/ruby_1_8_6/lib/soap/processor.rb new file mode 100644 index 0000000000..3c6dbedf2f --- /dev/null +++ b/ruby_1_8_6/lib/soap/processor.rb @@ -0,0 +1,66 @@ +# SOAP4R - marshal/unmarshal interface. +# Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'xsd/datatypes' +require 'soap/soap' +require 'soap/element' +require 'soap/parser' +require 'soap/generator' +require 'soap/encodingstyle/soapHandler' +require 'soap/encodingstyle/literalHandler' +require 'soap/encodingstyle/aspDotNetHandler' + + +module SOAP + + +module Processor + @@default_parser_option = {} + + class << self + public + + def marshal(env, opt = {}, io = nil) + generator = create_generator(opt) + marshalled_str = generator.generate(env, io) + unless env.external_content.empty? + opt[:external_content] = env.external_content + end + marshalled_str + end + + def unmarshal(stream, opt = {}) + parser = create_parser(opt) + parser.parse(stream) + end + + def default_parser_option=(rhs) + @@default_parser_option = rhs + end + + def default_parser_option + @@default_parser_option + end + + private + + def create_generator(opt) + SOAPGenerator.new(opt) + end + + def create_parser(opt) + if opt.empty? + opt = @@default_parser_option + end + ::SOAP::Parser.new(opt) + end + end +end + + +end diff --git a/ruby_1_8_6/lib/soap/property.rb b/ruby_1_8_6/lib/soap/property.rb new file mode 100644 index 0000000000..882dcc6e28 --- /dev/null +++ b/ruby_1_8_6/lib/soap/property.rb @@ -0,0 +1,333 @@ +# soap/property.rb: SOAP4R - Property implementation. +# Copyright (C) 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +module SOAP + + +# Property stream format: +# +# line separator is \r?\n. 1 line per a property. +# line which begins with '#' is a comment line. empty line is ignored, too. +# key/value separator is ':' or '='. +# '\' as escape character. but line separator cannot be escaped. +# \s at the head/tail of key/value are trimmed. +# +# '[' + key + ']' indicates property section. for example, +# +# [aaa.bbb] +# ccc = ddd +# eee.fff = ggg +# [] +# aaa.hhh = iii +# +# is the same as; +# +# aaa.bbb.ccc = ddd +# aaa.bbb.eee.fff = ggg +# aaa.hhh = iii +# +class Property + FrozenError = (RUBY_VERSION >= "1.9.0") ? RuntimeError : TypeError + + include Enumerable + + module Util + def const_from_name(fqname) + fqname.split("::").inject(Kernel) { |klass, name| klass.const_get(name) } + end + module_function :const_from_name + + def require_from_name(fqname) + require File.join(fqname.split("::").collect { |ele| ele.downcase }) + end + module_function :require_from_name + end + + def self.load(stream) + new.load(stream) + end + + def self.loadproperty(propname) + new.loadproperty(propname) + end + + def initialize + @store = Hash.new + @hook = Hash.new + @self_hook = Array.new + @locked = false + end + + KEY_REGSRC = '([^=:\\\\]*(?:\\\\.[^=:\\\\]*)*)' + DEF_REGSRC = '\\s*' + KEY_REGSRC + '\\s*[=:]\\s*(.*)' + COMMENT_REGEXP = Regexp.new('^(?:#.*|)$') + CATDEF_REGEXP = Regexp.new("^\\[\\s*#{KEY_REGSRC}\\s*\\]$") + LINE_REGEXP = Regexp.new("^#{DEF_REGSRC}$") + def load(stream) + key_prefix = "" + stream.each_with_index do |line, lineno| + line.sub!(/\r?\n\z/, '') + case line + when COMMENT_REGEXP + next + when CATDEF_REGEXP + key_prefix = $1.strip + when LINE_REGEXP + key, value = $1.strip, $2.strip + key = "#{key_prefix}.#{key}" unless key_prefix.empty? + key, value = loadstr(key), loadstr(value) + self[key] = value + else + raise TypeError.new( + "property format error at line #{lineno + 1}: `#{line}'") + end + end + self + end + + # find property from $:. + def loadproperty(propname) + return loadpropertyfile(propname) if File.file?(propname) + $:.each do |path| + if File.file?(file = File.join(path, propname)) + return loadpropertyfile(file) + end + end + nil + end + + # name: a Symbol, String or an Array + def [](name) + referent(name_to_a(name)) + end + + # name: a Symbol, String or an Array + # value: an Object + def []=(name, value) + name_pair = name_to_a(name).freeze + hooks = assign(name_pair, value) + hooks.each do |hook| + hook.call(name_pair, value) + end + value + end + + # value: an Object + # key is generated by property + def <<(value) + self[generate_new_key] = value + end + + # name: a Symbol, String or an Array; nil means hook to the root + # cascade: true/false; for cascading hook of sub key + # hook: block which will be called with 2 args, name and value + def add_hook(name = nil, cascade = false, &hook) + if name == nil or name == true or name == false + cascade = name + assign_self_hook(cascade, &hook) + else + assign_hook(name_to_a(name), cascade, &hook) + end + end + + def each + @store.each do |key, value| + yield(key, value) + end + end + + def empty? + @store.empty? + end + + def keys + @store.keys + end + + def values + @store.values + end + + def lock(cascade = false) + if cascade + each_key do |key| + key.lock(cascade) + end + end + @locked = true + self + end + + def unlock(cascade = false) + @locked = false + if cascade + each_key do |key| + key.unlock(cascade) + end + end + self + end + + def locked? + @locked + end + +protected + + def deref_key(key) + check_lock(key) + ref = @store[key] ||= self.class.new + unless propkey?(ref) + raise ArgumentError.new("key `#{key}' already defined as a value") + end + ref + end + + def local_referent(key) + check_lock(key) + if propkey?(@store[key]) and @store[key].locked? + raise FrozenError.new("cannot split any key from locked property") + end + @store[key] + end + + def local_assign(key, value) + check_lock(key) + if @locked + if propkey?(value) + raise FrozenError.new("cannot add any key to locked property") + elsif propkey?(@store[key]) + raise FrozenError.new("cannot override any key in locked property") + end + end + @store[key] = value + end + + def local_hook(key, direct) + hooks = [] + (@self_hook + (@hook[key] || NO_HOOK)).each do |hook, cascade| + hooks << hook if direct or cascade + end + hooks + end + + def local_assign_hook(key, cascade, &hook) + check_lock(key) + @store[key] ||= nil + (@hook[key] ||= []) << [hook, cascade] + end + +private + + NO_HOOK = [].freeze + + def referent(ary) + ary[0..-2].inject(self) { |ref, name| + ref.deref_key(to_key(name)) + }.local_referent(to_key(ary.last)) + end + + def assign(ary, value) + ref = self + hook = NO_HOOK + ary[0..-2].each do |name| + key = to_key(name) + hook += ref.local_hook(key, false) + ref = ref.deref_key(key) + end + last_key = to_key(ary.last) + ref.local_assign(last_key, value) + hook + ref.local_hook(last_key, true) + end + + def assign_hook(ary, cascade, &hook) + ary[0..-2].inject(self) { |ref, name| + ref.deref_key(to_key(name)) + }.local_assign_hook(to_key(ary.last), cascade, &hook) + end + + def assign_self_hook(cascade, &hook) + check_lock(nil) + @self_hook << [hook, cascade] + end + + def each_key + self.each do |key, value| + if propkey?(value) + yield(value) + end + end + end + + def check_lock(key) + if @locked and (key.nil? or !@store.key?(key)) + raise FrozenError.new("cannot add any key to locked property") + end + end + + def propkey?(value) + value.is_a?(::SOAP::Property) + end + + def name_to_a(name) + case name + when Symbol + [name] + when String + name.scan(/[^.\\]+(?:\\.[^.\\])*/) # split with unescaped '.' + when Array + name + else + raise ArgumentError.new("Unknown name #{name}(#{name.class})") + end + end + + def to_key(name) + name.to_s.downcase + end + + def generate_new_key + if @store.empty? + "0" + else + (key_max + 1).to_s + end + end + + def key_max + (@store.keys.max { |l, r| l.to_s.to_i <=> r.to_s.to_i }).to_s.to_i + end + + def loadpropertyfile(file) + puts "find property at #{file}" if $DEBUG + File.open(file) do |f| + load(f) + end + end + + def loadstr(str) + str.gsub(/\\./) { |c| eval("\"#{c}\"") } + end +end + + +end + + +# for ruby/1.6. +unless Enumerable.instance_methods.include?('inject') + module Enumerable + def inject(init) + result = init + each do |item| + result = yield(result, item) + end + result + end + end +end diff --git a/ruby_1_8_6/lib/soap/rpc/cgistub.rb b/ruby_1_8_6/lib/soap/rpc/cgistub.rb new file mode 100644 index 0000000000..487f05a9bf --- /dev/null +++ b/ruby_1_8_6/lib/soap/rpc/cgistub.rb @@ -0,0 +1,206 @@ +# SOAP4R - CGI/mod_ruby stub library +# Copyright (C) 2001, 2003-2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/streamHandler' +require 'webrick/httpresponse' +require 'webrick/httpstatus' +require 'logger' +require 'soap/rpc/soaplet' + + +module SOAP +module RPC + + +### +# SYNOPSIS +# CGIStub.new +# +# DESCRIPTION +# To be written... +# +class CGIStub < Logger::Application + include SOAP + include WEBrick + + class SOAPRequest + attr_reader :body + + def [](var); end + + def meta_vars; end + end + + class SOAPStdinRequest < SOAPRequest + attr_reader :body + + def initialize(stream) + size = ENV['CONTENT_LENGTH'].to_i || 0 + @body = stream.read(size) + end + + def [](var) + ENV[var.gsub(/-/, '_').upcase] + end + + def meta_vars + { + 'HTTP_SOAPACTION' => ENV['HTTP_SOAPAction'] + } + end + end + + class SOAPFCGIRequest < SOAPRequest + attr_reader :body + + def initialize(request) + @request = request + @body = @request.in.read + end + + def [](var) + @request.env[var.gsub(/-/, '_').upcase] + end + + def meta_vars + { + 'HTTP_SOAPACTION' => @request.env['HTTP_SOAPAction'] + } + end + end + + def initialize(appname, default_namespace) + super(appname) + set_log(STDERR) + self.level = ERROR + @default_namespace = default_namespace + @remote_host = ENV['REMOTE_HOST'] || ENV['REMOTE_ADDR'] || 'unknown' + @router = ::SOAP::RPC::Router.new(self.class.name) + @soaplet = ::SOAP::RPC::SOAPlet.new(@router) + on_init + end + + def on_init + # do extra initialization in a derived class if needed. + end + + def mapping_registry + @router.mapping_registry + end + + def mapping_registry=(value) + @router.mapping_registry = value + end + + def generate_explicit_type + @router.generate_explicit_type + end + + def generate_explicit_type=(generate_explicit_type) + @router.generate_explicit_type = generate_explicit_type + end + + # servant entry interface + + def add_rpc_servant(obj, namespace = @default_namespace) + @router.add_rpc_servant(obj, namespace) + end + alias add_servant add_rpc_servant + + def add_headerhandler(obj) + @router.add_headerhandler(obj) + end + alias add_rpc_headerhandler add_headerhandler + + # method entry interface + + def add_rpc_method(obj, name, *param) + add_rpc_method_with_namespace_as(@default_namespace, obj, name, name, *param) + end + alias add_method add_rpc_method + + def add_rpc_method_as(obj, name, name_as, *param) + add_rpc_method_with_namespace_as(@default_namespace, obj, name, name_as, *param) + end + alias add_method_as add_rpc_method_as + + def add_rpc_method_with_namespace(namespace, obj, name, *param) + add_rpc_method_with_namespace_as(namespace, obj, name, name, *param) + end + alias add_method_with_namespace add_rpc_method_with_namespace + + def add_rpc_method_with_namespace_as(namespace, obj, name, name_as, *param) + qname = XSD::QName.new(namespace, name_as) + soapaction = nil + param_def = SOAPMethod.derive_rpc_param_def(obj, name, *param) + @router.add_rpc_operation(obj, qname, soapaction, name, param_def) + end + alias add_method_with_namespace_as add_rpc_method_with_namespace_as + + def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {}) + @router.add_rpc_operation(receiver, qname, soapaction, name, param_def, opt) + end + + def add_document_operation(receiver, soapaction, name, param_def, opt = {}) + @router.add_document_operation(receiver, soapaction, name, param_def, opt) + end + + def set_fcgi_request(request) + @fcgi = request + end + +private + + HTTPVersion = WEBrick::HTTPVersion.new('1.0') # dummy; ignored + + def run + res = WEBrick::HTTPResponse.new({:HTTPVersion => HTTPVersion}) + begin + @log.info { "received a request from '#{ @remote_host }'" } + if @fcgi + req = SOAPFCGIRequest.new(@fcgi) + else + req = SOAPStdinRequest.new($stdin) + end + @soaplet.do_POST(req, res) + rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex + res.set_error(ex) + rescue HTTPStatus::Error => ex + res.set_error(ex) + rescue HTTPStatus::Status => ex + res.status = ex.code + rescue StandardError, NameError => ex # for Ruby 1.6 + res.set_error(ex, true) + ensure + if defined?(MOD_RUBY) + r = Apache.request + r.status = res.status + r.content_type = res.content_type + r.send_http_header + buf = res.body + else + buf = '' + res.send_response(buf) + buf.sub!(/^[^\r]+\r\n/, '') # Trim status line. + end + @log.debug { "SOAP CGI Response:\n#{ buf }" } + if @fcgi + @fcgi.out.print buf + @fcgi.finish + @fcgi = nil + else + print buf + end + end + 0 + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/rpc/driver.rb b/ruby_1_8_6/lib/soap/rpc/driver.rb new file mode 100644 index 0000000000..0fb4e82488 --- /dev/null +++ b/ruby_1_8_6/lib/soap/rpc/driver.rb @@ -0,0 +1,254 @@ +# SOAP4R - SOAP RPC driver +# Copyright (C) 2000, 2001, 2003-2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/soap' +require 'soap/mapping' +require 'soap/mapping/wsdlliteralregistry' +require 'soap/rpc/rpc' +require 'soap/rpc/proxy' +require 'soap/rpc/element' +require 'soap/streamHandler' +require 'soap/property' +require 'soap/header/handlerset' + + +module SOAP +module RPC + + +class Driver + class << self + if RUBY_VERSION >= "1.7.0" + def __attr_proxy(symbol, assignable = false) + name = symbol.to_s + define_method(name) { + @proxy.__send__(name) + } + if assignable + aname = name + '=' + define_method(aname) { |rhs| + @proxy.__send__(aname, rhs) + } + end + end + else + def __attr_proxy(symbol, assignable = false) + name = symbol.to_s + module_eval <<-EOS + def #{name} + @proxy.#{name} + end + EOS + if assignable + module_eval <<-EOS + def #{name}=(value) + @proxy.#{name} = value + end + EOS + end + end + end + end + + __attr_proxy :endpoint_url, true + __attr_proxy :mapping_registry, true + __attr_proxy :default_encodingstyle, true + __attr_proxy :generate_explicit_type, true + __attr_proxy :allow_unqualified_element, true + __attr_proxy :headerhandler + __attr_proxy :streamhandler + __attr_proxy :test_loopback_response + __attr_proxy :reset_stream + + attr_reader :proxy + attr_reader :options + attr_accessor :soapaction + + def inspect + "#<#{self.class}:#{@proxy.inspect}>" + end + + def httpproxy + options["protocol.http.proxy"] + end + + def httpproxy=(httpproxy) + options["protocol.http.proxy"] = httpproxy + end + + def wiredump_dev + options["protocol.http.wiredump_dev"] + end + + def wiredump_dev=(wiredump_dev) + options["protocol.http.wiredump_dev"] = wiredump_dev + end + + def mandatorycharset + options["protocol.mandatorycharset"] + end + + def mandatorycharset=(mandatorycharset) + options["protocol.mandatorycharset"] = mandatorycharset + end + + def wiredump_file_base + options["protocol.wiredump_file_base"] + end + + def wiredump_file_base=(wiredump_file_base) + options["protocol.wiredump_file_base"] = wiredump_file_base + end + + def initialize(endpoint_url, namespace = nil, soapaction = nil) + @namespace = namespace + @soapaction = soapaction + @options = setup_options + @wiredump_file_base = nil + @proxy = Proxy.new(endpoint_url, @soapaction, @options) + end + + def loadproperty(propertyname) + unless options.loadproperty(propertyname) + raise LoadError.new("No such property to load -- #{propertyname}") + end + end + + def add_rpc_method(name, *params) + add_rpc_method_with_soapaction_as(name, name, @soapaction, *params) + end + + def add_rpc_method_as(name, name_as, *params) + add_rpc_method_with_soapaction_as(name, name_as, @soapaction, *params) + end + + def add_rpc_method_with_soapaction(name, soapaction, *params) + add_rpc_method_with_soapaction_as(name, name, soapaction, *params) + end + + def add_rpc_method_with_soapaction_as(name, name_as, soapaction, *params) + param_def = SOAPMethod.create_rpc_param_def(params) + qname = XSD::QName.new(@namespace, name_as) + @proxy.add_rpc_method(qname, soapaction, name, param_def) + add_rpc_method_interface(name, param_def) + end + + # add_method is for shortcut of typical rpc/encoded method definition. + alias add_method add_rpc_method + alias add_method_as add_rpc_method_as + alias add_method_with_soapaction add_rpc_method_with_soapaction + alias add_method_with_soapaction_as add_rpc_method_with_soapaction_as + + def add_document_method(name, soapaction, req_qname, res_qname) + param_def = SOAPMethod.create_doc_param_def(req_qname, res_qname) + @proxy.add_document_method(soapaction, name, param_def) + add_document_method_interface(name, param_def) + end + + def add_rpc_operation(qname, soapaction, name, param_def, opt = {}) + @proxy.add_rpc_operation(qname, soapaction, name, param_def, opt) + add_rpc_method_interface(name, param_def) + end + + def add_document_operation(soapaction, name, param_def, opt = {}) + @proxy.add_document_operation(soapaction, name, param_def, opt) + add_document_method_interface(name, param_def) + end + + def invoke(headers, body) + if headers and !headers.is_a?(SOAPHeader) + headers = create_header(headers) + end + set_wiredump_file_base(body.elename.name) + env = @proxy.invoke(headers, body) + if env.nil? + return nil, nil + else + return env.header, env.body + end + end + + def call(name, *params) + set_wiredump_file_base(name) + @proxy.call(name, *params) + end + +private + + def set_wiredump_file_base(name) + if @wiredump_file_base + @proxy.set_wiredump_file_base("#{@wiredump_file_base}_#{name}") + end + end + + def create_header(headers) + header = SOAPHeader.new() + headers.each do |content, mustunderstand, encodingstyle| + header.add(SOAPHeaderItem.new(content, mustunderstand, encodingstyle)) + end + header + end + + def setup_options + if opt = Property.loadproperty(::SOAP::PropertyName) + opt = opt["client"] + end + opt ||= Property.new + opt.add_hook("protocol.mandatorycharset") do |key, value| + @proxy.mandatorycharset = value + end + opt.add_hook("protocol.wiredump_file_base") do |key, value| + @wiredump_file_base = value + end + opt["protocol.http.charset"] ||= XSD::Charset.xml_encoding_label + opt["protocol.http.proxy"] ||= Env::HTTP_PROXY + opt["protocol.http.no_proxy"] ||= Env::NO_PROXY + opt + end + + def add_rpc_method_interface(name, param_def) + param_count = RPC::SOAPMethod.param_count(param_def, + RPC::SOAPMethod::IN, RPC::SOAPMethod::INOUT) + add_method_interface(name, param_count) + end + + def add_document_method_interface(name, param_def) + param_count = RPC::SOAPMethod.param_count(param_def, RPC::SOAPMethod::IN) + add_method_interface(name, param_count) + end + + if RUBY_VERSION > "1.7.0" + def add_method_interface(name, param_count) + ::SOAP::Mapping.define_singleton_method(self, name) do |*arg| + unless arg.size == param_count + raise ArgumentError.new( + "wrong number of arguments (#{arg.size} for #{param_count})") + end + call(name, *arg) + end + self.method(name) + end + else + def add_method_interface(name, param_count) + instance_eval <<-EOS + def #{name}(*arg) + unless arg.size == #{param_count} + raise ArgumentError.new( + "wrong number of arguments (\#{arg.size} for #{param_count})") + end + call(#{name.dump}, *arg) + end + EOS + self.method(name) + end + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/rpc/element.rb b/ruby_1_8_6/lib/soap/rpc/element.rb new file mode 100644 index 0000000000..c224b03d0d --- /dev/null +++ b/ruby_1_8_6/lib/soap/rpc/element.rb @@ -0,0 +1,325 @@ +# SOAP4R - RPC element definition. +# Copyright (C) 2000, 2001, 2003, 2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/baseData' + + +module SOAP + +# Add method definitions for RPC to common definition in element.rb +class SOAPBody < SOAPStruct + public + + def request + root_node + end + + def response + root = root_node + if !@is_fault + if root.nil? + nil + elsif root.is_a?(SOAPBasetype) + root + else + # Initial element is [retval]. + root[0] + end + else + root + end + end + + def outparams + root = root_node + if !@is_fault and !root.nil? and !root.is_a?(SOAPBasetype) + op = root[1..-1] + op = nil if op && op.empty? + op + else + nil + end + end + + def fault + if @is_fault + self['fault'] + else + nil + end + end + + def fault=(fault) + @is_fault = true + add_member('fault', fault) + end +end + + +module RPC + + +class RPCError < Error; end +class MethodDefinitionError < RPCError; end +class ParameterError < RPCError; end + +class SOAPMethod < SOAPStruct + RETVAL = 'retval' + IN = 'in' + OUT = 'out' + INOUT = 'inout' + + attr_reader :param_def + attr_reader :inparam + attr_reader :outparam + attr_reader :retval_name + attr_reader :retval_class_name + + def initialize(qname, param_def = nil) + super(nil) + @elename = qname + @encodingstyle = nil + + @param_def = param_def + + @signature = [] + @inparam_names = [] + @inoutparam_names = [] + @outparam_names = [] + + @inparam = {} + @outparam = {} + @retval_name = nil + @retval_class_name = nil + + init_param(@param_def) if @param_def + end + + def have_outparam? + @outparam_names.size > 0 + end + + def input_params + collect_params(IN, INOUT) + end + + def output_params + collect_params(OUT, INOUT) + end + + def set_param(params) + params.each do |param, data| + @inparam[param] = data + data.elename.name = param + data.parent = self + end + end + + def set_outparam(params) + params.each do |param, data| + @outparam[param] = data + data.elename.name = param + end + end + + def SOAPMethod.param_count(param_def, *type) + count = 0 + param_def.each do |io_type, name, param_type| + if type.include?(io_type) + count += 1 + end + end + count + end + + def SOAPMethod.derive_rpc_param_def(obj, name, *param) + if param.size == 1 and param[0].is_a?(Array) + return param[0] + end + if param.empty? + method = obj.method(name) + param_names = (1..method.arity.abs).collect { |i| "p#{i}" } + else + param_names = param + end + create_rpc_param_def(param_names) + end + + def SOAPMethod.create_rpc_param_def(param_names) + param_def = [] + param_names.each do |param_name| + param_def.push([IN, param_name, nil]) + end + param_def.push([RETVAL, 'return', nil]) + param_def + end + + def SOAPMethod.create_doc_param_def(req_qnames, res_qnames) + req_qnames = [req_qnames] if req_qnames.is_a?(XSD::QName) + res_qnames = [res_qnames] if res_qnames.is_a?(XSD::QName) + param_def = [] + req_qnames.each do |qname| + param_def << [IN, qname.name, [nil, qname.namespace, qname.name]] + end + res_qnames.each do |qname| + param_def << [OUT, qname.name, [nil, qname.namespace, qname.name]] + end + param_def + end + +private + + def collect_params(*type) + names = [] + @signature.each do |io_type, name, param_type| + names << name if type.include?(io_type) + end + names + end + + def init_param(param_def) + param_def.each do |io_type, name, param_type| + case io_type + when IN + @signature.push([IN, name, param_type]) + @inparam_names.push(name) + when OUT + @signature.push([OUT, name, param_type]) + @outparam_names.push(name) + when INOUT + @signature.push([INOUT, name, param_type]) + @inoutparam_names.push(name) + when RETVAL + if @retval_name + raise MethodDefinitionError.new('duplicated retval') + end + @retval_name = name + @retval_class_name = nil + if param_type + if param_type[0].is_a?(String) + @retval_class_name = Mapping.class_from_name(param_type[0]) + else + @retval_class_name = param_type[0] + end + end + else + raise MethodDefinitionError.new("unknown type: #{io_type}") + end + end + end +end + + +class SOAPMethodRequest < SOAPMethod + attr_accessor :soapaction + + def SOAPMethodRequest.create_request(qname, *params) + param_def = [] + param_value = [] + i = 0 + params.each do |param| + param_name = "p#{i}" + i += 1 + param_def << [IN, param_name, nil] + param_value << [param_name, param] + end + param_def << [RETVAL, 'return', nil] + o = new(qname, param_def) + o.set_param(param_value) + o + end + + def initialize(qname, param_def = nil, soapaction = nil) + check_elename(qname) + super(qname, param_def) + @soapaction = soapaction + end + + def each + input_params.each do |name| + unless @inparam[name] + raise ParameterError.new("parameter: #{name} was not given") + end + yield(name, @inparam[name]) + end + end + + def dup + req = self.class.new(@elename.dup, @param_def, @soapaction) + req.encodingstyle = @encodingstyle + req + end + + def create_method_response(response_name = nil) + response_name ||= + XSD::QName.new(@elename.namespace, @elename.name + 'Response') + SOAPMethodResponse.new(response_name, @param_def) + end + +private + + def check_elename(qname) + # NCName & ruby's method name + unless /\A[\w_][\w\d_\-]*\z/ =~ qname.name + raise MethodDefinitionError.new("element name '#{qname.name}' not allowed") + end + end +end + + +class SOAPMethodResponse < SOAPMethod + + def initialize(qname, param_def = nil) + super(qname, param_def) + @retval = nil + end + + def retval=(retval) + @retval = retval + @retval.elename = @retval.elename.dup_name(@retval_name || 'return') + retval.parent = self + retval + end + + def each + if @retval_name and !@retval.is_a?(SOAPVoid) + yield(@retval_name, @retval) + end + + output_params.each do |name| + unless @outparam[name] + raise ParameterError.new("parameter: #{name} was not given") + end + yield(name, @outparam[name]) + end + end +end + + +# To return(?) void explicitly. +# def foo(input_var) +# ... +# return SOAP::RPC::SOAPVoid.new +# end +class SOAPVoid < XSD::XSDAnySimpleType + include SOAPBasetype + extend SOAPModuleUtils + Name = XSD::QName.new(Mapping::RubyCustomTypeNamespace, nil) + +public + def initialize() + @elename = Name + @id = nil + @precedents = [] + @parent = nil + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/rpc/httpserver.rb b/ruby_1_8_6/lib/soap/rpc/httpserver.rb new file mode 100644 index 0000000000..6d2a72ebe3 --- /dev/null +++ b/ruby_1_8_6/lib/soap/rpc/httpserver.rb @@ -0,0 +1,129 @@ +# SOAP4R - WEBrick HTTP Server +# Copyright (C) 2003, 2004 by NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'logger' +require 'soap/rpc/soaplet' +require 'soap/streamHandler' +require 'webrick' + + +module SOAP +module RPC + + +class HTTPServer < Logger::Application + attr_reader :server + attr_accessor :default_namespace + + def initialize(config) + super(config[:SOAPHTTPServerApplicationName] || self.class.name) + @default_namespace = config[:SOAPDefaultNamespace] + @webrick_config = config.dup + self.level = Logger::Severity::ERROR # keep silent by default + @webrick_config[:Logger] ||= @log + @log = @webrick_config[:Logger] # sync logger of App and HTTPServer + @router = ::SOAP::RPC::Router.new(self.class.name) + @soaplet = ::SOAP::RPC::SOAPlet.new(@router) + on_init + @server = WEBrick::HTTPServer.new(@webrick_config) + @server.mount('/', @soaplet) + end + + def on_init + # do extra initialization in a derived class if needed. + end + + def status + @server.status if @server + end + + def shutdown + @server.shutdown if @server + end + + def mapping_registry + @router.mapping_registry + end + + def mapping_registry=(mapping_registry) + @router.mapping_registry = mapping_registry + end + + def generate_explicit_type + @router.generate_explicit_type + end + + def generate_explicit_type=(generate_explicit_type) + @router.generate_explicit_type = generate_explicit_type + end + + # servant entry interface + + def add_rpc_request_servant(factory, namespace = @default_namespace) + @router.add_rpc_request_servant(factory, namespace) + end + + def add_rpc_servant(obj, namespace = @default_namespace) + @router.add_rpc_servant(obj, namespace) + end + + def add_request_headerhandler(factory) + @router.add_request_headerhandler(factory) + end + + def add_headerhandler(obj) + @router.add_headerhandler(obj) + end + alias add_rpc_headerhandler add_headerhandler + + # method entry interface + + def add_rpc_method(obj, name, *param) + add_rpc_method_as(obj, name, name, *param) + end + alias add_method add_rpc_method + + def add_rpc_method_as(obj, name, name_as, *param) + qname = XSD::QName.new(@default_namespace, name_as) + soapaction = nil + param_def = SOAPMethod.derive_rpc_param_def(obj, name, *param) + @router.add_rpc_operation(obj, qname, soapaction, name, param_def) + end + alias add_method_as add_rpc_method_as + + def add_document_method(obj, soapaction, name, req_qnames, res_qnames) + param_def = SOAPMethod.create_doc_param_def(req_qnames, res_qnames) + @router.add_document_operation(obj, soapaction, name, param_def) + end + + def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {}) + @router.add_rpc_operation(receiver, qname, soapaction, name, param_def, opt) + end + + def add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt = {}) + @router.add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt) + end + + def add_document_operation(receiver, soapaction, name, param_def, opt = {}) + @router.add_document_operation(receiver, soapaction, name, param_def, opt) + end + + def add_document_request_operation(factory, soapaction, name, param_def, opt = {}) + @router.add_document_request_operation(factory, soapaction, name, param_def, opt) + end + +private + + def run + @server.start + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/rpc/proxy.rb b/ruby_1_8_6/lib/soap/rpc/proxy.rb new file mode 100644 index 0000000000..7dfda62006 --- /dev/null +++ b/ruby_1_8_6/lib/soap/rpc/proxy.rb @@ -0,0 +1,497 @@ +# SOAP4R - RPC Proxy library. +# Copyright (C) 2000, 2003-2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/soap' +require 'soap/processor' +require 'soap/mapping' +require 'soap/rpc/rpc' +require 'soap/rpc/element' +require 'soap/streamHandler' +require 'soap/mimemessage' + + +module SOAP +module RPC + + +class Proxy + include SOAP + +public + + attr_accessor :soapaction + attr_accessor :mandatorycharset + attr_accessor :allow_unqualified_element + attr_accessor :default_encodingstyle + attr_accessor :generate_explicit_type + attr_reader :headerhandler + attr_reader :streamhandler + + attr_accessor :mapping_registry + attr_accessor :literal_mapping_registry + + attr_reader :operation + + def initialize(endpoint_url, soapaction, options) + @endpoint_url = endpoint_url + @soapaction = soapaction + @options = options + @streamhandler = HTTPStreamHandler.new( + @options["protocol.http"] ||= ::SOAP::Property.new) + @operation = {} + @mandatorycharset = nil + @allow_unqualified_element = true + @default_encodingstyle = nil + @generate_explicit_type = true + @headerhandler = Header::HandlerSet.new + @mapping_registry = nil + @literal_mapping_registry = ::SOAP::Mapping::WSDLLiteralRegistry.new + end + + def inspect + "#<#{self.class}:#{@endpoint_url}>" + end + + def endpoint_url + @endpoint_url + end + + def endpoint_url=(endpoint_url) + @endpoint_url = endpoint_url + reset_stream + end + + def reset_stream + @streamhandler.reset(@endpoint_url) + end + + def set_wiredump_file_base(wiredump_file_base) + @streamhandler.wiredump_file_base = wiredump_file_base + end + + def test_loopback_response + @streamhandler.test_loopback_response + end + + def add_rpc_operation(qname, soapaction, name, param_def, opt = {}) + opt[:request_qname] = qname + opt[:request_style] ||= :rpc + opt[:response_style] ||= :rpc + opt[:request_use] ||= :encoded + opt[:response_use] ||= :encoded + @operation[name] = Operation.new(soapaction, param_def, opt) + end + + def add_document_operation(soapaction, name, param_def, opt = {}) + opt[:request_style] ||= :document + opt[:response_style] ||= :document + opt[:request_use] ||= :literal + opt[:response_use] ||= :literal + # default values of these values are unqualified in XML Schema. + # set true for backward compatibility. + unless opt.key?(:elementformdefault) + opt[:elementformdefault] = true + end + unless opt.key?(:attributeformdefault) + opt[:attributeformdefault] = true + end + @operation[name] = Operation.new(soapaction, param_def, opt) + end + + # add_method is for shortcut of typical rpc/encoded method definition. + alias add_method add_rpc_operation + alias add_rpc_method add_rpc_operation + alias add_document_method add_document_operation + + def invoke(req_header, req_body, opt = nil) + opt ||= create_encoding_opt + route(req_header, req_body, opt, opt) + end + + def call(name, *params) + unless op_info = @operation[name] + raise MethodDefinitionError, "method: #{name} not defined" + end + mapping_opt = create_mapping_opt + req_header = create_request_header + req_body = SOAPBody.new( + op_info.request_body(params, @mapping_registry, + @literal_mapping_registry, mapping_opt) + ) + reqopt = create_encoding_opt( + :soapaction => op_info.soapaction || @soapaction, + :envelopenamespace => @options["soap.envelope.requestnamespace"], + :default_encodingstyle => + @default_encodingstyle || op_info.request_default_encodingstyle, + :elementformdefault => op_info.elementformdefault, + :attributeformdefault => op_info.attributeformdefault + ) + resopt = create_encoding_opt( + :envelopenamespace => @options["soap.envelope.responsenamespace"], + :default_encodingstyle => + @default_encodingstyle || op_info.response_default_encodingstyle, + :elementformdefault => op_info.elementformdefault, + :attributeformdefault => op_info.attributeformdefault + ) + env = route(req_header, req_body, reqopt, resopt) + raise EmptyResponseError unless env + receive_headers(env.header) + begin + check_fault(env.body) + rescue ::SOAP::FaultError => e + op_info.raise_fault(e, @mapping_registry, @literal_mapping_registry) + end + op_info.response_obj(env.body, @mapping_registry, + @literal_mapping_registry, mapping_opt) + end + + def route(req_header, req_body, reqopt, resopt) + req_env = ::SOAP::SOAPEnvelope.new(req_header, req_body) + unless reqopt[:envelopenamespace].nil? + set_envelopenamespace(req_env, reqopt[:envelopenamespace]) + end + reqopt[:external_content] = nil + conn_data = marshal(req_env, reqopt) + if ext = reqopt[:external_content] + mime = MIMEMessage.new + ext.each do |k, v| + mime.add_attachment(v.data) + end + mime.add_part(conn_data.send_string + "\r\n") + mime.close + conn_data.send_string = mime.content_str + conn_data.send_contenttype = mime.headers['content-type'].str + end + conn_data = @streamhandler.send(@endpoint_url, conn_data, + reqopt[:soapaction]) + if conn_data.receive_string.empty? + return nil + end + unmarshal(conn_data, resopt) + end + + def check_fault(body) + if body.fault + raise SOAP::FaultError.new(body.fault) + end + end + +private + + def set_envelopenamespace(env, namespace) + env.elename = XSD::QName.new(namespace, env.elename.name) + if env.header + env.header.elename = XSD::QName.new(namespace, env.header.elename.name) + end + if env.body + env.body.elename = XSD::QName.new(namespace, env.body.elename.name) + end + end + + def create_request_header + headers = @headerhandler.on_outbound + if headers.empty? + nil + else + h = ::SOAP::SOAPHeader.new + headers.each do |header| + h.add(header.elename.name, header) + end + h + end + end + + def receive_headers(headers) + @headerhandler.on_inbound(headers) if headers + end + + def marshal(env, opt) + send_string = Processor.marshal(env, opt) + StreamHandler::ConnectionData.new(send_string) + end + + def unmarshal(conn_data, opt) + contenttype = conn_data.receive_contenttype + if /#{MIMEMessage::MultipartContentType}/i =~ contenttype + opt[:external_content] = {} + mime = MIMEMessage.parse("Content-Type: " + contenttype, + conn_data.receive_string) + mime.parts.each do |part| + value = Attachment.new(part.content) + value.contentid = part.contentid + obj = SOAPAttachment.new(value) + opt[:external_content][value.contentid] = obj if value.contentid + end + opt[:charset] = @mandatorycharset || + StreamHandler.parse_media_type(mime.root.headers['content-type'].str) + env = Processor.unmarshal(mime.root.content, opt) + else + opt[:charset] = @mandatorycharset || + ::SOAP::StreamHandler.parse_media_type(contenttype) + env = Processor.unmarshal(conn_data.receive_string, opt) + end + unless env.is_a?(::SOAP::SOAPEnvelope) + raise ResponseFormatError.new( + "response is not a SOAP envelope: #{conn_data.receive_string}") + end + env + end + + def create_header(headers) + header = SOAPHeader.new() + headers.each do |content, mustunderstand, encodingstyle| + header.add(SOAPHeaderItem.new(content, mustunderstand, encodingstyle)) + end + header + end + + def create_encoding_opt(hash = nil) + opt = {} + opt[:default_encodingstyle] = @default_encodingstyle + opt[:allow_unqualified_element] = @allow_unqualified_element + opt[:generate_explicit_type] = @generate_explicit_type + opt[:no_indent] = @options["soap.envelope.no_indent"] + opt[:use_numeric_character_reference] = + @options["soap.envelope.use_numeric_character_reference"] + opt.update(hash) if hash + opt + end + + def create_mapping_opt(hash = nil) + opt = { + :external_ces => @options["soap.mapping.external_ces"] + } + opt.update(hash) if hash + opt + end + + class Operation + attr_reader :soapaction + attr_reader :request_style + attr_reader :response_style + attr_reader :request_use + attr_reader :response_use + attr_reader :elementformdefault + attr_reader :attributeformdefault + + def initialize(soapaction, param_def, opt) + @soapaction = soapaction + @request_style = opt[:request_style] + @response_style = opt[:response_style] + @request_use = opt[:request_use] + @response_use = opt[:response_use] + # set nil(unqualified) by default + @elementformdefault = opt[:elementformdefault] + @attributeformdefault = opt[:attributeformdefault] + check_style(@request_style) + check_style(@response_style) + check_use(@request_use) + check_use(@response_use) + if @request_style == :rpc + @rpc_request_qname = opt[:request_qname] + if @rpc_request_qname.nil? + raise MethodDefinitionError.new("rpc_request_qname must be given") + end + @rpc_method_factory = + RPC::SOAPMethodRequest.new(@rpc_request_qname, param_def, @soapaction) + else + @doc_request_qnames = [] + @doc_request_qualified = [] + @doc_response_qnames = [] + @doc_response_qualified = [] + param_def.each do |inout, paramname, typeinfo, eleinfo| + klass_not_used, nsdef, namedef = typeinfo + qualified = eleinfo + if namedef.nil? + raise MethodDefinitionError.new("qname must be given") + end + case inout + when SOAPMethod::IN + @doc_request_qnames << XSD::QName.new(nsdef, namedef) + @doc_request_qualified << qualified + when SOAPMethod::OUT + @doc_response_qnames << XSD::QName.new(nsdef, namedef) + @doc_response_qualified << qualified + else + raise MethodDefinitionError.new( + "illegal inout definition for document style: #{inout}") + end + end + end + end + + def request_default_encodingstyle + (@request_use == :encoded) ? EncodingNamespace : LiteralNamespace + end + + def response_default_encodingstyle + (@response_use == :encoded) ? EncodingNamespace : LiteralNamespace + end + + def request_body(values, mapping_registry, literal_mapping_registry, opt) + if @request_style == :rpc + request_rpc(values, mapping_registry, literal_mapping_registry, opt) + else + request_doc(values, mapping_registry, literal_mapping_registry, opt) + end + end + + def response_obj(body, mapping_registry, literal_mapping_registry, opt) + if @response_style == :rpc + response_rpc(body, mapping_registry, literal_mapping_registry, opt) + else + response_doc(body, mapping_registry, literal_mapping_registry, opt) + end + end + + def raise_fault(e, mapping_registry, literal_mapping_registry) + if @response_style == :rpc + Mapping.fault2exception(e, mapping_registry) + else + Mapping.fault2exception(e, literal_mapping_registry) + end + end + + private + + def check_style(style) + unless [:rpc, :document].include?(style) + raise MethodDefinitionError.new("unknown style: #{style}") + end + end + + def check_use(use) + unless [:encoded, :literal].include?(use) + raise MethodDefinitionError.new("unknown use: #{use}") + end + end + + def request_rpc(values, mapping_registry, literal_mapping_registry, opt) + if @request_use == :encoded + request_rpc_enc(values, mapping_registry, opt) + else + request_rpc_lit(values, literal_mapping_registry, opt) + end + end + + def request_doc(values, mapping_registry, literal_mapping_registry, opt) + if @request_use == :encoded + request_doc_enc(values, mapping_registry, opt) + else + request_doc_lit(values, literal_mapping_registry, opt) + end + end + + def request_rpc_enc(values, mapping_registry, opt) + method = @rpc_method_factory.dup + names = method.input_params + obj = create_request_obj(names, values) + soap = Mapping.obj2soap(obj, mapping_registry, @rpc_request_qname, opt) + method.set_param(soap) + method + end + + def request_rpc_lit(values, mapping_registry, opt) + method = @rpc_method_factory.dup + params = {} + idx = 0 + method.input_params.each do |name| + params[name] = Mapping.obj2soap(values[idx], mapping_registry, + XSD::QName.new(nil, name), opt) + idx += 1 + end + method.set_param(params) + method + end + + def request_doc_enc(values, mapping_registry, opt) + (0...values.size).collect { |idx| + ele = Mapping.obj2soap(values[idx], mapping_registry, nil, opt) + ele.elename = @doc_request_qnames[idx] + ele + } + end + + def request_doc_lit(values, mapping_registry, opt) + (0...values.size).collect { |idx| + ele = Mapping.obj2soap(values[idx], mapping_registry, + @doc_request_qnames[idx], opt) + ele.encodingstyle = LiteralNamespace + if ele.respond_to?(:qualified) + ele.qualified = @doc_request_qualified[idx] + end + ele + } + end + + def response_rpc(body, mapping_registry, literal_mapping_registry, opt) + if @response_use == :encoded + response_rpc_enc(body, mapping_registry, opt) + else + response_rpc_lit(body, literal_mapping_registry, opt) + end + end + + def response_doc(body, mapping_registry, literal_mapping_registry, opt) + if @response_use == :encoded + return *response_doc_enc(body, mapping_registry, opt) + else + return *response_doc_lit(body, literal_mapping_registry, opt) + end + end + + def response_rpc_enc(body, mapping_registry, opt) + ret = nil + if body.response + ret = Mapping.soap2obj(body.response, mapping_registry, + @rpc_method_factory.retval_class_name, opt) + end + if body.outparams + outparams = body.outparams.collect { |outparam| + Mapping.soap2obj(outparam, mapping_registry, nil, opt) + } + [ret].concat(outparams) + else + ret + end + end + + def response_rpc_lit(body, mapping_registry, opt) + body.root_node.collect { |key, value| + Mapping.soap2obj(value, mapping_registry, + @rpc_method_factory.retval_class_name, opt) + } + end + + def response_doc_enc(body, mapping_registry, opt) + body.collect { |key, value| + Mapping.soap2obj(value, mapping_registry, nil, opt) + } + end + + def response_doc_lit(body, mapping_registry, opt) + body.collect { |key, value| + Mapping.soap2obj(value, mapping_registry) + } + end + + def create_request_obj(names, params) + o = Object.new + idx = 0 + while idx < params.length + o.instance_variable_set('@' + names[idx], params[idx]) + idx += 1 + end + o + end + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/rpc/router.rb b/ruby_1_8_6/lib/soap/rpc/router.rb new file mode 100644 index 0000000000..71c6eb625b --- /dev/null +++ b/ruby_1_8_6/lib/soap/rpc/router.rb @@ -0,0 +1,594 @@ +# SOAP4R - RPC Routing library +# Copyright (C) 2001, 2002, 2004, 2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/soap' +require 'soap/processor' +require 'soap/mapping' +require 'soap/mapping/wsdlliteralregistry' +require 'soap/rpc/rpc' +require 'soap/rpc/element' +require 'soap/streamHandler' +require 'soap/mimemessage' +require 'soap/header/handlerset' + + +module SOAP +module RPC + + +class Router + include SOAP + + attr_reader :actor + attr_accessor :mapping_registry + attr_accessor :literal_mapping_registry + attr_accessor :generate_explicit_type + attr_accessor :external_ces + + def initialize(actor) + @actor = actor + @mapping_registry = nil + @headerhandler = Header::HandlerSet.new + @literal_mapping_registry = ::SOAP::Mapping::WSDLLiteralRegistry.new + @generate_explicit_type = true + @external_ces = nil + @operation_by_soapaction = {} + @operation_by_qname = {} + @headerhandlerfactory = [] + end + + ### + ## header handler interface + # + def add_request_headerhandler(factory) + unless factory.respond_to?(:create) + raise TypeError.new("factory must respond to 'create'") + end + @headerhandlerfactory << factory + end + + def add_headerhandler(handler) + @headerhandler.add(handler) + end + + ### + ## servant definition interface + # + def add_rpc_request_servant(factory, namespace) + unless factory.respond_to?(:create) + raise TypeError.new("factory must respond to 'create'") + end + obj = factory.create # a dummy instance for introspection + ::SOAP::RPC.defined_methods(obj).each do |name| + begin + qname = XSD::QName.new(namespace, name) + param_def = ::SOAP::RPC::SOAPMethod.derive_rpc_param_def(obj, name) + opt = create_styleuse_option(:rpc, :encoded) + add_rpc_request_operation(factory, qname, nil, name, param_def, opt) + rescue SOAP::RPC::MethodDefinitionError => e + p e if $DEBUG + end + end + end + + def add_rpc_servant(obj, namespace) + ::SOAP::RPC.defined_methods(obj).each do |name| + begin + qname = XSD::QName.new(namespace, name) + param_def = ::SOAP::RPC::SOAPMethod.derive_rpc_param_def(obj, name) + opt = create_styleuse_option(:rpc, :encoded) + add_rpc_operation(obj, qname, nil, name, param_def, opt) + rescue SOAP::RPC::MethodDefinitionError => e + p e if $DEBUG + end + end + end + alias add_servant add_rpc_servant + + ### + ## operation definition interface + # + def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {}) + ensure_styleuse_option(opt, :rpc, :encoded) + opt[:request_qname] = qname + op = ApplicationScopeOperation.new(soapaction, receiver, name, param_def, + opt) + if opt[:request_style] != :rpc + raise RPCRoutingError.new("illegal request_style given") + end + assign_operation(soapaction, qname, op) + end + alias add_method add_rpc_operation + alias add_rpc_method add_rpc_operation + + def add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt = {}) + ensure_styleuse_option(opt, :rpc, :encoded) + opt[:request_qname] = qname + op = RequestScopeOperation.new(soapaction, factory, name, param_def, opt) + if opt[:request_style] != :rpc + raise RPCRoutingError.new("illegal request_style given") + end + assign_operation(soapaction, qname, op) + end + + def add_document_operation(receiver, soapaction, name, param_def, opt = {}) + # + # adopt workaround for doc/lit wrapper method + # (you should consider to simply use rpc/lit service) + # + #unless soapaction + # raise RPCRoutingError.new("soapaction is a must for document method") + #end + ensure_styleuse_option(opt, :document, :literal) + op = ApplicationScopeOperation.new(soapaction, receiver, name, param_def, + opt) + if opt[:request_style] != :document + raise RPCRoutingError.new("illegal request_style given") + end + assign_operation(soapaction, first_input_part_qname(param_def), op) + end + alias add_document_method add_document_operation + + def add_document_request_operation(factory, soapaction, name, param_def, opt = {}) + # + # adopt workaround for doc/lit wrapper method + # (you should consider to simply use rpc/lit service) + # + #unless soapaction + # raise RPCRoutingError.new("soapaction is a must for document method") + #end + ensure_styleuse_option(opt, :document, :literal) + op = RequestScopeOperation.new(soapaction, receiver, name, param_def, opt) + if opt[:request_style] != :document + raise RPCRoutingError.new("illegal request_style given") + end + assign_operation(soapaction, first_input_part_qname(param_def), op) + end + + def route(conn_data) + # we cannot set request_default_encodingsyle before parsing the content. + env = unmarshal(conn_data) + if env.nil? + raise ArgumentError.new("illegal SOAP marshal format") + end + op = lookup_operation(conn_data.soapaction, env.body) + headerhandler = @headerhandler.dup + @headerhandlerfactory.each do |f| + headerhandler.add(f.create) + end + receive_headers(headerhandler, env.header) + soap_response = default_encodingstyle = nil + begin + soap_response = + op.call(env.body, @mapping_registry, @literal_mapping_registry, + create_mapping_opt) + default_encodingstyle = op.response_default_encodingstyle + rescue Exception + soap_response = fault($!) + default_encodingstyle = nil + end + conn_data.is_fault = true if soap_response.is_a?(SOAPFault) + header = call_headers(headerhandler) + body = SOAPBody.new(soap_response) + env = SOAPEnvelope.new(header, body) + marshal(conn_data, env, default_encodingstyle) + end + + # Create fault response string. + def create_fault_response(e) + env = SOAPEnvelope.new(SOAPHeader.new, SOAPBody.new(fault(e))) + opt = {} + opt[:external_content] = nil + response_string = Processor.marshal(env, opt) + conn_data = StreamHandler::ConnectionData.new(response_string) + conn_data.is_fault = true + if ext = opt[:external_content] + mimeize(conn_data, ext) + end + conn_data + end + +private + + def first_input_part_qname(param_def) + param_def.each do |inout, paramname, typeinfo| + if inout == SOAPMethod::IN + klass, nsdef, namedef = typeinfo + return XSD::QName.new(nsdef, namedef) + end + end + nil + end + + def create_styleuse_option(style, use) + opt = {} + opt[:request_style] = opt[:response_style] = style + opt[:request_use] = opt[:response_use] = use + opt + end + + def ensure_styleuse_option(opt, style, use) + opt[:request_style] ||= style + opt[:response_style] ||= style + opt[:request_use] ||= use + opt[:response_use] ||= use + end + + def assign_operation(soapaction, qname, op) + assigned = false + if soapaction and !soapaction.empty? + @operation_by_soapaction[soapaction] = op + assigned = true + end + if qname + @operation_by_qname[qname] = op + assigned = true + end + unless assigned + raise RPCRoutingError.new("cannot assign operation") + end + end + + def lookup_operation(soapaction, body) + if op = @operation_by_soapaction[soapaction] + return op + end + qname = body.root_node.elename + if op = @operation_by_qname[qname] + return op + end + if soapaction + raise RPCRoutingError.new( + "operation: #{soapaction} #{qname} not supported") + else + raise RPCRoutingError.new("operation: #{qname} not supported") + end + end + + def call_headers(headerhandler) + headers = headerhandler.on_outbound + if headers.empty? + nil + else + h = ::SOAP::SOAPHeader.new + headers.each do |header| + h.add(header.elename.name, header) + end + h + end + end + + def receive_headers(headerhandler, headers) + headerhandler.on_inbound(headers) if headers + end + + def unmarshal(conn_data) + opt = {} + contenttype = conn_data.receive_contenttype + if /#{MIMEMessage::MultipartContentType}/i =~ contenttype + opt[:external_content] = {} + mime = MIMEMessage.parse("Content-Type: " + contenttype, + conn_data.receive_string) + mime.parts.each do |part| + value = Attachment.new(part.content) + value.contentid = part.contentid + obj = SOAPAttachment.new(value) + opt[:external_content][value.contentid] = obj if value.contentid + end + opt[:charset] = + StreamHandler.parse_media_type(mime.root.headers['content-type'].str) + env = Processor.unmarshal(mime.root.content, opt) + else + opt[:charset] = ::SOAP::StreamHandler.parse_media_type(contenttype) + env = Processor.unmarshal(conn_data.receive_string, opt) + end + charset = opt[:charset] + conn_data.send_contenttype = "text/xml; charset=\"#{charset}\"" + env + end + + def marshal(conn_data, env, default_encodingstyle = nil) + opt = {} + opt[:external_content] = nil + opt[:default_encodingstyle] = default_encodingstyle + opt[:generate_explicit_type] = @generate_explicit_type + response_string = Processor.marshal(env, opt) + conn_data.send_string = response_string + if ext = opt[:external_content] + mimeize(conn_data, ext) + end + conn_data + end + + def mimeize(conn_data, ext) + mime = MIMEMessage.new + ext.each do |k, v| + mime.add_attachment(v.data) + end + mime.add_part(conn_data.send_string + "\r\n") + mime.close + conn_data.send_string = mime.content_str + conn_data.send_contenttype = mime.headers['content-type'].str + conn_data + end + + # Create fault response. + def fault(e) + detail = Mapping::SOAPException.new(e) + SOAPFault.new( + SOAPString.new('Server'), + SOAPString.new(e.to_s), + SOAPString.new(@actor), + Mapping.obj2soap(detail, @mapping_registry)) + end + + def create_mapping_opt + { :external_ces => @external_ces } + end + + class Operation + attr_reader :name + attr_reader :soapaction + attr_reader :request_style + attr_reader :response_style + attr_reader :request_use + attr_reader :response_use + + def initialize(soapaction, name, param_def, opt) + @soapaction = soapaction + @name = name + @request_style = opt[:request_style] + @response_style = opt[:response_style] + @request_use = opt[:request_use] + @response_use = opt[:response_use] + check_style(@request_style) + check_style(@response_style) + check_use(@request_use) + check_use(@response_use) + if @response_style == :rpc + request_qname = opt[:request_qname] or raise + @rpc_method_factory = + RPC::SOAPMethodRequest.new(request_qname, param_def, @soapaction) + @rpc_response_qname = opt[:response_qname] + else + @doc_request_qnames = [] + @doc_request_qualified = [] + @doc_response_qnames = [] + @doc_response_qualified = [] + param_def.each do |inout, paramname, typeinfo, eleinfo| + klass, nsdef, namedef = typeinfo + qualified = eleinfo + case inout + when SOAPMethod::IN + @doc_request_qnames << XSD::QName.new(nsdef, namedef) + @doc_request_qualified << qualified + when SOAPMethod::OUT + @doc_response_qnames << XSD::QName.new(nsdef, namedef) + @doc_response_qualified << qualified + else + raise ArgumentError.new( + "illegal inout definition for document style: #{inout}") + end + end + end + end + + def request_default_encodingstyle + (@request_use == :encoded) ? EncodingNamespace : LiteralNamespace + end + + def response_default_encodingstyle + (@response_use == :encoded) ? EncodingNamespace : LiteralNamespace + end + + def call(body, mapping_registry, literal_mapping_registry, opt) + if @request_style == :rpc + values = request_rpc(body, mapping_registry, literal_mapping_registry, + opt) + else + values = request_document(body, mapping_registry, + literal_mapping_registry, opt) + end + result = receiver.method(@name.intern).call(*values) + return result if result.is_a?(SOAPFault) + if @response_style == :rpc + response_rpc(result, mapping_registry, literal_mapping_registry, opt) + else + response_doc(result, mapping_registry, literal_mapping_registry, opt) + end + end + + private + + def receiver + raise NotImplementedError.new('must be defined in derived class') + end + + def request_rpc(body, mapping_registry, literal_mapping_registry, opt) + request = body.request + unless request.is_a?(SOAPStruct) + raise RPCRoutingError.new("not an RPC style") + end + if @request_use == :encoded + request_rpc_enc(request, mapping_registry, opt) + else + request_rpc_lit(request, literal_mapping_registry, opt) + end + end + + def request_document(body, mapping_registry, literal_mapping_registry, opt) + # ToDo: compare names with @doc_request_qnames + if @request_use == :encoded + request_doc_enc(body, mapping_registry, opt) + else + request_doc_lit(body, literal_mapping_registry, opt) + end + end + + def request_rpc_enc(request, mapping_registry, opt) + param = Mapping.soap2obj(request, mapping_registry, nil, opt) + request.collect { |key, value| + param[key] + } + end + + def request_rpc_lit(request, mapping_registry, opt) + request.collect { |key, value| + Mapping.soap2obj(value, mapping_registry, nil, opt) + } + end + + def request_doc_enc(body, mapping_registry, opt) + body.collect { |key, value| + Mapping.soap2obj(value, mapping_registry, nil, opt) + } + end + + def request_doc_lit(body, mapping_registry, opt) + body.collect { |key, value| + Mapping.soap2obj(value, mapping_registry, nil, opt) + } + end + + def response_rpc(result, mapping_registry, literal_mapping_registry, opt) + if @response_use == :encoded + response_rpc_enc(result, mapping_registry, opt) + else + response_rpc_lit(result, literal_mapping_registry, opt) + end + end + + def response_doc(result, mapping_registry, literal_mapping_registry, opt) + if @doc_response_qnames.size == 1 and !result.is_a?(Array) + result = [result] + end + if result.size != @doc_response_qnames.size + raise "required #{@doc_response_qnames.size} responses " + + "but #{result.size} given" + end + if @response_use == :encoded + response_doc_enc(result, mapping_registry, opt) + else + response_doc_lit(result, literal_mapping_registry, opt) + end + end + + def response_rpc_enc(result, mapping_registry, opt) + soap_response = + @rpc_method_factory.create_method_response(@rpc_response_qname) + if soap_response.have_outparam? + unless result.is_a?(Array) + raise RPCRoutingError.new("out parameter was not returned") + end + outparams = {} + i = 1 + soap_response.output_params.each do |outparam| + outparams[outparam] = Mapping.obj2soap(result[i], mapping_registry, + nil, opt) + i += 1 + end + soap_response.set_outparam(outparams) + soap_response.retval = Mapping.obj2soap(result[0], mapping_registry, + nil, opt) + else + soap_response.retval = Mapping.obj2soap(result, mapping_registry, nil, + opt) + end + soap_response + end + + def response_rpc_lit(result, mapping_registry, opt) + soap_response = + @rpc_method_factory.create_method_response(@rpc_response_qname) + if soap_response.have_outparam? + unless result.is_a?(Array) + raise RPCRoutingError.new("out parameter was not returned") + end + outparams = {} + i = 1 + soap_response.output_params.each do |outparam| + outparams[outparam] = Mapping.obj2soap(result[i], mapping_registry, + XSD::QName.new(nil, outparam), opt) + i += 1 + end + soap_response.set_outparam(outparams) + soap_response.retval = Mapping.obj2soap(result[0], mapping_registry, + XSD::QName.new(nil, soap_response.elename), opt) + else + soap_response.retval = Mapping.obj2soap(result, mapping_registry, + XSD::QName.new(nil, soap_response.elename), opt) + end + soap_response + end + + def response_doc_enc(result, mapping_registry, opt) + (0...result.size).collect { |idx| + ele = Mapping.obj2soap(result[idx], mapping_registry, nil, opt) + ele.elename = @doc_response_qnames[idx] + ele + } + end + + def response_doc_lit(result, mapping_registry, opt) + (0...result.size).collect { |idx| + ele = Mapping.obj2soap(result[idx], mapping_registry, + @doc_response_qnames[idx]) + ele.encodingstyle = LiteralNamespace + if ele.respond_to?(:qualified) + ele.qualified = @doc_response_qualified[idx] + end + ele + } + end + + def check_style(style) + unless [:rpc, :document].include?(style) + raise ArgumentError.new("unknown style: #{style}") + end + end + + def check_use(use) + unless [:encoded, :literal].include?(use) + raise ArgumentError.new("unknown use: #{use}") + end + end + end + + class ApplicationScopeOperation < Operation + def initialize(soapaction, receiver, name, param_def, opt) + super(soapaction, name, param_def, opt) + @receiver = receiver + end + + private + + def receiver + @receiver + end + end + + class RequestScopeOperation < Operation + def initialize(soapaction, receiver_factory, name, param_def, opt) + super(soapaction, name, param_def, opt) + unless receiver_factory.respond_to?(:create) + raise TypeError.new("factory must respond to 'create'") + end + @receiver_factory = receiver_factory + end + + private + + def receiver + @receiver_factory.create + end + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/rpc/rpc.rb b/ruby_1_8_6/lib/soap/rpc/rpc.rb new file mode 100644 index 0000000000..a48b525dbb --- /dev/null +++ b/ruby_1_8_6/lib/soap/rpc/rpc.rb @@ -0,0 +1,25 @@ +# SOAP4R - RPC utility. +# Copyright (C) 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +module SOAP + + +module RPC + ServerException = Mapping::MappedException + + def self.defined_methods(obj) + if obj.is_a?(Module) + obj.methods - Module.methods + else + obj.methods - Object.instance_methods(true) + end + end +end + + +end diff --git a/ruby_1_8_6/lib/soap/rpc/soaplet.rb b/ruby_1_8_6/lib/soap/rpc/soaplet.rb new file mode 100644 index 0000000000..7cccdd3e31 --- /dev/null +++ b/ruby_1_8_6/lib/soap/rpc/soaplet.rb @@ -0,0 +1,162 @@ +# SOAP4R - SOAP handler servlet for WEBrick +# Copyright (C) 2001-2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'webrick/httpservlet/abstract' +require 'webrick/httpstatus' +require 'soap/rpc/router' +require 'soap/streamHandler' +begin + require 'stringio' + require 'zlib' +rescue LoadError + warn("Loading stringio or zlib failed. No gzipped response supported.") if $DEBUG +end + + +warn("Overriding WEBrick::Log#debug") if $DEBUG +require 'webrick/log' +module WEBrick + class Log < BasicLog + alias __debug debug + def debug(msg = nil) + if block_given? and msg.nil? + __debug(yield) + else + __debug(msg) + end + end + end +end + + +module SOAP +module RPC + + +class SOAPlet < WEBrick::HTTPServlet::AbstractServlet +public + attr_reader :options + + def initialize(router = nil) + @router = router || ::SOAP::RPC::Router.new(self.class.name) + @options = {} + @config = {} + end + + # for backward compatibility + def app_scope_router + @router + end + + # for backward compatibility + def add_servant(obj, namespace) + @router.add_rpc_servant(obj, namespace) + end + + def allow_content_encoding_gzip=(allow) + @options[:allow_content_encoding_gzip] = allow + end + + ### + ## Servlet interfaces for WEBrick. + # + def get_instance(config, *options) + @config = config + self + end + + def require_path_info? + false + end + + def do_GET(req, res) + res.header['Allow'] = 'POST' + raise WEBrick::HTTPStatus::MethodNotAllowed, "GET request not allowed" + end + + def do_POST(req, res) + logger.debug { "SOAP request: " + req.body } if logger + begin + conn_data = ::SOAP::StreamHandler::ConnectionData.new + setup_req(conn_data, req) + @router.external_ces = @options[:external_ces] + conn_data = @router.route(conn_data) + setup_res(conn_data, req, res) + rescue Exception => e + conn_data = @router.create_fault_response(e) + res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR + res.body = conn_data.send_string + res['content-type'] = conn_data.send_contenttype || "text/xml" + end + if res.body.is_a?(IO) + res.chunked = true + logger.debug { "SOAP response: (chunked response not logged)" } if logger + else + logger.debug { "SOAP response: " + res.body } if logger + end + end + +private + + def logger + @config[:Logger] + end + + def setup_req(conn_data, req) + conn_data.receive_string = req.body + conn_data.receive_contenttype = req['content-type'] + conn_data.soapaction = parse_soapaction(req.meta_vars['HTTP_SOAPACTION']) + end + + def setup_res(conn_data, req, res) + res['content-type'] = conn_data.send_contenttype + if conn_data.is_fault + res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR + end + if outstring = encode_gzip(req, conn_data.send_string) + res['content-encoding'] = 'gzip' + res['content-length'] = outstring.size + res.body = outstring + else + res.body = conn_data.send_string + end + end + + def parse_soapaction(soapaction) + if !soapaction.nil? and !soapaction.empty? + if /^"(.+)"$/ =~ soapaction + return $1 + end + end + nil + end + + def encode_gzip(req, outstring) + unless encode_gzip?(req) + return nil + end + begin + ostream = StringIO.new + gz = Zlib::GzipWriter.new(ostream) + gz.write(outstring) + ostream.string + ensure + gz.close + end + end + + def encode_gzip?(req) + @options[:allow_content_encoding_gzip] and defined?(::Zlib) and + req['accept-encoding'] and + req['accept-encoding'].split(/,\s*/).include?('gzip') + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/rpc/standaloneServer.rb b/ruby_1_8_6/lib/soap/rpc/standaloneServer.rb new file mode 100644 index 0000000000..080343ba33 --- /dev/null +++ b/ruby_1_8_6/lib/soap/rpc/standaloneServer.rb @@ -0,0 +1,43 @@ +# SOAP4R - WEBrick Server +# Copyright (C) 2003 by NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/rpc/httpserver' + + +module SOAP +module RPC + + +class StandaloneServer < HTTPServer + def initialize(appname, default_namespace, host = "0.0.0.0", port = 8080) + @appname = appname + @default_namespace = default_namespace + @host = host + @port = port + super(create_config) + end + + alias add_servant add_rpc_servant + alias add_headerhandler add_rpc_headerhandler + +private + + def create_config + { + :BindAddress => @host, + :Port => @port, + :AccessLog => [], + :SOAPDefaultNamespace => @default_namespace, + :SOAPHTTPServerApplicationName => @appname, + } + end +end + + +end +end diff --git a/ruby_1_8_6/lib/soap/soap.rb b/ruby_1_8_6/lib/soap/soap.rb new file mode 100644 index 0000000000..12e09eccfe --- /dev/null +++ b/ruby_1_8_6/lib/soap/soap.rb @@ -0,0 +1,140 @@ +# soap/soap.rb: SOAP4R - Base definitions. +# Copyright (C) 2000-2004 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'xsd/qname' +require 'xsd/charset' + + +module SOAP + + +VERSION = Version = '1.5.5' +PropertyName = 'soap/property' + +EnvelopeNamespace = 'http://schemas.xmlsoap.org/soap/envelope/' +EncodingNamespace = 'http://schemas.xmlsoap.org/soap/encoding/' +LiteralNamespace = 'http://xml.apache.org/xml-soap/literalxml' + +NextActor = 'http://schemas.xmlsoap.org/soap/actor/next' + +EleEnvelope = 'Envelope' +EleHeader = 'Header' +EleBody = 'Body' +EleFault = 'Fault' +EleFaultString = 'faultstring' +EleFaultActor = 'faultactor' +EleFaultCode = 'faultcode' +EleFaultDetail = 'detail' + +AttrMustUnderstand = 'mustUnderstand' +AttrEncodingStyle = 'encodingStyle' +AttrActor = 'actor' +AttrRoot = 'root' +AttrArrayType = 'arrayType' +AttrOffset = 'offset' +AttrPosition = 'position' +ValueArray = 'Array' + +EleEnvelopeName = XSD::QName.new(EnvelopeNamespace, EleEnvelope).freeze +EleHeaderName = XSD::QName.new(EnvelopeNamespace, EleHeader).freeze +EleBodyName = XSD::QName.new(EnvelopeNamespace, EleBody).freeze +EleFaultName = XSD::QName.new(EnvelopeNamespace, EleFault).freeze +EleFaultStringName = XSD::QName.new(nil, EleFaultString).freeze +EleFaultActorName = XSD::QName.new(nil, EleFaultActor).freeze +EleFaultCodeName = XSD::QName.new(nil, EleFaultCode).freeze +EleFaultDetailName = XSD::QName.new(nil, EleFaultDetail).freeze +AttrMustUnderstandName = XSD::QName.new(EnvelopeNamespace, AttrMustUnderstand).freeze +AttrEncodingStyleName = XSD::QName.new(EnvelopeNamespace, AttrEncodingStyle).freeze +AttrRootName = XSD::QName.new(EncodingNamespace, AttrRoot).freeze +AttrArrayTypeName = XSD::QName.new(EncodingNamespace, AttrArrayType).freeze +AttrOffsetName = XSD::QName.new(EncodingNamespace, AttrOffset).freeze +AttrPositionName = XSD::QName.new(EncodingNamespace, AttrPosition).freeze +ValueArrayName = XSD::QName.new(EncodingNamespace, ValueArray).freeze + +Base64Literal = 'base64' + +SOAPNamespaceTag = 'env' +XSDNamespaceTag = 'xsd' +XSINamespaceTag = 'xsi' + +MediaType = 'text/xml' + +class Error < StandardError; end + +class StreamError < Error; end +class HTTPStreamError < StreamError; end +class PostUnavailableError < HTTPStreamError; end +class MPostUnavailableError < HTTPStreamError; end + +class ArrayIndexOutOfBoundsError < Error; end +class ArrayStoreError < Error; end + +class RPCRoutingError < Error; end +class EmptyResponseError < Error; end +class ResponseFormatError < Error; end + +class UnhandledMustUnderstandHeaderError < Error; end + +class FaultError < Error + attr_reader :faultcode + attr_reader :faultstring + attr_reader :faultactor + attr_accessor :detail + + def initialize(fault) + @faultcode = fault.faultcode + @faultstring = fault.faultstring + @faultactor = fault.faultactor + @detail = fault.detail + super(self.to_s) + end + + def to_s + str = nil + if @faultstring and @faultstring.respond_to?('data') + str = @faultstring.data + end + str || '(No faultstring)' + end +end + + +module Env + def self.getenv(name) + ENV[name.downcase] || ENV[name.upcase] + end + + use_proxy = getenv('soap_use_proxy') == 'on' + HTTP_PROXY = use_proxy ? getenv('http_proxy') : nil + NO_PROXY = use_proxy ? getenv('no_proxy') : nil +end + + +end + + +unless Object.respond_to?(:instance_variable_get) + class Object + def instance_variable_get(ivarname) + instance_eval(ivarname) + end + + def instance_variable_set(ivarname, value) + instance_eval("#{ivarname} = value") + end + end +end + + +unless Kernel.respond_to?(:warn) + module Kernel + def warn(msg) + STDERR.puts(msg + "\n") unless $VERBOSE.nil? + end + end +end diff --git a/ruby_1_8_6/lib/soap/streamHandler.rb b/ruby_1_8_6/lib/soap/streamHandler.rb new file mode 100644 index 0000000000..672396ecce --- /dev/null +++ b/ruby_1_8_6/lib/soap/streamHandler.rb @@ -0,0 +1,229 @@ +# SOAP4R - Stream handler. +# Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'soap/soap' +require 'soap/httpconfigloader' +begin + require 'stringio' + require 'zlib' +rescue LoadError + warn("Loading stringio or zlib failed. No gzipped response support.") if $DEBUG +end + + +module SOAP + + +class StreamHandler + RUBY_VERSION_STRING = "ruby #{ RUBY_VERSION } (#{ RUBY_RELEASE_DATE }) [#{ RUBY_PLATFORM }]" + + class ConnectionData + attr_accessor :send_string + attr_accessor :send_contenttype + attr_accessor :receive_string + attr_accessor :receive_contenttype + attr_accessor :is_fault + attr_accessor :soapaction + + def initialize(send_string = nil) + @send_string = send_string + @send_contenttype = nil + @receive_string = nil + @receive_contenttype = nil + @is_fault = false + @soapaction = nil + end + end + + def self.parse_media_type(str) + if /^#{ MediaType }(?:\s*;\s*charset=([^"]+|"[^"]+"))?$/i !~ str + return nil + end + charset = $1 + charset.gsub!(/"/, '') if charset + charset || 'us-ascii' + end + + def self.create_media_type(charset) + "#{ MediaType }; charset=#{ charset }" + end +end + + +class HTTPStreamHandler < StreamHandler + include SOAP + + begin + require 'http-access2' + if HTTPAccess2::VERSION < "2.0" + raise LoadError.new("http-access/2.0 or later is required.") + end + Client = HTTPAccess2::Client + RETRYABLE = true + rescue LoadError + warn("Loading http-access2 failed. Net/http is used.") if $DEBUG + require 'soap/netHttpClient' + Client = SOAP::NetHttpClient + RETRYABLE = false + end + + +public + + attr_reader :client + attr_accessor :wiredump_file_base + + MAX_RETRY_COUNT = 10 # [times] + + def initialize(options) + super() + @client = Client.new(nil, "SOAP4R/#{ Version }") + @wiredump_file_base = nil + @charset = @wiredump_dev = nil + @options = options + set_options + @client.debug_dev = @wiredump_dev + @cookie_store = nil + @accept_encoding_gzip = false + end + + def test_loopback_response + @client.test_loopback_response + end + + def accept_encoding_gzip=(allow) + @accept_encoding_gzip = allow + end + + def inspect + "#<#{self.class}>" + end + + def send(endpoint_url, conn_data, soapaction = nil, charset = @charset) + conn_data.soapaction ||= soapaction # for backward conpatibility + send_post(endpoint_url, conn_data, charset) + end + + def reset(endpoint_url = nil) + if endpoint_url.nil? + @client.reset_all + else + @client.reset(endpoint_url) + end + @client.save_cookie_store if @cookie_store + end + +private + + def set_options + HTTPConfigLoader.set_options(@client, @options) + @charset = @options["charset"] || XSD::Charset.xml_encoding_label + @options.add_hook("charset") do |key, value| + @charset = value + end + @wiredump_dev = @options["wiredump_dev"] + @options.add_hook("wiredump_dev") do |key, value| + @wiredump_dev = value + @client.debug_dev = @wiredump_dev + end + set_cookie_store_file(@options["cookie_store_file"]) + @options.add_hook("cookie_store_file") do |key, value| + set_cookie_store_file(value) + end + ssl_config = @options["ssl_config"] + basic_auth = @options["basic_auth"] + @options.lock(true) + ssl_config.unlock + basic_auth.unlock + end + + def set_cookie_store_file(value) + value = nil if value and value.empty? + @cookie_store = value + @client.set_cookie_store(@cookie_store) if @cookie_store + end + + def send_post(endpoint_url, conn_data, charset) + conn_data.send_contenttype ||= StreamHandler.create_media_type(charset) + + if @wiredump_file_base + filename = @wiredump_file_base + '_request.xml' + f = File.open(filename, "w") + f << conn_data.send_string + f.close + end + + extra = {} + extra['Content-Type'] = conn_data.send_contenttype + extra['SOAPAction'] = "\"#{ conn_data.soapaction }\"" + extra['Accept-Encoding'] = 'gzip' if send_accept_encoding_gzip? + send_string = conn_data.send_string + @wiredump_dev << "Wire dump:\n\n" if @wiredump_dev + begin + retry_count = 0 + while true + res = @client.post(endpoint_url, send_string, extra) + if RETRYABLE and HTTP::Status.redirect?(res.status) + retry_count += 1 + if retry_count >= MAX_RETRY_COUNT + raise HTTPStreamError.new("redirect count exceeded") + end + endpoint_url = res.header["location"][0] + puts "redirected to #{endpoint_url}" if $DEBUG + else + break + end + end + rescue + @client.reset(endpoint_url) + raise + end + @wiredump_dev << "\n\n" if @wiredump_dev + receive_string = res.content + if @wiredump_file_base + filename = @wiredump_file_base + '_response.xml' + f = File.open(filename, "w") + f << receive_string + f.close + end + case res.status + when 405 + raise PostUnavailableError.new("#{ res.status }: #{ res.reason }") + when 200, 500 + # Nothing to do. + else + raise HTTPStreamError.new("#{ res.status }: #{ res.reason }") + end + if res.respond_to?(:header) and !res.header['content-encoding'].empty? and + res.header['content-encoding'][0].downcase == 'gzip' + receive_string = decode_gzip(receive_string) + end + conn_data.receive_string = receive_string + conn_data.receive_contenttype = res.contenttype + conn_data + end + + def send_accept_encoding_gzip? + @accept_encoding_gzip and defined?(::Zlib) + end + + def decode_gzip(instring) + unless send_accept_encoding_gzip? + raise HTTPStreamError.new("Gzipped response content.") + end + begin + gz = Zlib::GzipReader.new(StringIO.new(instring)) + gz.read + ensure + gz.close + end + end +end + + +end diff --git a/ruby_1_8_6/lib/soap/wsdlDriver.rb b/ruby_1_8_6/lib/soap/wsdlDriver.rb new file mode 100644 index 0000000000..eba9608df5 --- /dev/null +++ b/ruby_1_8_6/lib/soap/wsdlDriver.rb @@ -0,0 +1,575 @@ +# SOAP4R - SOAP WSDL driver +# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi . + +# This program is copyrighted free software by NAKAMURA, Hiroshi. You can +# redistribute it and/or modify it under the same terms of Ruby's license; +# either the dual license version in 2003, or any later version. + + +require 'wsdl/parser' +require 'wsdl/importer' +require 'xsd/qname' +require 'xsd/codegen/gensupport' +require 'soap/mapping/wsdlencodedregistry' +require 'soap/mapping/wsdlliteralregistry' +require 'soap/rpc/driver' +require 'wsdl/soap/methodDefCreator' + + +module SOAP + + +class WSDLDriverFactory + class FactoryError < StandardError; end + + attr_reader :wsdl + + def initialize(wsdl) + @wsdl = import(wsdl) + @methoddefcreator = WSDL::SOAP::MethodDefCreator.new(@wsdl) + end + + def inspect + "#<#{self.class}:#{@wsdl.name}>" + end + + def create_rpc_driver(servicename = nil, portname = nil) + port = find_port(servicename, portname) + drv = SOAP::RPC::Driver.new(port.soap_address.location) + init_driver(drv, port) + add_operation(drv, port) + drv + end + + # depricated old interface + def create_driver(servicename = nil, portname = nil) + warn("WSDLDriverFactory#create_driver is depricated. Use create_rpc_driver instead.") + port = find_port(servicename, portname) + WSDLDriver.new(@wsdl, port, nil) + end + + # Backward compatibility. + alias createDriver create_driver + +private + + def find_port(servicename = nil, portname = nil) + service = port = nil + if servicename + service = @wsdl.service( + XSD::QName.new(@wsdl.targetnamespace, servicename)) + else + service = @wsdl.services[0] + end + if service.nil? + raise FactoryError.new("service #{servicename} not found in WSDL") + end + if portname + port = service.ports[XSD::QName.new(@wsdl.targetnamespace, portname)] + if port.nil? + raise FactoryError.new("port #{portname} not found in WSDL") + end + else + port = service.ports.find { |port| !port.soap_address.nil? } + if port.nil? + raise FactoryError.new("no ports have soap:address") + end + end + if port.soap_address.nil? + raise FactoryError.new("soap:address element not found in WSDL") + end + port + end + + def init_driver(drv, port) + wsdl_elements = @wsdl.collect_elements + wsdl_types = @wsdl.collect_complextypes + @wsdl.collect_simpletypes + rpc_decode_typemap = wsdl_types + + @wsdl.soap_rpc_complextypes(port.find_binding) + drv.proxy.mapping_registry = + Mapping::WSDLEncodedRegistry.new(rpc_decode_typemap) + drv.proxy.literal_mapping_registry = + Mapping::WSDLLiteralRegistry.new(wsdl_types, wsdl_elements) + end + + def add_operation(drv, port) + port.find_binding.operations.each do |op_bind| + op_name = op_bind.soapoperation_name + soapaction = op_bind.soapaction || '' + orgname = op_name.name + name = XSD::CodeGen::GenSupport.safemethodname(orgname) + param_def = create_param_def(op_bind) + opt = { + :request_style => op_bind.soapoperation_style, + :response_style => op_bind.soapoperation_style, + :request_use => op_bind.input.soapbody_use, + :response_use => op_bind.output.soapbody_use, + :elementformdefault => false, + :attributeformdefault => false + } + if op_bind.soapoperation_style == :rpc + drv.add_rpc_operation(op_name, soapaction, name, param_def, opt) + else + drv.add_document_operation(soapaction, name, param_def, opt) + end + if orgname != name and orgname.capitalize == name.capitalize + ::SOAP::Mapping.define_singleton_method(drv, orgname) do |*arg| + __send__(name, *arg) + end + end + end + end + + def import(location) + WSDL::Importer.import(location) + end + + def create_param_def(op_bind) + op = op_bind.find_operation + if op_bind.soapoperation_style == :rpc + param_def = @methoddefcreator.collect_rpcparameter(op) + else + param_def = @methoddefcreator.collect_documentparameter(op) + end + # the first element of typedef in param_def is a String like + # "::SOAP::SOAPStruct". turn this String to a class. + param_def.collect { |io, name, typedef| + typedef[0] = Mapping.class_from_name(typedef[0]) + [io, name, typedef] + } + end + + def partqname(part) + if part.type + part.type + else + part.element + end + end + + def param_def(type, name, klass, partqname) + [type, name, [klass, partqname.namespace, partqname.name]] + end + + def filter_parts(partsdef, partssource) + parts = partsdef.split(/\s+/) + partssource.find_all { |part| parts.include?(part.name) } + end +end + + +class WSDLDriver + class << self + if RUBY_VERSION >= "1.7.0" + def __attr_proxy(symbol, assignable = false) + name = symbol.to_s + define_method(name) { + @servant.__send__(name) + } + if assignable + aname = name + '=' + define_method(aname) { |rhs| + @servant.__send__(aname, rhs) + } + end + end + else + def __attr_proxy(symbol, assignable = false) + name = symbol.to_s + module_eval <<-EOS + def #{name} + @servant.#{name} + end + EOS + if assignable + module_eval <<-EOS + def #{name}=(value) + @servant.#{name} = value + end + EOS + end + end + end + end + + __attr_proxy :options + __attr_proxy :headerhandler + __attr_proxy :streamhandler + __attr_proxy :test_loopback_response + __attr_proxy :endpoint_url, true + __attr_proxy :mapping_registry, true # for RPC unmarshal + __attr_proxy :wsdl_mapping_registry, true # for RPC marshal + __attr_proxy :default_encodingstyle, true + __attr_proxy :generate_explicit_type, true + __attr_proxy :allow_unqualified_element, true + + def httpproxy + @servant.options["protocol.http.proxy"] + end + + def httpproxy=(httpproxy) + @servant.options["protocol.http.proxy"] = httpproxy + end + + def wiredump_dev + @servant.options["protocol.http.wiredump_dev"] + end + + def wiredump_dev=(wiredump_dev) + @servant.options["protocol.http.wiredump_dev"] = wiredump_dev + end + + def mandatorycharset + @servant.options["protocol.mandatorycharset"] + end + + def mandatorycharset=(mandatorycharset) + @servant.options["protocol.mandatorycharset"] = mandatorycharset + end + + def wiredump_file_base + @servant.options["protocol.wiredump_file_base"] + end + + def wiredump_file_base=(wiredump_file_base) + @servant.options["protocol.wiredump_file_base"] = wiredump_file_base + end + + def initialize(wsdl, port, logdev) + @servant = Servant__.new(self, wsdl, port, logdev) + end + + def inspect + "#<#{self.class}:#{@servant.port.name}>" + end + + def reset_stream + @servant.reset_stream + end + + # Backward compatibility. + alias generateEncodeType= generate_explicit_type= + + class Servant__ + include SOAP + + attr_reader :options + attr_reader :port + + attr_accessor :soapaction + attr_accessor :default_encodingstyle + attr_accessor :allow_unqualified_element + attr_accessor :generate_explicit_type + attr_accessor :mapping_registry + attr_accessor :wsdl_mapping_registry + + def initialize(host, wsdl, port, logdev) + @host = host + @wsdl = wsdl + @port = port + @logdev = logdev + @soapaction = nil + @options = setup_options + @default_encodingstyle = nil + @allow_unqualified_element = nil + @generate_explicit_type = false + @mapping_registry = nil # for rpc unmarshal + @wsdl_mapping_registry = nil # for rpc marshal + @wiredump_file_base = nil + @mandatorycharset = nil + @wsdl_elements = @wsdl.collect_elements + @wsdl_types = @wsdl.collect_complextypes + @wsdl.collect_simpletypes + @rpc_decode_typemap = @wsdl_types + + @wsdl.soap_rpc_complextypes(port.find_binding) + @wsdl_mapping_registry = Mapping::WSDLEncodedRegistry.new( + @rpc_decode_typemap) + @doc_mapper = Mapping::WSDLLiteralRegistry.new( + @wsdl_types, @wsdl_elements) + endpoint_url = @port.soap_address.location + # Convert a map which key is QName, to a Hash which key is String. + @operation = {} + @port.inputoperation_map.each do |op_name, op_info| + orgname = op_name.name + name = XSD::CodeGen::GenSupport.safemethodname(orgname) + @operation[name] = @operation[orgname] = op_info + add_method_interface(op_info) + end + @proxy = ::SOAP::RPC::Proxy.new(endpoint_url, @soapaction, @options) + end + + def inspect + "#<#{self.class}:#{@proxy.inspect}>" + end + + def endpoint_url + @proxy.endpoint_url + end + + def endpoint_url=(endpoint_url) + @proxy.endpoint_url = endpoint_url + end + + def headerhandler + @proxy.headerhandler + end + + def streamhandler + @proxy.streamhandler + end + + def test_loopback_response + @proxy.test_loopback_response + end + + def reset_stream + @proxy.reset_stream + end + + def rpc_call(name, *values) + set_wiredump_file_base(name) + unless op_info = @operation[name] + raise RuntimeError, "method: #{name} not defined" + end + req_header = create_request_header + req_body = create_request_body(op_info, *values) + reqopt = create_options({ + :soapaction => op_info.soapaction || @soapaction}) + resopt = create_options({ + :decode_typemap => @rpc_decode_typemap}) + env = @proxy.route(req_header, req_body, reqopt, resopt) + raise EmptyResponseError unless env + receive_headers(env.header) + begin + @proxy.check_fault(env.body) + rescue ::SOAP::FaultError => e + Mapping.fault2exception(e) + end + ret = env.body.response ? + Mapping.soap2obj(env.body.response, @mapping_registry) : nil + if env.body.outparams + outparams = env.body.outparams.collect { |outparam| + Mapping.soap2obj(outparam) + } + return [ret].concat(outparams) + else + return ret + end + end + + # req_header: [[element, mustunderstand, encodingstyle(QName/String)], ...] + # req_body: SOAPBasetype/SOAPCompoundtype + def document_send(name, header_obj, body_obj) + set_wiredump_file_base(name) + unless op_info = @operation[name] + raise RuntimeError, "method: #{name} not defined" + end + req_header = header_obj ? header_from_obj(header_obj, op_info) : nil + req_body = body_from_obj(body_obj, op_info) + opt = create_options({ + :soapaction => op_info.soapaction || @soapaction, + :decode_typemap => @wsdl_types}) + env = @proxy.invoke(req_header, req_body, opt) + raise EmptyResponseError unless env + if env.body.fault + raise ::SOAP::FaultError.new(env.body.fault) + end + res_body_obj = env.body.response ? + Mapping.soap2obj(env.body.response, @mapping_registry) : nil + return env.header, res_body_obj + end + + private + + def create_options(hash = nil) + opt = {} + opt[:default_encodingstyle] = @default_encodingstyle + opt[:allow_unqualified_element] = @allow_unqualified_element + opt[:generate_explicit_type] = @generate_explicit_type + opt.update(hash) if hash + opt + end + + def set_wiredump_file_base(name) + if @wiredump_file_base + @proxy.set_wiredump_file_base(@wiredump_file_base + "_#{name}") + end + end + + def create_request_header + headers = @proxy.headerhandler.on_outbound + if headers.empty? + nil + else + h = SOAPHeader.new + headers.each do |header| + h.add(header.elename.name, header) + end + h + end + end + + def receive_headers(headers) + @proxy.headerhandler.on_inbound(headers) if headers + end + + def create_request_body(op_info, *values) + method = create_method_struct(op_info, *values) + SOAPBody.new(method) + end + + def create_method_struct(op_info, *params) + parts_names = op_info.bodyparts.collect { |part| part.name } + obj = create_method_obj(parts_names, params) + method = Mapping.obj2soap(obj, @wsdl_mapping_registry, op_info.op_name) + if method.members.size != parts_names.size + new_method = SOAPStruct.new + method.each do |key, value| + if parts_names.include?(key) + new_method.add(key, value) + end + end + method = new_method + end + method.elename = op_info.op_name + method.type = XSD::QName.new # Request should not be typed. + method + end + + def create_method_obj(names, params) + o = Object.new + idx = 0 + while idx < params.length + o.instance_variable_set('@' + names[idx], params[idx]) + idx += 1 + end + o + end + + def header_from_obj(obj, op_info) + if obj.is_a?(SOAPHeader) + obj + elsif op_info.headerparts.empty? + if obj.nil? + nil + else + raise RuntimeError.new("no header definition in schema: #{obj}") + end + elsif op_info.headerparts.size == 1 + part = op_info.headerparts[0] + header = SOAPHeader.new() + header.add(headeritem_from_obj(obj, part.element || part.eletype)) + header + else + header = SOAPHeader.new() + op_info.headerparts.each do |part| + child = Mapping.get_attribute(obj, part.name) + ele = headeritem_from_obj(child, part.element || part.eletype) + header.add(part.name, ele) + end + header + end + end + + def headeritem_from_obj(obj, name) + if obj.nil? + SOAPElement.new(name) + elsif obj.is_a?(SOAPHeaderItem) + obj + else + Mapping.obj2soap(obj, @doc_mapper, name) + end + end + + def body_from_obj(obj, op_info) + if obj.is_a?(SOAPBody) + obj + elsif op_info.bodyparts.empty? + if obj.nil? + nil + else + raise RuntimeError.new("no body found in schema") + end + elsif op_info.bodyparts.size == 1 + part = op_info.bodyparts[0] + ele = bodyitem_from_obj(obj, part.element || part.type) + SOAPBody.new(ele) + else + body = SOAPBody.new + op_info.bodyparts.each do |part| + child = Mapping.get_attribute(obj, part.name) + ele = bodyitem_from_obj(child, part.element || part.type) + body.add(ele.elename.name, ele) + end + body + end + end + + def bodyitem_from_obj(obj, name) + if obj.nil? + SOAPElement.new(name) + elsif obj.is_a?(SOAPElement) + obj + else + Mapping.obj2soap(obj, @doc_mapper, name) + end + end + + def add_method_interface(op_info) + name = XSD::CodeGen::GenSupport.safemethodname(op_info.op_name.name) + orgname = op_info.op_name.name + parts_names = op_info.bodyparts.collect { |part| part.name } + case op_info.style + when :document + if orgname != name and orgname.capitalize == name.capitalize + add_document_method_interface(orgname, parts_names) + end + add_document_method_interface(name, parts_names) + when :rpc + if orgname != name and orgname.capitalize == name.capitalize + add_rpc_method_interface(orgname, parts_names) + end + add_rpc_method_interface(name, parts_names) + else + raise RuntimeError.new("unknown style: #{op_info.style}") + end + end + + def add_rpc_method_interface(name, parts_names) + ::SOAP::Mapping.define_singleton_method(@host, name) do |*arg| + unless arg.size == parts_names.size + raise ArgumentError.new( + "wrong number of arguments (#{arg.size} for #{parts_names.size})") + end + @servant.rpc_call(name, *arg) + end + @host.method(name) + end + + def add_document_method_interface(name, parts_names) + ::SOAP::Mapping.define_singleton_method(@host, name) do |h, b| + @servant.document_send(name, h, b) + end + @host.method(name) + end + + def setup_options + if opt = Property.loadproperty(::SOAP::PropertyName) + opt = opt["client"] + end + opt ||= Property.new + opt.add_hook("protocol.mandatorycharset") do |key, value| + @mandatorycharset = value + end + opt.add_hook("protocol.wiredump_file_base") do |key, value| + @wiredump_file_base = value + end + opt["protocol.http.charset"] ||= XSD::Charset.xml_encoding_label + opt["protocol.http.proxy"] ||= Env::HTTP_PROXY + opt["protocol.http.no_proxy"] ||= Env::NO_PROXY + opt + end + end +end + + +end -- cgit v1.2.3