1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* lib/soap/* (29 files): SOAP4R added.

* lib/wsdl/* (42 files): WSDL4R added.

* lib/xsd/* (12 files): XSD4R added.

* test/soap/* (16 files): added.

* test/wsdl/* (2 files): added.

* test/xsd/* (3 files): added.

* sample/soap/* (27 files): added.

* sample/wsdl/* (13 files): added.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4591 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nahi 2003-09-24 15:18:44 +00:00
parent 8c2fb77787
commit db9445103c
145 changed files with 20938 additions and 0 deletions

View file

@ -1,3 +1,21 @@
Mon Sep 25 00:13:15 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>
* lib/soap/* (29 files): SOAP4R added.
* lib/wsdl/* (42 files): WSDL4R added.
* lib/xsd/* (12 files): XSD4R added.
* test/soap/* (16 files): added.
* test/wsdl/* (2 files): added.
* test/xsd/* (3 files): added.
* sample/soap/* (27 files): added.
* sample/wsdl/* (13 files): added.
Wed Sep 24 02:08:11 2003 GOTOU Yuuzou <gotoyuzo@notwork.org>
* lib/webrick/httpservlet/cgihandler.rb: conform to mswin32.

782
lib/soap/baseData.rb Normal file
View file

@ -0,0 +1,782 @@
=begin
SOAP4R - Base type library
Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
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
###
## Mix-in module for SOAP base type instances.
#
module SOAPBasetype
include SOAP
attr_accessor :encodingstyle
attr_accessor :elename
attr_accessor :id
attr_reader :precedents
attr_accessor :root
attr_accessor :parent
attr_accessor :position
attr_reader :extraattr
public
def initialize(*vars)
super(*vars)
@encodingstyle = nil
@elename = XSD::QName.new
@id = nil
@precedents = []
@parent = nil
@position = nil
@extraattr = {}
end
end
###
## Mix-in module for SOAP compound type instances.
#
module SOAPCompoundtype
include SOAP
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
public
def initialize(type)
super()
@type = type
@encodingstyle = nil
@elename = XSD::QName.new
@id = nil
@precedents = []
@root = false
@parent = nil
@position = nil
@definedtype = nil
@extraattr = {}
end
end
###
## Convenience datatypes.
#
class SOAPReference < XSD::NSDBase
include SOAPBasetype
extend SOAPModuleUtils
public
attr_accessor :refid
attr_accessor :elename
# Override the definition in SOAPBasetype.
def initialize(refid = nil)
super()
@type = XSD::QName.new
@encodingstyle = nil
@elename = XSD::QName.new
@id = nil
@precedents = []
@root = false
@parent = nil
@refid = refid
@obj = nil
end
def __getobj__
@obj
end
def __setobj__(obj)
@obj = obj
@refid = 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 self.decode(elename, refid)
d = super(elename)
d.refid = refid
d
end
def SOAPReference.create_refid(obj)
'id' << obj.__id__.to_s
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 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
###
## Compound datatypes.
#
class SOAPStruct < XSD::NSDBase
include SOAPCompoundtype
include Enumerable
public
def initialize(type = nil)
super(type || XSD::QName.new)
@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[@array.index(idx)] = data
else
add(idx, data)
end
end
def key?(name)
@array.include?(name)
end
def members
@array
end
def each
for i in 0..(@array.length - 1)
yield(@array[i], @data[i])
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() unless value
@array.push(name)
value.elename = value.elename.dup_name(name)
@data.push(value)
end
end
# SOAPElement is not typed so it does not derive NSDBase.
class SOAPElement
include Enumerable
attr_accessor :encodingstyle
attr_accessor :extraattr
attr_reader :precedents
attr_accessor :qualified
attr_accessor :elename
def initialize(elename, text = nil)
if !elename.is_a?(XSD::QName)
elename = XSD::QName.new(nil, elename)
end
@encodingstyle = LiteralNamespace
@extraattr = {}
@precedents = []
@qualified = false
@elename = elename
@array = []
@data = []
@text = text
end
# Text interface.
attr_accessor :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[@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 = {}
each do |k, v|
hash[k] = v.to_obj
end
hash
end
end
def each
for i in 0..(@array.length - 1)
yield(@array[i], @data[i])
end
end
def self.decode(elename)
o = SOAPElement.new
o.elename = elename
o
end
def self.from_obj(hash_or_string)
o = SOAPElement.new(nil)
if hash_or_string.is_a?(Hash)
hash_or_string.each do |k, v|
child = self.from_obj(v)
child.elename = XSD::QName.new(nil, k)
o.add(child)
end
else
o.text = hash_or_string
end
o
end
private
def add_member(name, value)
add_accessor(name)
@array.push(name)
@data.push(value)
end
def add_accessor(name)
methodname = name
if self.respond_to?(methodname)
methodname = safe_accessor_name(methodname)
end
begin
instance_eval <<-EOS
def #{ methodname }()
@data[@array.index('#{ name }')]
end
def #{ methodname }=(value)
@data[@array.index('#{ name }')] = value
end
EOS
rescue SyntaxError
methodname = safe_accessor_name(methodname)
retry
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 || XSD::QName.new)
@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
for i in 0..(idxary.size - 1)
if idxary[i] + 1 > @size[i]
@size[i] = idxary[i] + 1
end
end
data = retrieve(idxary[0, idxary.size - 1])
data[idxary.last] = value
if value.is_a?(SOAPBasetype) || value.is_a?(SOAPCompoundtype)
value.elename = value.elename.dup_name('item')
# Sync type
unless @type.name
@type = XSD::QName.new(value.type.namespace,
SOAPArray.create_arytype(value.type.name, @rank))
end
unless value.type
value.type = @type
end
end
@offset = idxary
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 = new_obj.elename.dup_name('item')
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
for rank in 1..(position.size - 1)
idx = position[rank - 1]
if iteary[idx].nil?
iteary = iteary[idx] = Array.new
else
iteary = iteary[idx]
end
end
if block_given?
iteary[position.last] = yield(v)
else
iteary[position.last] = v
end
end
end
def position
@position
end
private
def retrieve(idxary)
data = @data
for rank in 1..(idxary.size)
idx = idxary[rank - 1]
if data[idx].nil?
data = data[idx] = Array.new
else
data = data[idx]
end
end
data
end
def traverse_data(data, rank = 1)
for idx in 0..(ranksize(rank) - 1)
if rank < @rank
traverse_data(data[idx], rank + 1) do |*v|
v[1, 0] = idx
yield(*v)
end
else
yield(data[idx], idx)
end
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

232
lib/soap/element.rb Normal file
View file

@ -0,0 +1,232 @@
=begin
SOAP4R - SOAP elements library
Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
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
end
def encode(buf, ns, attrs = {}, indent = '')
SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace)
SOAPGenerator.assign_ns(attrs, ns, EncodingNamespace)
attrs[ns.name(AttrEncodingStyleName)] = EncodingNamespace
name = ns.name(@elename)
SOAPGenerator.encode_tag(buf, name, attrs, indent)
yield(self.faultcode, false)
yield(self.faultstring, false)
yield(self.faultactor, false)
yield(self.detail, false) if self.detail
SOAPGenerator.encode_tag_end(buf, name, indent, true)
end
end
class SOAPBody < SOAPStruct
include SOAPEnvelopeElement
public
def initialize(data = nil, is_fault = false)
super(nil)
@elename = EleBodyName
@encodingstyle = nil
add(data.elename.name, data) if data
@is_fault = is_fault
end
def encode(buf, ns, attrs = {}, indent = '')
name = ns.name(@elename)
SOAPGenerator.encode_tag(buf, name, attrs, indent)
if @is_fault
yield(@data, true)
else
@data.each do |data|
yield(data, true)
end
end
SOAPGenerator.encode_tag_end(buf, name, indent, 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 SOAPParser::FormatDecodeError.new('No root element.')
end
end
class SOAPHeaderItem < XSD::NSDBase
include SOAPEnvelopeElement
include SOAPCompoundtype
public
attr_accessor :content
attr_accessor :mustunderstand
attr_accessor :encodingstyle
def initialize(content, mustunderstand = true, encodingstyle = nil)
super(nil)
@content = content
@mustunderstand = mustunderstand
@encodingstyle = encodingstyle || LiteralNamespace
end
def encode(buf, ns, attrs = {}, indent = '')
attrs.each do |key, value|
@content.attr[key] = value
end
@content.attr[ns.name(EnvelopeNamespace, AttrMustUnderstand)] =
(@mustunderstand ? '1' : '0')
if @encodingstyle
@content.attr[ns.name(EnvelopeNamespace, AttrEncodingStyle)] =
@encodingstyle
end
@content.encodingstyle = @encodingstyle if !@content.encodingstyle
yield(@content, true)
end
end
class SOAPHeader < SOAPArray
include SOAPEnvelopeElement
def initialize()
super(nil, 1) # rank == 1
@elename = EleHeaderName
@encodingstyle = nil
end
def encode(buf, ns, attrs = {}, indent = '')
name = ns.name(@elename)
SOAPGenerator.encode_tag(buf, name, attrs, indent)
@data.each do |data|
yield(data, true)
end
SOAPGenerator.encode_tag_end(buf, name, indent, true)
end
def length
@data.length
end
end
class SOAPEnvelope < XSD::NSDBase
include SOAPEnvelopeElement
include SOAPCompoundtype
attr_accessor :header
attr_accessor :body
def initialize(header = nil, body = nil)
super(nil)
@elename = EleEnvelopeName
@encodingstyle = nil
@header = header
@body = body
end
def encode(buf, ns, attrs = {}, indent = '')
SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace,
SOAPNamespaceTag)
name = ns.name(@elename)
SOAPGenerator.encode_tag(buf, name, attrs, indent)
yield(@header, true) if @header and @header.length > 0
yield(@body, true)
SOAPGenerator.encode_tag_end(buf, name, indent, true)
end
end
end

View file

@ -0,0 +1,232 @@
=begin
SOAP4R - ASP.NET EncodingStyle handler library
Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
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(buf, ns, qualified, data, parent, indent = '')
attrs = {}
name = if qualified and data.elename.namespace
SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace)
ns.name(data.elename)
else
data.elename.name
end
case data
when SOAPRawString
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << data.to_s
when XSD::XSDString
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << SOAPGenerator.encode_str(@charset ?
XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
when XSD::XSDAnySimpleType
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << SOAPGenerator.encode_str(data.to_s)
when SOAPStruct
SOAPGenerator.encode_tag(buf, name, attrs, indent)
data.each do |key, value|
if !value.elename.namespace
value.elename.namespace = data.elename.namespace
end
yield(value, true)
end
when SOAPArray
SOAPGenerator.encode_tag(buf, name, attrs, indent)
data.traverse do |child, *rank|
data.position = nil
yield(child, true)
end
else
raise EncodingStyleError.new("Unknown object:#{ data } in this encodingSt
yle.")
end
end
def encode_data_end(buf, ns, qualified, data, parent, indent = "")
name = if qualified and data.elename.namespace
ns.name(data.elename)
else
data.elename.name
end
cr = data.is_a?(SOAPCompoundtype)
SOAPGenerator.encode_tag_end(buf, name, indent, 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)
# ToDo: check if @textbuf is empty...
@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

View file

@ -0,0 +1,111 @@
=begin
SOAP4R - EncodingStyle handler library
Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
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=(complextypes)
@decode_typemap = complextypes
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(buf, ns, qualified, data, parent, indent)
raise NotImplementError.new('Method encode_data must be defined in derived class.')
end
def encode_data_end(buf, ns, qualified, data, parent, indent)
raise NotImplementError.new('Method encode_data must be defined in derived class.')
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

View file

@ -0,0 +1,218 @@
=begin
SOAP4R - XML Literal EncodingStyle handler library
Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
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(buf, ns, qualified, data, parent, indent = '')
attrs = {}
name = if qualified and data.elename.namespace
SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace)
ns.name(data.elename)
else
data.elename.name
end
case data
when SOAPRawString
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << data.to_s
when XSD::XSDString
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << SOAPGenerator.encode_str(@charset ?
XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
when XSD::XSDAnySimpleType
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << SOAPGenerator.encode_str(data.to_s)
when SOAPStruct
SOAPGenerator.encode_tag(buf, name, attrs, indent)
data.each do |key, value|
value.elename.namespace = data.elename.namespace if !value.elename.namespace
yield(value, true)
end
when SOAPArray
SOAPGenerator.encode_tag(buf, name, attrs, indent)
data.traverse do |child, *rank|
data.position = nil
yield(child, true)
end
when SOAPElement
SOAPGenerator.encode_tag(buf, name, attrs.update(data.extraattr),
indent)
buf << data.text if data.text
data.each do |key, value|
value.elename.namespace = data.elename.namespace if !value.elename.namespace
#yield(value, data.qualified)
yield(value, qualified)
end
else
raise EncodingStyleError.new("Unknown object:#{ data } in this encodingStyle.")
end
end
def encode_data_end(buf, ns, qualified, data, parent, indent)
name = if qualified and data.elename.namespace
ns.name(data.elename)
else
data.elename.name
end
SOAPGenerator.encode_tag_end(buf, name, indent)
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
@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)
# ToDo: check if @textbuf is empty...
@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 = 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
parent.node.add(node.name, node)
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
LiteralHandler.new
end
end

View file

@ -0,0 +1,548 @@
=begin
SOAP4R - SOAP EncodingStyle handler library
Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
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(buf, ns, qualified, data, parent, indent = '')
attrs = encode_attrs(ns, qualified, data, parent)
if parent && parent.is_a?(SOAPArray) && parent.position
attrs[ns.name(AttrPositionName)] = '[' << parent.position.join(',') << ']'
end
name = nil
if qualified and data.elename.namespace
SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace)
name = ns.name(data.elename)
else
name = data.elename.name
end
if data.respond_to?(:encode)
SOAPGenerator.encode_tag(buf, name, attrs, indent)
return data.encode(buf, ns, attrs, indent)
end
case data
when SOAPReference
attrs['href'] = '#' << data.refid
SOAPGenerator.encode_tag(buf, name, attrs, indent)
when SOAPRawString
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << data.to_s
when XSD::XSDString
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << SOAPGenerator.encode_str(@charset ?
XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
when XSD::XSDAnySimpleType
SOAPGenerator.encode_tag(buf, name, attrs, indent)
buf << SOAPGenerator.encode_str(data.to_s)
when SOAPStruct
SOAPGenerator.encode_tag(buf, name, attrs, indent)
data.each do |key, value|
yield(value, false)
end
when SOAPArray
SOAPGenerator.encode_tag(buf, name, attrs, indent)
data.traverse do |child, *rank|
data.position = data.sparse ? rank : nil
yield(child, false)
end
else
raise EncodingStyleError.new(
"Unknown object:#{ data } in this encodingStyle.")
end
end
def encode_data_end(buf, ns, qualified, data, parent, indent = '')
name = if qualified and data.elename.namespace
ns.name(data.elename)
else
data.elename.name
end
cr = data.is_a?(SOAPCompoundtype)
SOAPGenerator.encode_tag_end(buf, name, indent, 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)
# ToDo: check if @textbuf is empty...
@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 &&
(parent.node.class != SOAPBody || @is_first_top_ele)
# multi-ref element should be parsed by decode_tag_by_type.
@is_first_top_ele = false
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
if o.is_a?(SOAPCompoundtype)
o.definedtype = nil
end
decode_textbuf(o)
@textbuf = ''
end
def decode_text(ns, text)
# @textbuf is set at decode_tag_end.
@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)
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
when SOAPBasetype
raise EncodingStyleError.new("SOAP base type must not have a child.")
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(ns, qualified, data, parent)
return {} if data.is_a?(SOAPReference)
attrs = {}
if !parent || parent.encodingstyle != EncodingNamespace
if @generate_explicit_type
SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace)
SOAPGenerator.assign_ns(attrs, ns, EncodingNamespace)
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
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)] = value # ns.name(value) ?
end
if data.id
attrs['id'] = data.id
end
attrs
end
def decode_tag_by_wsdl(ns, elename, typestr, parent, arytypestr, extraattr)
if parent.class == SOAPBody
# Unqualified name is allowed here.
type = @decode_typemap[elename] || @decode_typemap.find_name(elename.name)
unless type
raise EncodingStyleError.new("Unknown operation '#{ elename }'.")
end
o = SOAPStruct.new(elename)
o.definedtype = type
return o
end
if parent.type == XSD::AnyTypeName
return decode_tag_by_type(ns, elename, typestr, parent, arytypestr,
extraattr)
end
# parent.definedtype is 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
raise EncodingStyleError.new("Unknown type '#{ parent.type }'.")
end
typename = parenttype.child_type(elename)
if typename
if (klass = TypeMap[typename])
return klass.decode(elename)
elsif typename == XSD::AnyTypeName
return decode_tag_by_type(ns, elename, typestr, parent, arytypestr,
extraattr)
end
end
type = if typename
@decode_typemap[typename]
else
parenttype.child_defined_complextype(elename)
end
unless type
raise EncodingStyleError.new("Unknown type '#{ typename }'.")
end
case type.compoundtype
when :TYPE_STRUCT
o = SOAPStruct.decode(elename, typename)
o.definedtype = type
return o
when :TYPE_ARRAY
expected_arytype = type.find_arytype
actual_arytype = if arytypestr
XSD::QName.new(expected_arytype.namespace,
content_typename(expected_arytype.name) <<
content_ranksize(arytypestr))
else
expected_arytype
end
o = SOAPArray.decode(elename, typename, actual_arytype)
o.definedtype = type
return o
end
return 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.
# <SOAP-ENC:Array ...> => type Array in SOAP-ENC.
# <Country xmlns="foo"> => type Country in foo.
type = elename
end
if (klass = TypeMap[type])
klass.decode(elename)
else
# Unknown type... Struct or String
SOAPUnknown.new(self, elename, type, extraattr)
end
end
def decode_textbuf(node)
case node
when XSD::XSDHexBinary, XSD::XSDBase64Binary
node.set_encoded(@textbuf)
when XSD::XSDString
if @charset
node.set(XSD::Charset.encoding_from_xml(@textbuf, @charset))
else
node.set(@textbuf)
end
when SOAPNil
# Nothing to do.
when SOAPBasetype
node.set(@textbuf)
else
# Nothing to do...
end
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
extraattr[qname] = value
end
return is_nil, type, arytype, root, offset, position, href, id, extraattr
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)
}
unless o
raise EncodingStyleError.new("Unresolved reference: #{ ref.refid }.")
end
if o.is_a?(SOAPReference)
true
else
ref.__setobj__(o)
false
end
}
count -= 1
end
end
end
SOAPHandler.new
end
end

206
lib/soap/generator.rb Normal file
View file

@ -0,0 +1,206 @@
=begin
SOAP4R - SOAP XML Instance Generator library.
Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
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 :pretty
def initialize(opt = {})
@reftarget = nil
@handlers = {}
@charset = opt[:charset] || XSD::Charset.encoding_label
@default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace
@generate_explicit_type =
opt.key?(:generate_explicit_type) ? opt[:generate_explicit_type] : true
@pretty = true # opt[:pretty]
end
def generate(obj, io = nil)
prologue
@handlers.each do |uri, handler|
handler.encode_prologue
end
io = '' if io.nil?
ns = XSD::NS.new
io << xmldecl
encode_data(io, ns, true, obj, nil, 0)
@handlers.each do |uri, handler|
handler.encode_epilogue
end
epilogue
io
end
def encode_data(buf, ns, qualified, obj, parent, indent)
if obj.is_a?(SOAPEnvelopeElement)
encode_element(buf, ns, qualified, obj, parent, indent)
return
end
if @reftarget && !obj.precedents.empty?
@reftarget.add(obj.elename.name, obj)
ref = SOAPReference.new
ref.elename.name = obj.elename.name
ref.__setobj__(obj)
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
indent_str = ' ' * indent
child_indent = @pretty ? indent + 2 : indent
handler.encode_data(buf, ns, qualified, obj, parent, indent_str) do |child, child_q|
encode_data(buf, ns.clone_ns, child_q, child, obj, child_indent)
end
handler.encode_data_end(buf, ns, qualified, obj, parent, indent_str)
end
def encode_element(buf, ns, qualified, obj, parent, indent)
indent_str = ' ' * indent
child_indent = @pretty ? indent + 2 : indent
attrs = {}
if obj.is_a?(SOAPBody)
@reftarget = obj
obj.encode(buf, ns, attrs, indent_str) do |child, child_q|
encode_data(buf, ns.clone_ns, child_q, child, obj, child_indent)
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(buf, ns, attrs, indent_str) do |child, child_q|
encode_data(buf, ns.clone_ns, child_q, child, obj, child_indent)
end
end
end
def self.assign_ns(attrs, ns, namespace, tag = nil)
unless ns.assigned?(namespace)
tag = ns.assign(namespace, tag)
attrs['xmlns:' << tag] = namespace
end
end
def self.encode_tag(buf, elename, attrs = nil, indent = '')
if attrs
buf << "\n#{ indent }<#{ elename }" <<
attrs.collect { |key, value|
%Q[ #{ key }="#{ value }"]
}.join <<
'>'
else
buf << "\n#{ indent }<#{ elename }>"
end
end
def self.encode_tag_end(buf, elename, indent = '', cr = nil)
if cr
buf << "\n#{ indent }</#{ elename }>"
else
buf << "</#{ elename }>"
end
end
EncodeMap = {
'&' => '&amp;',
'<' => '&lt;',
'>' => '&gt;',
'"' => '&quot;',
'\'' => '&apos;',
"\r" => '&#xd;'
}
EncodeCharRegexp = Regexp.new("[#{EncodeMap.keys.join}]")
def self.encode_str(str)
str.gsub(EncodeCharRegexp) { |c| EncodeMap[c] }
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[<?xml version="1.0" encoding="#{ @charset }" ?>]
else
%Q[<?xml version="1.0" ?>]
end
end
end
end

21
lib/soap/mapping.rb Normal file
View file

@ -0,0 +1,21 @@
=begin
SOAP4R - Ruby type mapping utility.
Copyright (C) 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'soap/mapping/mapping'
require 'soap/mapping/registry'

310
lib/soap/mapping/factory.rb Normal file
View file

@ -0,0 +1,310 @@
=begin
SOAP4R - Mapping factory.
Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
module SOAP
module Mapping
class Factory
include TraverseSupport
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
if Object.respond_to?(:allocate)
# ruby/1.7 or later.
def create_empty_object(klass)
klass.allocate
end
else
def create_empty_object(klass)
name = klass.name
# Below line is from TANAKA, Akira's amarshal.rb.
# See http://cvs.m17n.org/cgi-bin/viewcvs/amarshal/?cvsroot=ruby
::Marshal.load(sprintf("\004\006o:%c%s\000", name.length + 5, name))
end
end
def set_instance_vars(obj, values)
values.each do |name, value|
setter = name + "="
if obj.respond_to?(setter)
obj.__send__(setter, value)
else
obj.instance_eval("@#{ name } = value")
end
end
end
def setiv2obj(obj, node, map)
return if node.nil?
vars = {}
node.each do |name, value|
vars[Mapping.elename2name(name)] = Mapping._soap2obj(value, map)
end
set_instance_vars(obj, vars)
end
def setiv2soap(node, obj, map)
obj.instance_variables.each do |var|
name = var.sub(/^@/, '')
node.add(Mapping.name2elename(name),
Mapping._obj2soap(obj.instance_eval(var), map))
end
end
def addiv2soap(node, obj, map)
return if obj.instance_variables.empty?
ivars = SOAPStruct.new # Undefined type.
setiv2soap(ivars, obj, map)
node.add('ivars', ivars)
end
# It breaks Thread.current[:SOAPMarshalDataKey].
def mark_marshalled_obj(obj, soap_obj)
Thread.current[:SOAPMarshalDataKey][obj.__id__] = soap_obj
end
# It breaks Thread.current[:SOAPMarshalDataKey].
def mark_unmarshalled_obj(node, obj)
Thread.current[:SOAPMarshalDataKey][node.id] = obj
end
def name2typename(name)
capitalize(name)
end
def capitalize(target)
target.gsub(/^([a-z])/) { $1.tr!('[a-z]', '[A-Z]') }
end
end
class StringFactory_ < Factory
def obj2soap(soap_class, obj, info, map)
begin
if XSD::Charset.is_ces(obj, $KCODE)
encoded = XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding)
soap_obj = soap_class.new(encoded)
else
return nil
end
rescue XSD::ValueSpaceError
return nil
end
mark_marshalled_obj(obj, soap_obj)
soap_obj
end
def soap2obj(obj_class, node, info, map)
obj = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding, $KCODE)
mark_unmarshalled_obj(node, obj)
return true, obj
end
end
class BasetypeFactory_ < Factory
def obj2soap(soap_class, obj, info, map)
soap_obj = nil
begin
soap_obj = soap_class.new(obj)
rescue XSD::ValueSpaceError
return nil
end
# Basetype except String should not be multiref-ed in SOAP/1.1.
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 obj2soap(soap_class, obj, info, map)
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)
obj = nil
if obj_class == Time
obj = node.to_time
if obj.nil?
# Is out of range as a Time
return false
end
elsif obj_class == Date
obj = node.data
else
return false
end
mark_unmarshalled_obj(node, obj)
return true, obj
end
end
class Base64Factory_ < 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.string
mark_unmarshalled_obj(node, obj)
return true, obj
end
end
class ArrayFactory_ < Factory
# [[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)
arytype = Mapping.obj2element(obj)
if arytype.name
arytype.namespace ||= RubyTypeNamespace
else
arytype = XSD::AnyTypeName
end
param = SOAPArray.new(ValueArrayName, 1, arytype)
mark_marshalled_obj(obj, param)
obj.each do |var|
param.add(Mapping._obj2soap(var, map))
end
param
end
def soap2obj(obj_class, node, info, map)
obj = 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 obj2soap(soap_class, obj, info, map)
arytype = info[:type] || info[0]
param = SOAPArray.new(ValueArrayName, 1, arytype)
mark_marshalled_obj(obj, param)
obj.each do |var|
param.add(Mapping._obj2soap(var, map))
end
param
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 = 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]
param = soap_class.new(type)
mark_marshalled_obj(obj, param)
if obj.class <= SOAP::Marshallable
setiv2soap(param, obj, map)
else
setiv2soap(param, obj, map)
end
param
end
def soap2obj(obj_class, node, info, map)
type = info[:type] || info[0]
unless node.type == type
return false
end
obj = 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 obj2soap(soap_class, obj, info, map)
if obj.default or
(obj.respond_to?(:default_proc) and obj.default_proc)
return nil
end
param = SOAPStruct.new(MapQName)
mark_marshalled_obj(obj, param)
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.
param.add("item", elem)
end
param
end
def soap2obj(obj_class, node, info, map)
unless node.type == MapQName
return false
end
if node.key?('default')
return false
end
obj = create_empty_object(obj_class)
mark_unmarshalled_obj(node, obj)
node.each do |key, value|
obj[Mapping._soap2obj(value['key'], map)] =
Mapping._soap2obj(value['value'], map)
end
return true, obj
end
end
end
end

218
lib/soap/mapping/mapping.rb Normal file
View file

@ -0,0 +1,218 @@
=begin
SOAP4R - Ruby type mapping utility.
Copyright (C) 2000, 2001, 2003 NAKAMURA Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
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 Thread.current[:SOAPMarshalDataKey].
module TraverseSupport
def mark_marshalled_obj(obj, soap_obj)
Thread.current[:SOAPMarshalDataKey][obj.__id__] = soap_obj
end
def mark_unmarshalled_obj(node, obj)
# node.id is not Object#id but SOAPReference#id
Thread.current[:SOAPMarshalDataKey][node.id] = obj
end
end
def self.obj2soap(obj, registry = nil, type = nil)
registry ||= Mapping::DefaultRegistry
Thread.current[:SOAPMarshalDataKey] = {}
soap_obj = _obj2soap(obj, registry, type)
Thread.current[:SOAPMarshalDataKey] = nil
soap_obj
end
def self.soap2obj(node, registry = nil)
registry ||= Mapping::DefaultRegistry
Thread.current[:SOAPMarshalDataKey] = {}
obj = _soap2obj(node, registry)
Thread.current[:SOAPMarshalDataKey] = nil
obj
end
def self.ary2soap(ary, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil)
registry ||= Mapping::DefaultRegistry
type = XSD::QName.new(type_ns, typename)
soap_ary = SOAPArray.new(ValueArrayName, 1, type)
Thread.current[:SOAPMarshalDataKey] = {}
ary.each do |ele|
soap_ary.add(_obj2soap(ele, registry, type))
end
Thread.current[:SOAPMarshalDataKey] = nil
soap_ary
end
def self.ary2md(ary, rank, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil)
registry ||= Mapping::DefaultRegistry
type = XSD::QName.new(type_ns, typename)
md_ary = SOAPArray.new(ValueArrayName, rank, type)
Thread.current[:SOAPMarshalDataKey] = {}
add_md_ary(md_ary, ary, [], registry)
Thread.current[:SOAPMarshalDataKey] = nil
md_ary
end
def self.fault2exception(e, registry = nil)
registry ||= Mapping::DefaultRegistry
detail = if e.detail
soap2obj(e.detail, registry) || ""
else
""
end
if detail.is_a?(Mapping::SOAPException)
begin
raise detail.to_e
rescue Exception => e2
detail.set_backtrace(e2)
raise
end
else
e.detail = detail
e.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__]
soap_obj = SOAPReference.new
soap_obj.__setobj__(referent)
soap_obj
else
registry.obj2soap(obj.class, obj, type)
end
end
def self._soap2obj(node, registry)
if node.is_a?(SOAPReference)
target = node.__getobj__
# target.id is not Object#id but SOAPReference#id
if referent = Thread.current[:SOAPMarshalDataKey][target.id]
return referent
else
return _soap2obj(target, registry)
end
end
return registry.soap2obj(node.class, node)
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.class_from_name(name)
if /^[A-Z]/ !~ name
return nil
end
klass = ::Object
name.split('::').each do |klass_str|
if klass.const_defined?(klass_str)
klass = klass.const_get(klass_str)
else
return nil
end
end
klass
end
def self.class2qname(klass)
name = if klass.class_variables.include?("@@schema_type")
klass.class_eval("@@schema_type")
else
nil
end
namespace = if klass.class_variables.include?("@@schema_ns")
klass.class_eval("@@schema_ns")
else
nil
end
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_eval("@schema_type")
end
if ivars.include?("@schema_ns")
namespace = obj.instance_eval("@schema_ns")
end
if !name or !namespace
class2qname(obj.class)
else
XSD::QName.new(namespace, name)
end
end
class << Mapping
private
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

View file

@ -0,0 +1,408 @@
=begin
SOAP4R - Mapping registry.
Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
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')
# Inner class to pass an exception.
class SOAPException; include Marshallable
attr_reader :excn_type_name, :message, :backtrace, :cause
def initialize(e)
@excn_type_name = Mapping.name2elename(e.class.to_s)
@message = e.message
@backtrace = e.backtrace
@cause = e
end
def to_e
if @cause.is_a?(::Exception)
@cause.extend(::SOAP::Mapping::MappedException)
return @cause
end
klass = Mapping.class_from_name(
Mapping.elename2name(@excn_type_name.to_s))
if klass.nil?
raise RuntimeError.new(@message)
end
unless klass <= ::Exception
raise NameError.new
end
obj = klass.new(@message)
obj.extend(::SOAP::Mapping::MappedException)
obj
end
def set_backtrace(e)
e.set_backtrace(
if @backtrace.is_a?(Array)
@backtrace
else
[@backtrace.inspect]
end
)
end
end
# For anyType object: SOAP::Mapping::Object not ::Object
class Object; include Marshallable
def set_property(name, value)
var_name = name
begin
instance_eval <<-EOS
def #{ var_name }
@#{ var_name }
end
def #{ var_name }=(value)
@#{ var_name } = value
end
EOS
self.send(var_name + '=', value)
rescue SyntaxError
var_name = safe_name(var_name)
retry
end
var_name
end
def members
instance_variables.collect { |str| str[1..-1] }
end
def [](name)
if self.respond_to?(name)
self.send(name)
else
self.send(safe_name(name))
end
end
def []=(name, value)
if self.respond_to?(name)
self.send(name + '=', value)
else
self.send(safe_name(name) + '=', value)
end
end
private
def safe_name(name)
require 'md5'
"var_" << MD5.new(name).hexdigest
end
end
class MappingError < Error; end
class Registry
class Map
def initialize(registry)
@map = []
@registry = registry
end
def obj2soap(klass, obj)
@map.each do |obj_class, soap_class, factory, info|
if klass == obj_class or
(info[:derived_class] and klass <= obj_class)
ret = factory.obj2soap(soap_class, obj, info, @registry)
return ret if ret
end
end
nil
end
def soap2obj(klass, node)
@map.each do |obj_class, soap_class, factory, info|
if klass == soap_class or
(info[:derived_class] and klass <= soap_class)
conv, obj = factory.soap2obj(obj_class, node, info, @registry)
return true, obj if conv
end
end
return false
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 ||= {}
@map.unshift([obj_class, soap_class, factory, info])
end
def clear
@map.clear
end
def find_mapped_soap_class(target_obj_class)
@map.each do |obj_class, soap_class, factory, info|
if obj_class == target_obj_class
return soap_class
end
end
nil
end
def find_mapped_obj_class(target_soap_class)
@map.each do |obj_class, soap_class, factory, info|
if soap_class == target_soap_class
return obj_class
end
end
nil
end
end
StringFactory = StringFactory_.new
BasetypeFactory = BasetypeFactory_.new
DateTimeFactory = DateTimeFactory_.new
ArrayFactory = ArrayFactory_.new
Base64Factory = Base64Factory_.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, BasetypeFactory],
[::Date, ::SOAP::SOAPDateTime, BasetypeFactory],
[::Date, ::SOAP::SOAPDate, BasetypeFactory],
[::Time, ::SOAP::SOAPDateTime, BasetypeFactory],
[::Time, ::SOAP::SOAPTime, BasetypeFactory],
[::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}],
[::URI::Generic, ::SOAP::SOAPAnyURI, BasetypeFactory,
{: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],
[::Array, ::SOAP::SOAPArray, ArrayFactory,
{:derived_class => true}],
[::Hash, ::SOAP::SOAPStruct, HashFactory],
[::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, BasetypeFactory],
[::Date, ::SOAP::SOAPDateTime, BasetypeFactory],
[::Date, ::SOAP::SOAPDate, BasetypeFactory],
[::Time, ::SOAP::SOAPDateTime, BasetypeFactory],
[::Time, ::SOAP::SOAPTime, BasetypeFactory],
[::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}],
[::URI::Generic, ::SOAP::SOAPAnyURI, BasetypeFactory,
{: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],
# Does not allow Array's subclass here.
[::Array, ::SOAP::SOAPArray, ArrayFactory],
[::Hash, ::SOAP::SOAPStruct, HashFactory],
[::SOAP::Mapping::SOAPException,
::SOAP::SOAPStruct, TypedStructFactory,
{:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}],
]
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
# This mapping registry ignores type hint.
def obj2soap(klass, obj, type = nil)
ret = nil
if obj.is_a?(SOAPStruct) || 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(klass, obj) ||
@default_factory.obj2soap(klass, obj, nil, self)
rescue MappingError
end
return ret if ret
if @excn_handler_obj2soap
ret = @excn_handler_obj2soap.call(obj) { |yield_obj|
Mapping._obj2soap(yield_obj, self)
}
end
return ret if ret
raise MappingError.new("Cannot map #{ klass.name } to SOAP/OM.")
end
def soap2obj(klass, node)
if node.extraattr.key?(RubyTypeName)
conv, obj = @rubytype_factory.soap2obj(klass, node, nil, self)
return obj if conv
else
conv, obj = @map.soap2obj(klass, node)
return obj if conv
conv, obj = @default_factory.soap2obj(klass, 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 default_factory=(factory)
@default_factory = factory
end
def excn_handler_obj2soap=(handler)
@excn_handler_obj2soap = handler
end
def excn_handler_soap2obj=(handler)
@excn_handler_soap2obj = handler
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
end
DefaultRegistry = Registry.new
RubyOriginalRegistry = Registry.new(:allow_original_mapping => true)
end
end

View file

@ -0,0 +1,437 @@
=begin
SOAP4R - Ruby type mapping factory.
Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
module SOAP
module Mapping
class RubytypeFactory < Factory
TYPE_STRING = 'String'
TYPE_ARRAY = 'Array'
TYPE_REGEXP = 'Regexp'
TYPE_RANGE = 'Range'
TYPE_CLASS = 'Class'
TYPE_MODULE = 'Module'
TYPE_SYMBOL = 'Symbol'
TYPE_STRUCT = 'Struct'
TYPE_HASH = '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
end
def obj2soap(soap_class, obj, info, map)
param = nil
case obj
when String
unless @allow_original_mapping
return nil
end
unless XSD::Charset.is_ces(obj, $KCODE)
return nil
end
encoded = XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding)
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_STRING))
mark_marshalled_obj(obj, param)
param.add('string', SOAPString.new(encoded))
if obj.class != String
param.extraattr[RubyTypeName] = obj.class.name
end
addiv2soap(param, obj, map)
when Array
unless @allow_original_mapping
return nil
end
arytype = Mapping.obj2element(obj)
if arytype.name
arytype.namespace ||= RubyTypeNamespace
else
arytype = XSD::AnyTypeName
end
if obj.instance_variables.empty?
param = SOAPArray.new(ValueArrayName, 1, arytype)
mark_marshalled_obj(obj, param)
obj.each do |var|
param.add(Mapping._obj2soap(var, map))
end
else
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_ARRAY))
mark_marshalled_obj(obj, param)
ary = SOAPArray.new(ValueArrayName, 1, arytype)
obj.each do |var|
ary.add(Mapping._obj2soap(var, map))
end
param.add('array', ary)
addiv2soap(param, obj, map)
end
if obj.class != Array
param.extraattr[RubyTypeName] = obj.class.name
end
when Regexp
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, 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))
addiv2soap(param, obj, map)
when Range
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, 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?))
addiv2soap(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(XSD::QName.new(RubyTypeNamespace, 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))
addiv2soap(param, obj, map)
when Class
if obj.name.empty?
raise TypeError.new("Can't dump anonymous class #{ obj }.")
end
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_CLASS))
mark_marshalled_obj(obj, param)
param.add('name', SOAPString.new(obj.name))
addiv2soap(param, obj, map)
when Module
if obj.name.empty?
raise TypeError.new("Can't dump anonymous module #{ obj }.")
end
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_MODULE))
mark_marshalled_obj(obj, param)
param.add('name', SOAPString.new(obj.name))
addiv2soap(param, obj, map)
when Symbol
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_SYMBOL))
mark_marshalled_obj(obj, param)
param.add('id', SOAPString.new(obj.id2name))
addiv2soap(param, obj, map)
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))
addiv2soap(param, obj, map)
when Struct
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, 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)
addiv2soap(param, obj, map)
when IO, Binding, Continuation, Data, Dir, File::Stat, MatchData, Method,
Proc, Thread, ThreadGroup
return nil
when ::SOAP::Mapping::Object
param = SOAPStruct.new(XSD::AnyTypeName)
mark_marshalled_obj(obj, param)
setiv2soap(param, obj, map) # addiv2soap?
else
if obj.class.name.empty?
raise TypeError.new("Can't dump anonymous class #{ obj }.")
end
if check_singleton(obj)
raise TypeError.new("singleton can't be dumped #{ obj }")
end
type = Mapping.class2element(obj.class)
param = SOAPStruct.new(type)
mark_marshalled_obj(obj, param)
if obj.class <= Marshallable
setiv2soap(param, obj, map)
else
setiv2soap(param, obj, map) # Should not be marshalled?
end
end
param
end
def soap2obj(obj_class, node, info, map)
rubytype = node.extraattr[RubyTypeName]
if rubytype or node.type.namespace == RubyTypeNamespace
rubytype2obj(node, map, rubytype)
elsif node.type == XSD::AnyTypeName or node.type == XSD::AnySimpleTypeName
anytype2obj(node, map)
else
unknowntype2obj(node, map)
end
end
private
def check_singleton(obj)
unless singleton_methods_true(obj).empty?
return true
end
singleton_class = class << obj; self; end
if !singleton_class.instance_variables.empty? or
!(singleton_class.ancestors - obj.class.ancestors).empty?
return true
end
false
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, map, rubytype)
obj = nil
case node.class
when SOAPString
obj = string2obj(node, map, rubytype)
obj.replace(node.data)
return true, obj
when SOAPArray
obj = array2obj(node, map, rubytype)
node.soap2array(obj) do |elem|
elem ? Mapping._soap2obj(elem, map) : nil
end
return true, obj
end
case node.type.name
when TYPE_STRING
obj = string2obj(node, map, rubytype)
obj.replace(node['string'].data)
setiv2obj(obj, node['ivars'], map)
when TYPE_ARRAY
obj = array2obj(node, map, rubytype)
node['array'].soap2array(obj) do |elem|
elem ? Mapping._soap2obj(elem, map) : nil
end
setiv2obj(obj, node['ivars'], map)
when TYPE_REGEXP
klass = rubytype ? Mapping.class_from_name(rubytype) : Regexp
obj = create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
source = node['source'].string
options = node['options'].data || 0
obj.instance_eval { initialize(source, options) }
setiv2obj(obj, node['ivars'], map)
when TYPE_RANGE
klass = rubytype ? Mapping.class_from_name(rubytype) : Range
obj = 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
obj.instance_eval { initialize(first, last, exclude_end) }
setiv2obj(obj, node['ivars'], map)
when TYPE_HASH
unless @allow_original_mapping
return false
end
klass = rubytype ? Mapping.class_from_name(rubytype) : Hash
obj = 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
setiv2obj(obj, node['ivars'], map)
when TYPE_CLASS
obj = Mapping.class_from_name(node['name'].data)
setiv2obj(obj, node['ivars'], map)
when TYPE_MODULE
obj = Mapping.class_from_name(node['name'].data)
setiv2obj(obj, node['ivars'], map)
when TYPE_SYMBOL
obj = node['id'].data.intern
setiv2obj(obj, node['ivars'], map)
when TYPE_STRUCT
typestr = Mapping.elename2name(node['type'].data)
klass = Mapping.class_from_name(typestr)
if klass.nil?
klass = Mapping.class_from_name(name2typename(typestr))
end
if klass.nil?
return false
end
unless klass <= ::Struct
return false
end
obj = create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
node['member'].each do |name, value|
obj[Mapping.elename2name(name)] =
Mapping._soap2obj(value, map)
end
setiv2obj(obj, node['ivars'], map)
else
conv, obj = exception2obj(node, map)
unless conv
return false
end
setiv2obj(obj, node['ivars'], map)
end
return true, obj
end
def exception2obj(node, map)
typestr = Mapping.elename2name(node.type.name)
klass = Mapping.class_from_name(typestr)
if klass.nil?
return false
end
unless klass <= Exception
return false
end
message = Mapping._soap2obj(node['message'], map)
backtrace = Mapping._soap2obj(node['backtrace'], map)
obj = create_empty_object(klass)
obj = obj.exception(message)
mark_unmarshalled_obj(node, obj)
obj.set_backtrace(backtrace)
setiv2obj(obj, node['ivars'], map)
return true, obj
end
def anytype2obj(node, 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.set_property(name, Mapping._soap2obj(value, map))
end
return true, obj
else
return false
end
end
def unknowntype2obj(node, map)
if node.is_a?(SOAPStruct)
obj = struct2obj(node, map)
return true, obj if obj
if !@allow_untyped_struct
return false
end
return anytype2obj(node, map)
else
# Basetype which is not defined...
return false
end
end
def struct2obj(node, map)
obj = nil
typestr = Mapping.elename2name(node.type.name)
klass = Mapping.class_from_name(typestr)
if klass.nil?
klass = Mapping.class_from_name(name2typename(typestr))
end
if klass.nil?
return nil
end
klass_type = Mapping.class2qname(klass)
return nil unless node.type.match(klass_type)
obj = create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
setiv2obj(obj, node, map)
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 = 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 = create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
obj
end
end
end
end

View file

@ -0,0 +1,52 @@
=begin
SOAP4R - Base type mapping definition
Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
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::XSDLong::Type => SOAPLong,
XSD::XSDInt::Type => SOAPInt,
XSD::XSDShort::Type => SOAPShort,
SOAP::SOAPBase64::Type => SOAPBase64,
}
end

View file

@ -0,0 +1,146 @@
=begin
SOAP4R - WSDL mapping registry.
Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'soap/baseData'
require 'soap/mapping/mapping'
require 'soap/mapping/typeMap'
module SOAP
module Mapping
class WSDLRegistry
include TraverseSupport
attr_reader :complextypes
def initialize(complextypes, config = {})
@complextypes = complextypes
@config = config
@excn_handler_obj2soap = nil
# For mapping AnyType element.
@rubytype_factory = RubytypeFactory.new(
:allow_untyped_struct => true,
:allow_original_mapping => true
)
end
def obj2soap(klass, obj, type_qname)
soap_obj = nil
if obj.nil?
soap_obj = SOAPNil.new
elsif obj.is_a?(XSD::NSDBase)
soap_obj = soap2soap(obj, type_qname)
elsif (type = @complextypes[type_qname])
case type.compoundtype
when :TYPE_STRUCT
soap_obj = struct2soap(obj, type_qname, type)
when :TYPE_ARRAY
soap_obj = array2soap(obj, type_qname, type)
end
elsif (type = TypeMap[type_qname])
soap_obj = base2soap(obj, type)
elsif type_qname == XSD::AnyTypeName
soap_obj = @rubytype_factory.obj2soap(nil, obj, nil, nil)
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)
}
end
return soap_obj if soap_obj
raise MappingError.new("Cannot map #{ klass.name } to SOAP/OM.")
end
def soap2obj(klass, node)
raise RuntimeError.new("#{ self } is for obj2soap only.")
end
def excn_handler_obj2soap=(handler)
@excn_handler_obj2soap = handler
end
private
def soap2soap(obj, type_qname)
if obj.is_a?(SOAPBasetype)
obj
elsif obj.is_a?(SOAPStruct) && (type = @complextypes[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 = @complextypes[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 base2soap(obj, type)
soap_obj = nil
if type <= XSD::XSDString
soap_obj = type.new(XSD::Charset.is_ces(obj, $KCODE) ?
XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding) : obj)
mark_marshalled_obj(obj, soap_obj)
else
soap_obj = type.new(obj)
end
soap_obj
end
def struct2soap(obj, type_qname, type)
soap_obj = SOAPStruct.new(type_qname)
mark_marshalled_obj(obj, soap_obj)
elements2soap(obj, soap_obj, type.content.elements)
soap_obj
end
def array2soap(obj, type_qname, type)
contenttype = type.child_type
soap_obj = SOAPArray.new(ValueArrayName, 1, contenttype)
mark_marshalled_obj(obj, soap_obj)
obj.each do |item|
soap_obj.add(Mapping._obj2soap(item, self, contenttype))
end
soap_obj
end
def elements2soap(obj, soap_obj, elements)
elements.each do |element|
name = element.name.name
child_obj = obj.instance_eval("@#{ name }")
soap_obj.add(name, Mapping._obj2soap(child_obj, self, element.type))
end
end
end
end
end

71
lib/soap/marshal.rb Normal file
View file

@ -0,0 +1,71 @@
=begin
SOAP4R - Marshalling/Unmarshalling Ruby's object using SOAP Encoding.
Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
# The original version of the marshal.rb to marshal/unmarshal Ruby's object
# using SOAP Encoding was written by Michael Neumann. His valuable comments
# and his program inspired me to write this. Thanks.
require "soap/mapping"
require "soap/processor"
module SOAP
module Marshal
# Trying xsd:dateTime data to be recovered as aTime. aDateTime if it fails.
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)
SOAP::Processor.marshal(nil, body, {}, io)
end
def unmarshal(stream, mapping_registry = MarshalMappingRegistry)
header, body = SOAP::Processor.unmarshal(stream)
Mapping.soap2obj(body.root_node, mapping_registry)
end
end
end
end
SOAPMarshal = SOAP::Marshal

101
lib/soap/netHttpClient.rb Normal file
View file

@ -0,0 +1,101 @@
=begin
SOAP4R - net/http wrapper
Copyright (C) 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'net/http'
module SOAP
class NetHttpClient
attr_accessor :proxy
attr_accessor :debug_dev
attr_reader :session_manager
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
def initialize(proxy = nil, agent = nil)
@proxy = proxy ? URI.parse(proxy) : nil
@agent = agent
@debug_dev = nil
@session_manager = SessionManager.new
end
def reset(url)
# ignored.
end
def post(url, req_body, header = {})
url = URI.parse(url)
extra = header.dup
extra['User-Agent'] = @agent if @agent
res = start(url) { |http|
http.post(url.instance_eval('path_query'), req_body, extra)
}
Response.new(res)
end
def get_content(url, header = {})
url = URI.parse(url)
extra = header.dup
extra['User-Agent'] = @agent if @agent
res = start(url) { |http|
http.get(url.instance_eval('path_query'), extra)
}
res.body
end
private
def start(url)
proxy_host = @proxy ? @proxy.host : nil
proxy_port = @proxy ? @proxy.port : nil
response = nil
Net::HTTP::Proxy(proxy_host, proxy_port).start(url.host, url.port) { |http|
if http.respond_to?(:set_debug_output)
http.set_debug_output(@debug_dev)
end
response, = yield(http)
http.finish
}
response
end
end
end

252
lib/soap/parser.rb Normal file
View file

@ -0,0 +1,252 @@
=begin
SOAP4R - SOAP XML Instance Parser library.
Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
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 :default_encodingstyle
attr_accessor :decode_typemap
attr_accessor :allow_unqualified_element
def initialize(opt = {})
@parser = XSD::XMLParser.create_parser(self, opt)
@parsestack = nil
@lastnode = nil
@handlers = {}
@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.
encodingstyle ||= parent_encodingstyle || @default_encodingstyle
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.
ns = lastframe.ns
parent = lastframe.node
encodingstyle = lastframe.encodingstyle
decode_text(ns, text, 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
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.parent = parent if o
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

79
lib/soap/processor.rb Normal file
View file

@ -0,0 +1,79 @@
=begin
SOAP4R - marshal/unmarshal interface.
Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
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(header, body, opt = {}, io = nil)
env = SOAPEnvelope.new(header, body)
generator = create_generator(opt)
generator.generate(env, io)
end
def unmarshal(stream, opt = {})
parser = create_parser(opt)
env = parser.parse(stream)
if env
return env.header, env.body
else
return nil, nil
end
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

214
lib/soap/rpc/cgistub.rb Normal file
View file

@ -0,0 +1,214 @@
=begin
SOAP4R - CGI stub library
Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'soap/streamHandler'
require 'webrick/httpresponse'
require 'webrick/httpstatus'
require 'logger'
require 'soap/rpc/router'
module SOAP
module RPC
###
# SYNOPSIS
# CGIStub.new
#
# DESCRIPTION
# To be written...
#
class CGIStub < Logger::Application
include SOAP
# There is a client which does not accept the media-type which is defined in
# SOAP spec.
attr_accessor :mediatype
class CGIError < Error; end
class SOAPRequest
ALLOWED_LENGTH = 1024 * 1024
def initialize(stream = $stdin)
@method = ENV['REQUEST_METHOD']
@size = ENV['CONTENT_LENGTH'].to_i || 0
@contenttype = ENV['CONTENT_TYPE']
@charset = nil
@soapaction = ENV['HTTP_SOAPAction']
@source = stream
@body = nil
end
def init
validate
@charset = StreamHandler.parse_media_type(@contenttype)
@body = @source.read(@size)
self
end
def dump
@body.dup
end
def soapaction
@soapaction
end
def charset
@charset
end
def to_s
"method: #{ @method }, size: #{ @size }"
end
private
def validate # raise CGIError
if @method != 'POST'
raise CGIError.new("Method '#{ @method }' not allowed.")
end
if @size > ALLOWED_LENGTH
raise CGIError.new("Content-length too long.")
end
end
end
def initialize(appname, default_namespace)
super(appname)
set_log(STDERR)
self.level = INFO
@default_namespace = default_namespace
@router = SOAP::RPC::Router.new(appname)
@remote_user = ENV['REMOTE_USER'] || 'anonymous'
@remote_host = ENV['REMOTE_HOST'] || ENV['REMOTE_ADDR'] || 'unknown'
@request = nil
@response = nil
@mediatype = MediaType
on_init
end
def add_servant(obj, namespace = @default_namespace, soapaction = nil)
RPC.defined_methods(obj).each do |name|
qname = XSD::QName.new(namespace, name)
param_size = obj.method(name).arity.abs
params = (1..param_size).collect { |i| "p#{ i }" }
param_def = SOAP::RPC::SOAPMethod.create_param_def(params)
@router.add_method(obj, qname, soapaction, name, param_def)
end
end
def on_init
# Override this method in derived class to call 'add_method' to add methods.
end
def mapping_registry
@router.mapping_registry
end
def mapping_registry=(value)
@router.mapping_registry = value
end
def add_method(receiver, name, *param)
add_method_with_namespace_as(@default_namespace, receiver,
name, name, *param)
end
def add_method_as(receiver, name, name_as, *param)
add_method_with_namespace_as(@default_namespace, receiver,
name, name_as, *param)
end
def add_method_with_namespace(namespace, receiver, name, *param)
add_method_with_namespace_as(namespace, receiver, name, name, *param)
end
def add_method_with_namespace_as(namespace, receiver, name, name_as, *param)
param_def = if param.size == 1 and param[0].is_a?(Array)
param[0]
else
SOAP::RPC::SOAPMethod.create_param_def(param)
end
qname = XSD::QName.new(namespace, name_as)
@router.add_method(receiver, qname, nil, name, param_def)
end
def route(request_string, charset)
@router.route(request_string, charset)
end
def create_fault_response(e)
@router.create_fault_response(e)
end
private
def run
prologue
httpversion = WEBrick::HTTPVersion.new('1.0')
@response = WEBrick::HTTPResponse.new({:HTTPVersion => httpversion})
begin
log(INFO) { "Received a request from '#{ @remote_user }@#{ @remote_host }'." }
# SOAP request parsing.
@request = SOAPRequest.new.init
req_charset = @request.charset
req_string = @request.dump
log(DEBUG) { "XML Request: #{req_string}" }
res_string, is_fault = route(req_string, req_charset)
log(DEBUG) { "XML Response: #{res_string}" }
@response['Cache-Control'] = 'private'
if req_charset
@response['content-type'] = "#{@mediatype}; charset=\"#{req_charset}\""
else
@response['content-type'] = @mediatype
end
if is_fault
@response.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR
end
@response.body = res_string
rescue Exception
res_string = create_fault_response($!)
@response['Cache-Control'] = 'private'
@response['content-type'] = @mediatype
@response.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR
ensure
buf = ''
@response.send_response(buf)
buf.sub!(/^[^\r]+\r\n/, '') # Trim status line.
log(DEBUG) { "SOAP CGI Response:\n#{ buf }" }
print buf
epilogue
end
0
end
def prologue; end
def epilogue; end
end
end
end

189
lib/soap/rpc/driver.rb Normal file
View file

@ -0,0 +1,189 @@
=begin
SOAP4R - SOAP RPC driver
Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'soap/soap'
require 'soap/mapping'
require 'soap/rpc/rpc'
require 'soap/rpc/proxy'
require 'soap/rpc/element'
require 'soap/streamHandler'
module SOAP
module RPC
class Driver
public
class EmptyResponseError < Error; end
attr_accessor :mapping_registry
attr_accessor :soapaction
attr_reader :endpoint_url
attr_reader :wiredump_dev
attr_reader :wiredump_file_base
attr_reader :httpproxy
def initialize(endpoint_url, namespace, soapaction = nil)
@endpoint_url = endpoint_url
@namespace = namespace
@mapping_registry = nil # for unmarshal
@soapaction = soapaction
@wiredump_dev = nil
@wiredump_file_base = nil
@httpproxy = ENV['httpproxy'] || ENV['HTTP_PROXY']
@handler = HTTPPostStreamHandler.new(@endpoint_url, @httpproxy,
XSD::Charset.encoding_label)
@proxy = Proxy.new(@handler, @soapaction)
@proxy.allow_unqualified_element = true
end
def endpoint_url=(endpoint_url)
@endpoint_url = endpoint_url
if @handler
@handler.endpoint_url = @endpoint_url
@handler.reset
end
end
def wiredump_dev=(dev)
@wiredump_dev = dev
if @handler
@handler.wiredump_dev = @wiredump_dev
@handler.reset
end
end
def wiredump_file_base=(base)
@wiredump_file_base = base
end
def httpproxy=(httpproxy)
@httpproxy = httpproxy
if @handler
@handler.proxy = @httpproxy
@handler.reset
end
end
def default_encodingstyle
@proxy.default_encodingstyle
end
def default_encodingstyle=(encodingstyle)
@proxy.default_encodingstyle = encodingstyle
end
###
## Method definition interfaces.
#
# params: [[param_def...]] or [paramname, paramname, ...]
# param_def: See proxy.rb. Sorry.
def add_method(name, *params)
add_method_with_soapaction_as(name, name, @soapaction, *params)
end
def add_method_as(name, name_as, *params)
add_method_with_soapaction_as(name, name_as, @soapaction, *params)
end
def add_method_with_soapaction(name, soapaction, *params)
add_method_with_soapaction_as(name, name, soapaction, *params)
end
def add_method_with_soapaction_as(name, name_as, soapaction, *params)
param_def = if params.size == 1 and params[0].is_a?(Array)
params[0]
else
SOAPMethod.create_param_def(params)
end
qname = XSD::QName.new(@namespace, name_as)
@proxy.add_method(qname, soapaction, name, param_def)
add_rpc_method_interface(name, param_def)
end
###
## Driving interface.
#
def invoke(headers, body)
if @wiredump_file_base
@handler.wiredump_file_base =
@wiredump_file_base + '_' << body.elename.name
end
@proxy.invoke(headers, body)
end
def call(name, *params)
# Convert parameters: params array => SOAPArray => members array
params = Mapping.obj2soap(params, @mapping_registry).to_a
if @wiredump_file_base
@handler.wiredump_file_base = @wiredump_file_base + '_' << name
end
# Then, call @proxy.call like the following.
header, body = @proxy.call(nil, name, *params)
unless body
raise EmptyResponseError.new("Empty response.")
end
begin
@proxy.check_fault(body)
rescue SOAP::FaultError => e
Mapping.fault2exception(e)
end
ret = body.response ? Mapping.soap2obj(body.response, @mapping_registry) : nil
if body.outparams
outparams = body.outparams.collect { |outparam| Mapping.soap2obj(outparam) }
return [ret].concat(outparams)
else
return ret
end
end
def reset_stream
@handler.reset
end
private
def add_rpc_method_interface(name, param_def)
param_names = []
i = 0
@proxy.method[name].each_param_name(RPC::SOAPMethod::IN,
RPC::SOAPMethod::INOUT) do |param_name|
i += 1
param_names << "arg#{ i }"
end
callparam = (param_names.collect { |pname| ", " + pname }).join
self.instance_eval <<-EOS
def #{ name }(#{ param_names.join(", ") })
call("#{ name }"#{ callparam })
end
EOS
end
end
end
end

278
lib/soap/rpc/element.rb Normal file
View file

@ -0,0 +1,278 @@
=begin
SOAP4R - RPC element definition.
Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
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
if !@is_fault
if void?
nil
else
# Initial element is [retval].
root_node[0]
end
else
root_node
end
end
def outparams
if !@is_fault and !void?
op = root_node[1..-1]
op = nil if op && op.empty?
op
else
nil
end
end
def void?
root_node.nil? # || root_node.is_a?(SOAPNil)
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
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
init_param(@param_def) if @param_def
end
def have_outparam?
@outparam_names.size > 0
end
def each_param_name(*type)
@signature.each do |io_type, name, param_type|
if type.include?(io_type)
yield(name)
end
end
end
def set_param(params)
params.each do |param, data|
@inparam[param] = data
data.elename.name = param
end
end
def set_outparam(params)
params.each do |param, data|
@outparam[param] = data
data.elename.name = param
end
end
def SOAPMethod.create_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
private
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
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, nil, param_name]
param_value << [param_name, param]
end
param_def << [RETVAL, nil, 'return']
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
each_param_name(IN, INOUT) 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
SOAPMethodResponse.new(
XSD::QName.new(@elename.namespace, @elename.name + 'Response'),
@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('return')
end
def each
if @retval_name and !@retval.is_a?(SOAPVoid)
yield(@retval_name, @retval)
end
each_param_name(OUT, INOUT) do |param_name|
unless @outparam[param_name]
raise ParameterError.new("Parameter: #{ param_name } was not given.")
end
yield(param_name, @outparam[param_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

147
lib/soap/rpc/proxy.rb Normal file
View file

@ -0,0 +1,147 @@
=begin
SOAP4R - RPC Proxy library.
Copyright (C) 2000, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'soap/soap'
require 'soap/processor'
require 'soap/mapping'
require 'soap/rpc/rpc'
require 'soap/rpc/element'
require 'soap/streamHandler'
module SOAP
module RPC
class Proxy
include SOAP
public
attr_accessor :soapaction
attr_accessor :allow_unqualified_element, :default_encodingstyle
attr_reader :method
def initialize(stream_handler, soapaction = nil)
@handler = stream_handler
@soapaction = soapaction
@method = {}
@allow_unqualified_element = false
@default_encodingstyle = nil
end
class Request
include RPC
public
attr_reader :method
attr_reader :namespace
attr_reader :name
def initialize(model, values)
@method = model.dup
@namespace = @method.elename.namespace
@name = @method.elename.name
params = {}
if ((values.size == 1) and (values[0].is_a?(Hash)))
params = values[0]
else
i = 0
@method.each_param_name(SOAPMethod::IN, SOAPMethod::INOUT) do |name|
params[name] = values[i] || SOAPNil.new
i += 1
end
end
@method.set_param(params)
end
end
def add_method(qname, soapaction, name, param_def)
@method[name] = SOAPMethodRequest.new(qname, param_def, soapaction)
end
def create_request(name, *values)
if (@method.key?(name))
method = @method[name]
method.encodingstyle = @default_encodingstyle if @default_encodingstyle
else
raise SOAP::RPC::MethodDefinitionError.new(
"Method: #{ name } not defined.")
end
Request.new(method, values)
end
def invoke(req_header, req_body, soapaction = nil)
if req_header and !req_header.is_a?(SOAPHeader)
req_header = create_header(req_header)
end
if !req_body.is_a?(SOAPBody)
req_body = SOAPBody.new(req_body)
end
opt = create_options
send_string = Processor.marshal(req_header, req_body, opt)
data = @handler.send(send_string, soapaction)
if data.receive_string.empty?
return nil, nil
end
res_charset = StreamHandler.parse_media_type(data.receive_contenttype)
opt = create_options
opt[:charset] = res_charset
res_header, res_body = Processor.unmarshal(data.receive_string, opt)
return res_header, res_body
end
def call(headers, name, *values)
req = create_request(name, *values)
return invoke(headers, req.method, req.method.soapaction || @soapaction)
end
def check_fault(body)
if body.fault
raise SOAP::FaultError.new(body.fault)
end
end
private
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_options
opt = {}
opt[:default_encodingstyle] = @default_encodingstyle
if @allow_unqualified_element
opt[:allow_unqualified_element] = true
end
opt
end
end
end
end

176
lib/soap/rpc/router.rb Normal file
View file

@ -0,0 +1,176 @@
=begin
SOAP4R - RPC Routing library
Copyright (C) 2001, 2002 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'soap/soap'
require 'soap/processor'
require 'soap/mapping'
require 'soap/rpc/rpc'
require 'soap/rpc/element'
module SOAP
module RPC
class Router
include SOAP
attr_reader :actor
attr_accessor :allow_unqualified_element
attr_accessor :default_encodingstyle
attr_accessor :mapping_registry
def initialize(actor)
@actor = actor
@receiver = {}
@method_name = {}
@method = {}
@allow_unqualified_element = false
@default_encodingstyle = nil
@mapping_registry = nil
end
def add_method(receiver, qname, soapaction, name, param_def)
fqname = fqname(qname)
@receiver[fqname] = receiver
@method_name[fqname] = name
@method[fqname] = RPC::SOAPMethodRequest.new(qname, param_def, soapaction)
end
def add_header_handler
raise NotImplementedError.new
end
# Routing...
def route(soap_string, charset = nil)
opt = options
opt[:charset] = charset
is_fault = false
begin
header, body = Processor.unmarshal(soap_string, opt)
# So far, header is omitted...
soap_request = body.request
unless soap_request.is_a?(SOAPStruct)
raise RPCRoutingError.new("Not an RPC style.")
end
soap_response = dispatch(soap_request)
rescue Exception
soap_response = fault($!)
is_fault = true
end
header = SOAPHeader.new
body = SOAPBody.new(soap_response)
response_string = Processor.marshal(header, body, opt)
return response_string, is_fault
end
# Create fault response string.
def create_fault_response(e, charset = nil)
header = SOAPHeader.new
soap_response = fault(e)
body = SOAPBody.new(soap_response)
opt = options
opt[:charset] = charset
Processor.marshal(header, body, opt)
end
private
# Create new response.
def create_response(qname, result)
name = fqname(qname)
if (@method.key?(name))
method = @method[name]
else
raise RPCRoutingError.new("Method: #{ name } not defined.")
end
soap_response = method.create_method_response
if soap_response.have_outparam?
unless result.is_a?(Array)
raise RPCRoutingError.new("Out parameter was not returned.")
end
outparams = {}
i = 1
soap_response.each_param_name('out', 'inout') do |outparam|
outparams[outparam] = Mapping.obj2soap(result[i], @mapping_registry)
i += 1
end
soap_response.set_outparam(outparams)
soap_response.retval = Mapping.obj2soap(result[0], @mapping_registry)
else
soap_response.retval = Mapping.obj2soap(result, @mapping_registry)
end
soap_response
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
# Dispatch to defined method.
def dispatch(soap_method)
request_struct = Mapping.soap2obj(soap_method, @mapping_registry)
values = soap_method.collect { |key, value| request_struct[key] }
method = lookup(soap_method.elename, values)
unless method
raise RPCRoutingError.new(
"Method: #{ soap_method.elename } not supported.")
end
result = method.call(*values)
create_response(soap_method.elename, result)
end
# Method lookup
def lookup(qname, values)
name = fqname(qname)
# It may be necessary to check all part of method signature...
if @method.member?(name)
@receiver[name].method(@method_name[name].intern)
else
nil
end
end
def fqname(qname)
"#{ qname.namespace }:#{ qname.name }"
end
def options
opt = {}
opt[:default_encodingstyle] = @default_encodingstyle
if @allow_unqualified_element
opt[:allow_unqualified_element] = true
end
opt
end
end
end
end

36
lib/soap/rpc/rpc.rb Normal file
View file

@ -0,0 +1,36 @@
=begin
SOAP4R - RPC utility.
Copyright (C) 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
module SOAP
module RPC
ServerException = Mapping::MappedException
def self.defined_methods(obj)
if obj.is_a?(Module)
obj.methods - Module.methods
else
obj.methods - Kernel.instance_methods(true)
end
end
end
end

167
lib/soap/rpc/soaplet.rb Normal file
View file

@ -0,0 +1,167 @@
=begin
SOAP4R - SOAP handler servlet for WEBrick
Copyright (C) 2001, 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'webrick/httpservlet/abstract'
require 'webrick/httpstatus'
require 'soap/rpc/router'
require 'soap/streamHandler'
module SOAP
module RPC
class SOAPlet < WEBrick::HTTPServlet::AbstractServlet
public
attr_reader :app_scope_router
def initialize
@router_map = {}
@app_scope_router = ::SOAP::RPC::Router.new(self.class.name)
end
# Add servant klass whose object has request scope. A servant object is
# instanciated for each request.
#
# Bare in mind that servant klasses are distinguished by HTTP SOAPAction
# header in request. Client which calls request-scoped servant must have a
# SOAPAction header which is a namespace of the servant klass.
# I mean, use Driver#add_method_with_soapaction instead of Driver#add_method
# at client side.
#
def add_rpc_request_servant(klass, namespace, mapping_registry = nil)
router = RequestRouter.new(klass, namespace, mapping_registry)
add_router(namespace, router)
end
# Add servant object which has application scope.
def add_rpc_servant(obj, namespace)
router = @app_scope_router
SOAPlet.add_servant_to_router(router, obj, namespace)
add_router(namespace, router)
end
alias add_servant add_rpc_servant
###
## 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)
namespace = parse_soapaction(req.meta_vars['HTTP_SOAPACTION'])
router = lookup_router(namespace)
is_fault = false
charset = ::SOAP::StreamHandler.parse_media_type(req['content-type'])
begin
response_stream, is_fault = router.route(req.body, charset)
rescue Exception => e
response_stream = router.create_fault_response(e)
is_fault = true
end
res.body = response_stream
res['content-type'] = "text/xml; charset=\"#{charset}\""
if response_stream.is_a?(IO)
res.chunked = true
end
if is_fault
res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR
end
end
private
class RequestRouter < ::SOAP::RPC::Router
def initialize(klass, namespace, mapping_registry = nil)
super(namespace)
if mapping_registry
self.mapping_registry = mapping_registry
end
@klass = klass
@namespace = namespace
end
def route(soap_string)
obj = @klass.new
namespace = self.actor
router = ::SOAP::RPC::Router.new(@namespace)
SOAPlet.add_servant_to_router(router, obj, namespace)
router.route(soap_string)
end
end
def add_router(namespace, router)
@router_map[namespace] = router
end
def parse_soapaction(soapaction)
if /^"(.*)"$/ =~ soapaction
soapaction = $1
end
if soapaction.empty?
return nil
end
soapaction
end
def lookup_router(namespace)
if namespace
@router_map[namespace] || @app_scope_router
else
@app_scope_router
end
end
class << self
public
def add_servant_to_router(router, obj, namespace)
::SOAP::RPC.defined_methods(obj).each do |name|
add_servant_method_to_router(router, obj, namespace, name)
end
end
def add_servant_method_to_router(router, obj, namespace, name)
qname = XSD::QName.new(namespace, name)
soapaction = nil
method = obj.method(name)
param_def = ::SOAP::RPC::SOAPMethod.create_param_def(
(1..method.arity.abs).collect { |i| "p#{ i }" })
router.add_method(obj, qname, soapaction, name, param_def)
end
end
end
end
end

View file

@ -0,0 +1,116 @@
=begin
SOAP4R - WEBrick Server
Copyright (C) 2003 by NAKAMURA, Hiroshi
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'logger'
require 'soap/rpc/soaplet'
require 'soap/streamHandler'
# require 'webrick'
require 'webrick/compat.rb'
require 'webrick/version.rb'
require 'webrick/config.rb'
require 'webrick/log.rb'
require 'webrick/server.rb'
require 'webrick/utils.rb'
require 'webrick/accesslog'
# require 'webrick/htmlutils.rb'
require 'webrick/httputils.rb'
# require 'webrick/cookie.rb'
require 'webrick/httpversion.rb'
require 'webrick/httpstatus.rb'
require 'webrick/httprequest.rb'
require 'webrick/httpresponse.rb'
require 'webrick/httpserver.rb'
# require 'webrick/httpservlet.rb'
# require 'webrick/httpauth.rb'
module SOAP
module RPC
class StandaloneServer < Logger::Application
attr_reader :server
def initialize(app_name, namespace, host = "0.0.0.0", port = 8080)
super(app_name)
@logdev = Logger.new(STDERR)
@logdev.level = INFO
@namespace = namespace
@server = WEBrick::HTTPServer.new(
:BindAddress => host,
:Logger => logdev,
:AccessLog => [[logdev, WEBrick::AccessLog::COMBINED_LOG_FORMAT]],
:Port => port
)
@soaplet = ::SOAP::RPC::SOAPlet.new
on_init
@server.mount('/', @soaplet)
end
def on_init
# define extra methods in derived class.
end
def add_rpc_request_servant(klass, namespace = @namespace, mapping_registry = nil)
@soaplet.add_rpc_request_servant(klass, namespace, mapping_registry)
end
def add_rpc_servant(obj, namespace = @namespace)
@soaplet.add_rpc_servant(obj, namespace)
end
alias add_servant add_rpc_servant
def mapping_registry
@soaplet.app_scope_router.mapping_registry
end
def mapping_registry=(mapping_registry)
@soaplet.app_scope_router.mapping_registry = mapping_registry
end
def add_method(obj, name, *param)
add_method_as(obj, name, name, *param)
end
def add_method_as(obj, name, name_as, *param)
qname = XSD::QName.new(@namespace, name_as)
soapaction = nil
method = obj.method(name)
param_def = if param.size == 1 and param[0].is_a?(Array)
param[0]
elsif param.empty?
::SOAP::RPC::SOAPMethod.create_param_def(
(1..method.arity.abs).collect { |i| "p#{ i }" })
else
SOAP::RPC::SOAPMethod.create_param_def(param)
end
@soaplet.app_scope_router.add_method(obj, qname, soapaction, name, param_def)
end
private
def run
@server.start
end
end
end
end

112
lib/soap/soap.rb Normal file
View file

@ -0,0 +1,112 @@
=begin
SOAP4R - Base definitions.
Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'xsd/qname'
require 'xsd/charset'
module SOAP
Version = '1.5.0'
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)
EleHeaderName = XSD::QName.new(EnvelopeNamespace, EleHeader)
EleBodyName = XSD::QName.new(EnvelopeNamespace, EleBody)
EleFaultName = XSD::QName.new(EnvelopeNamespace, EleFault)
EleFaultStringName = XSD::QName.new(nil, EleFaultString)
EleFaultActorName = XSD::QName.new(nil, EleFaultActor)
EleFaultCodeName = XSD::QName.new(nil, EleFaultCode)
EleFaultDetailName = XSD::QName.new(nil, EleFaultDetail)
AttrEncodingStyleName = XSD::QName.new(EnvelopeNamespace, AttrEncodingStyle)
AttrRootName = XSD::QName.new(EncodingNamespace, AttrRoot)
AttrArrayTypeName = XSD::QName.new(EncodingNamespace, AttrArrayType)
AttrOffsetName = XSD::QName.new(EncodingNamespace, AttrOffset)
AttrPositionName = XSD::QName.new(EncodingNamespace, AttrPosition)
ValueArrayName = XSD::QName.new(EncodingNamespace, ValueArray)
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 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 && @faultstring.respond_to?('data')
str = @faultstring.data
end
str || '(No faultstring)'
end
end
end

188
lib/soap/streamHandler.rb Normal file
View file

@ -0,0 +1,188 @@
=begin
SOAP4R - Stream handler.
Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'soap/soap'
module SOAP
class StreamHandler
Client = begin
require 'http-access2'
if HTTPAccess2::VERSION < "2.0"
raise LoadError.new("http-access/2.0 or later is required.")
end
HTTPAccess2::Client
rescue LoadError
STDERR.puts "Loading http-access2 failed. Net/http is used." if $DEBUG
require 'soap/netHttpClient'
SOAP::NetHttpClient
end
RUBY_VERSION_STRING = "ruby #{ RUBY_VERSION } (#{ RUBY_RELEASE_DATE }) [#{ RUBY_PLATFORM }]"
%q$Id$ =~ /: (\S+),v (\S+)/
RCS_FILE, RCS_REVISION = $1, $2
class ConnectionData
attr_accessor :send_string
attr_accessor :send_contenttype
attr_accessor :receive_string
attr_accessor :receive_contenttype
def initialize
@send_string = nil
@send_contenttype = nil
@receive_string = nil
@receive_contenttype = nil
@bag = {}
end
def [](idx)
@bag[idx]
end
def []=(idx, value)
@bag[idx] = value
end
end
attr_accessor :endpoint_url
def initialize(endpoint_url)
@endpoint_url = endpoint_url
end
def self.parse_media_type(str)
if /^#{ MediaType }(?:\s*;\s*charset=([^"]+|"[^"]+"))?$/i !~ str
raise StreamError.new("Illegal media type.");
end
charset = $1
charset.gsub!(/"/, '') if charset
charset
end
def self.create_media_type(charset)
"#{ MediaType }; charset=#{ charset }"
end
end
class HTTPPostStreamHandler < StreamHandler
include SOAP
public
attr_accessor :wiredump_dev
attr_accessor :wiredump_file_base
attr_accessor :charset
NofRetry = 10 # [times]
ConnectTimeout = 20 # [sec]
SendTimeout = 60 # [sec]
ReceiveTimeout = 60 # [sec]
def initialize(endpoint_url, proxy = nil, charset = nil)
super(endpoint_url)
@proxy = proxy || ENV['http_proxy'] || ENV['HTTP_PROXY']
@charset = charset || XSD::Charset.charset_label($KCODE)
@wiredump_dev = nil # Set an IO to get wiredump.
@wiredump_file_base = nil
@client = Client.new(@proxy, "SOAP4R/#{ Version }")
@client.session_manager.connect_timeout = ConnectTimeout
@client.session_manager.send_timeout = SendTimeout
@client.session_manager.receive_timeout = ReceiveTimeout
end
def proxy=(proxy)
@proxy = proxy
@client.proxy = @proxy
end
def send(soap_string, soapaction = nil, charset = @charset)
send_post(soap_string, soapaction, charset)
end
def reset
@client.reset(@endpoint_url)
end
private
def send_post(soap_string, soapaction, charset)
data = ConnectionData.new
data.send_string = soap_string
data.send_contenttype = StreamHandler.create_media_type(charset)
wiredump_dev = if @wiredump_dev && @wiredump_dev.respond_to?("<<")
@wiredump_dev
else
nil
end
@client.debug_dev = wiredump_dev
if @wiredump_file_base
filename = @wiredump_file_base + '_request.xml'
f = File.open(filename, "w")
f << soap_string
f.close
end
extra = {}
extra['Content-Type'] = data.send_contenttype
extra['SOAPAction'] = "\"#{ soapaction }\""
wiredump_dev << "Wire dump:\n\n" if wiredump_dev
begin
res = @client.post(@endpoint_url, soap_string, extra)
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
data.receive_string = receive_string
data.receive_contenttype = res.contenttype
return data
end
CRLF = "\r\n"
end
end

490
lib/soap/wsdlDriver.rb Normal file
View file

@ -0,0 +1,490 @@
=begin
SOAP4R - SOAP WSDL driver
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/parser'
require 'wsdl/importer'
require 'xsd/qname'
require 'soap/element'
require 'soap/baseData'
require 'soap/streamHandler'
require 'soap/mapping'
require 'soap/mapping/wsdlRegistry'
require 'soap/rpc/rpc'
require 'soap/rpc/element'
require 'soap/processor'
require 'logger'
module SOAP
class WSDLDriverFactory
class FactoryError < StandardError; end
attr_reader :wsdl
def initialize(wsdl, logdev = nil)
@logdev = logdev
@wsdl = import(wsdl)
end
def create_driver(servicename = nil, portname = nil, opt = {})
service = if servicename
@wsdl.service(XSD::QName.new(@wsdl.targetnamespace, servicename))
else
@wsdl.services[0]
end
if service.nil?
raise FactoryError.new("Service #{ servicename } not found in WSDL.")
end
port = if portname
service.ports[XSD::QName.new(@wsdl.targetnamespace, portname)]
else
service.ports[0]
end
if port.nil?
raise FactoryError.new("Port #{ portname } not found in WSDL.")
end
if port.soap_address.nil?
raise FactoryError.new("soap:address element not found in WSDL.")
end
WSDLDriver.new(@wsdl, port, @logdev, opt)
end
# Backward compatibility.
alias createDriver create_driver
private
def import(location)
WSDL::Importer.import(location)
end
end
class WSDLDriver
class << self
def __attr_proxy(symbol, assignable = false)
name = symbol.to_s
module_eval <<-EOD
def #{name}
@servant.#{name}
end
EOD
if assignable
module_eval <<-EOD
def #{name}=(rhs)
@servant.#{name} = rhs
end
EOD
end
end
end
__attr_proxy :opt
__attr_proxy :logdev, true
__attr_proxy :mapping_registry, true # for RPC unmarshal
__attr_proxy :wsdl_mapping_registry, true # for RPC marshal
__attr_proxy :endpoint_url, true
__attr_proxy :wiredump_dev, true
__attr_proxy :wiredump_file_base, true
__attr_proxy :httpproxy, true
__attr_proxy :default_encodingstyle, true
__attr_proxy :allow_unqualified_element, true
__attr_proxy :generate_explicit_type, true
def reset_stream
@servant.reset_stream
end
# Backward compatibility.
alias generateEncodeType= generate_explicit_type=
class Servant__
include Logger::Severity
include SOAP
attr_reader :opt
attr_accessor :logdev
attr_accessor :mapping_registry
attr_accessor :wsdl_mapping_registry
attr_reader :endpoint_url
attr_reader :wiredump_dev
attr_reader :wiredump_file_base
attr_reader :httpproxy
attr_accessor :default_encodingstyle
attr_accessor :allow_unqualified_element
attr_accessor :generate_explicit_type
class Mapper
def initialize(elements, types)
@elements = elements
@types = types
end
def obj2ele(obj, name)
if ele = @elements[name]
_obj2ele(obj, ele)
elsif type = @types[name]
obj2type(obj, type)
else
raise RuntimeError.new("Cannot find name #{name} in schema.")
end
end
def ele2obj(ele, *arg)
raise NotImplementedError.new
end
private
def _obj2ele(obj, ele)
o = nil
if ele.type
if type = @types[ele.type]
o = obj2type(obj, type)
elsif type = TypeMap[ele.type]
o = base2soap(obj, type)
else
raise RuntimeError.new("Cannot find type #{ele.type}.")
end
o.elename = ele.name
elsif ele.local_complextype
o = SOAPElement.new(ele.name)
ele.local_complextype.each_element do |child_name, child_ele|
o.add(_obj2ele(find_attribute(obj, child_name.name), child_ele))
end
else
raise RuntimeError.new("Illegal schema?")
end
o
end
def obj2type(obj, type)
o = SOAPElement.new(type.name)
type.each_element do |child_name, child_ele|
o.add(_obj2ele(find_attribute(obj, child_name.name), child_ele))
end
o
end
def _ele2obj(ele)
raise NotImplementedError.new
end
def base2soap(obj, type)
soap_obj = nil
if type <= XSD::XSDString
soap_obj = type.new(XSD::Charset.is_ces(obj, $KCODE) ?
XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding) : obj)
else
soap_obj = type.new(obj)
end
soap_obj
end
def find_attribute(obj, attr_name)
if obj.respond_to?(attr_name)
obj.__send__(attr_name)
elsif obj.is_a?(Hash)
obj[attr_name] || obj[attr_name.intern]
else
obj.instance_eval("@#{ attr_name }")
end
end
end
def initialize(host, wsdl, port, logdev, opt)
@host = host
@wsdl = wsdl
@port = port
@logdev = logdev
@opt = opt.dup
@mapping_registry = nil # for rpc unmarshal
@wsdl_mapping_registry = nil # for rpc marshal
@endpoint_url = nil
@wiredump_dev = nil
@wiredump_file_base = nil
@httpproxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
@wsdl_elements = @wsdl.collect_elements
@wsdl_types = @wsdl.collect_complextypes
@rpc_decode_typemap = @wsdl_types + @wsdl.soap_rpc_complextypes(port.find_binding)
@wsdl_mapping_registry = Mapping::WSDLRegistry.new(@rpc_decode_typemap)
@doc_mapper = Mapper.new(@wsdl_elements, @wsdl_types)
@default_encodingstyle = EncodingNamespace
@allow_unqualified_element = true
@generate_explicit_type = false
create_handler
@operations = {}
# Convert a map which key is QName, to a Hash which key is String.
@port.inputoperation_map.each do |op_name, op_info|
@operations[op_name.name] = op_info
add_method_interface(op_info)
end
end
def endpoint_url=(endpoint_url)
@endpoint_url = endpoint_url
if @handler
@handler.endpoint_url = @endpoint_url
@handler.reset
end
log(DEBUG) { "endpoint_url=: set endpoint_url #{ @endpoint_url }." }
end
def wiredump_dev=(dev)
@wiredump_dev = dev
if @handler
@handler.wiredump_dev = @wiredump_dev
@handler.reset
end
end
def wiredump_file_base=(base)
@wiredump_file_base = base
end
def httpproxy=(httpproxy)
@httpproxy = httpproxy
if @handler
@handler.proxy = @httpproxy
@handler.reset
end
log(DEBUG) { "httpproxy=: set httpproxy #{ @httpproxy }." }
end
def reset_stream
@handler.reset
end
def rpc_send(method_name, *params)
log(INFO) { "call: calling method '#{ method_name }'." }
log(DEBUG) { "call: parameters '#{ params.inspect }'." }
op_info = @operations[method_name]
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.optype_name)
method.elename = op_info.op_name
method.type = XSD::QName.new # Request should not be typed.
req_header = nil
req_body = SOAPBody.new(method)
if @wiredump_file_base
@handler.wiredump_file_base = @wiredump_file_base + '_' << method_name
end
begin
opt = create_options
opt[:decode_typemap] = @rpc_decode_typemap
res_header, res_body = invoke(req_header, req_body, op_info, opt)
if res_body.fault
raise SOAP::FaultError.new(res_body.fault)
end
rescue SOAP::FaultError => e
Mapping.fault2exception(e)
end
ret = res_body.response ?
Mapping.soap2obj(res_body.response, @mapping_registry) : nil
if res_body.outparams
outparams = res_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)
log(INFO) { "document_send: sending document '#{ name }'." }
op_info = @operations[name]
req_header = header_from_obj(header_obj, op_info)
req_body = body_from_obj(body_obj, op_info)
opt = create_options
res_header, res_body = invoke(req_header, req_body, op_info, opt)
if res_body.fault
raise SOAP::FaultError.new(res_body.fault)
end
res_body_obj = res_body.response ?
Mapping.soap2obj(res_body.response, @mapping_registry) : nil
return res_header, res_body_obj
end
private
def create_handler
endpoint_url = @endpoint_url || @port.soap_address.location
@handler = HTTPPostStreamHandler.new(endpoint_url, @httpproxy,
XSD::Charset.encoding_label)
@handler.wiredump_dev = @wiredump_dev
end
def create_method_obj(names, params)
o = Object.new
for idx in 0 ... params.length
o.instance_eval("@#{ names[idx] } = params[idx]")
end
o
end
def invoke(req_header, req_body, op_info, opt)
send_string = Processor.marshal(req_header, req_body, opt)
log(DEBUG) { "invoke: sending string #{ send_string }" }
data = @handler.send(send_string, op_info.soapaction)
log(DEBUG) { "invoke: received string #{ data.receive_string }" }
if data.receive_string.empty?
return nil, nil
end
res_charset = StreamHandler.parse_media_type(data.receive_contenttype)
opt[:charset] = res_charset
res_header, res_body = Processor.unmarshal(data.receive_string, opt)
return res_header, res_body
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.")
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 = obj[part.elename.name]
ele = headeritem_from_obj(child, part.element || part.eletype)
header.add(ele)
end
header
end
end
def headeritem_from_obj(obj, name)
if obj.nil?
SOAPElement.new(name)
elsif obj.is_a?(SOAPHeaderItem)
obj
else
@doc_mapper.obj2ele(obj, 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 = obj[part.elename.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
@doc_mapper.obj2ele(obj, name)
end
end
def add_method_interface(op_info)
case op_info.style
when :document
add_document_method_interface(op_info.op_name.name)
when :rpc
parts_names = op_info.bodyparts.collect { |part| part.name }
add_rpc_method_interface(op_info.op_name.name, parts_names)
else
raise RuntimeError.new("Unknown style: #{op_info.style}")
end
end
def add_document_method_interface(name)
@host.instance_eval <<-EOS
def #{ name }(headers, body)
@servant.document_send(#{ name.dump }, headers, body)
end
EOS
end
def add_rpc_method_interface(name, parts_names)
i = 0
param_names = parts_names.collect { |orgname| i += 1; "arg#{ i }" }
callparam_str = (param_names.collect { |pname| ", " + pname }).join
@host.instance_eval <<-EOS
def #{ name }(#{ param_names.join(", ") })
@servant.rpc_send(#{ name.dump }#{ callparam_str })
end
EOS
end
def create_options
opt = @opt.dup
opt[:default_encodingstyle] = @default_encodingstyle
opt[:allow_unqualified_element] = @allow_unqualified_element
opt[:generate_explicit_type] = @generate_explicit_type
opt
end
def log(sev)
@logdev.add(sev, nil, self.class) { yield } if @logdev
end
end
def initialize(wsdl, port, logdev, opt)
@servant = Servant__.new(self, wsdl, port, logdev, opt)
end
end
end

76
lib/wsdl/binding.rb Normal file
View file

@ -0,0 +1,76 @@
=begin
WSDL4R - WSDL binding definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
require 'xsd/namedelements'
module WSDL
class Binding < Info
attr_reader :name # required
attr_reader :type # required
attr_reader :operations
attr_reader :soapbinding
def initialize
super
@name = nil
@type = nil
@operations = XSD::NamedElements.new
@soapbinding = nil
end
def targetnamespace
parent.targetnamespace
end
def parse_element(element)
case element
when OperationName
o = OperationBinding.new
@operations << o
o
when SOAPBindingName
o = WSDL::SOAP::Binding.new
@soapbinding = o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(targetnamespace, value)
when TypeAttrName
@type = value
else
nil
end
end
end
end

73
lib/wsdl/data.rb Normal file
View file

@ -0,0 +1,73 @@
=begin
WSDL4R - WSDL data definitions.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/documentation'
require 'wsdl/definitions'
require 'wsdl/types'
require 'wsdl/message'
require 'wsdl/part'
require 'wsdl/portType'
require 'wsdl/operation'
require 'wsdl/param'
require 'wsdl/binding'
require 'wsdl/operationBinding'
require 'wsdl/service'
require 'wsdl/port'
require 'wsdl/import'
module WSDL
BindingName = XSD::QName.new(Namespace, 'binding')
DefinitionsName = XSD::QName.new(Namespace, 'definitions')
DocumentationName = XSD::QName.new(Namespace, 'documentation')
FaultName = XSD::QName.new(Namespace, 'fault')
ImportName = XSD::QName.new(Namespace, 'import')
InputName = XSD::QName.new(Namespace, 'input')
MessageName = XSD::QName.new(Namespace, 'message')
OperationName = XSD::QName.new(Namespace, 'operation')
OutputName = XSD::QName.new(Namespace, 'output')
PartName = XSD::QName.new(Namespace, 'part')
PortName = XSD::QName.new(Namespace, 'port')
PortTypeName = XSD::QName.new(Namespace, 'portType')
ServiceName = XSD::QName.new(Namespace, 'service')
TypesName = XSD::QName.new(Namespace, 'types')
SchemaName = XSD::QName.new(XSD::Namespace, 'schema')
SOAPAddressName = XSD::QName.new(SOAPBindingNamespace, 'address')
SOAPBindingName = XSD::QName.new(SOAPBindingNamespace, 'binding')
SOAPHeaderName = XSD::QName.new(SOAPBindingNamespace, 'header')
SOAPBodyName = XSD::QName.new(SOAPBindingNamespace, 'body')
SOAPFaultName = XSD::QName.new(SOAPBindingNamespace, 'fault')
SOAPOperationName = XSD::QName.new(SOAPBindingNamespace, 'operation')
BindingAttrName = XSD::QName.new(nil, 'binding')
ElementAttrName = XSD::QName.new(nil, 'element')
LocationAttrName = XSD::QName.new(nil, 'location')
MessageAttrName = XSD::QName.new(nil, 'message')
NameAttrName = XSD::QName.new(nil, 'name')
NamespaceAttrName = XSD::QName.new(nil, 'namespace')
ParameterOrderAttrName = XSD::QName.new(nil, 'parameterOrder')
TargetNamespaceAttrName = XSD::QName.new(nil, 'targetNamespace')
TypeAttrName = XSD::QName.new(nil, 'type')
end

233
lib/wsdl/definitions.rb Normal file
View file

@ -0,0 +1,233 @@
=begin
WSDL4R - WSDL definitions.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
require 'xsd/namedelements'
module WSDL
class Definitions < Info
attr_reader :name
attr_reader :targetnamespace
attr_reader :imports
# Overrides Info#root
def root
@root
end
def root=(root)
@root = root
end
def initialize
super
@name = nil
@targetnamespace = nil
@types = nil
@imports = []
@messages = XSD::NamedElements.new
@porttypes = XSD::NamedElements.new
@bindings = XSD::NamedElements.new
@services = XSD::NamedElements.new
@anontypes = XSD::NamedElements.new
@root = self
end
def targetnamespace=(targetnamespace)
@targetnamespace = targetnamespace
if @name
@name = XSD::QName.new(@targetnamespace, @name.name)
end
end
def collect_elements
result = XSD::NamedElements.new
if @types
@types.schemas.each do |schema|
result.concat(schema.elements)
end
end
@imports.each do |import|
result.concat(import.content.collect_elements)
end
result
end
def collect_complextypes
result = @anontypes.dup
if @types
@types.schemas.each do |schema|
result.concat(schema.complextypes)
end
end
@imports.each do |import|
result.concat(import.content.collect_complextypes)
end
result
end
def add_type(complextype)
@anontypes << complextype
end
def messages
result = @messages.dup
@imports.each do |import|
result.concat(import.content.messages) if self.class === import.content
end
result
end
def porttypes
result = @porttypes.dup
@imports.each do |import|
result.concat(import.content.porttypes) if self.class === import.content
end
result
end
def bindings
result = @bindings.dup
@imports.each do |import|
result.concat(import.content.bindings) if self.class === import.content
end
result
end
def services
result = @services.dup
@imports.each do |import|
result.concat(import.content.services) if self.class === import.content
end
result
end
def message(name)
message = @messages[name]
return message if message
@imports.each do |import|
message = import.content.message(name) if self.class === import.content
return message if message
end
nil
end
def porttype(name)
porttype = @porttypes[name]
return porttype if porttype
@imports.each do |import|
porttype = import.content.porttype(name) if self.class === import.content
return porttype if porttype
end
nil
end
def binding(name)
binding = @bindings[name]
return binding if binding
@imports.each do |import|
binding = import.content.binding(name) if self.class === import.content
return binding if binding
end
nil
end
def service(name)
service = @services[name]
return service if service
@imports.each do |import|
service = import.content.service(name) if self.class === import.content
return service if service
end
nil
end
def porttype_binding(name)
binding = @bindings.find { |item| item.type == name }
return binding if binding
@imports.each do |import|
binding = import.content.porttype_binding(name) if self.class === import.content
return binding if binding
end
nil
end
def parse_element(element)
case element
when ImportName
o = Import.new
@imports << o
o
when TypesName
o = Types.new
@types = o
o
when MessageName
o = Message.new
@messages << o
o
when PortTypeName
o = PortType.new
@porttypes << o
o
when BindingName
o = Binding.new
@bindings << o
o
when ServiceName
o = Service.new
@services << o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(@targetnamespace, value)
when TargetNamespaceAttrName
self.targetnamespace = value
else
nil
end
end
def self.parse_element(element)
if element == DefinitionsName
Definitions.new
else
nil
end
end
private
end
end

43
lib/wsdl/documentation.rb Normal file
View file

@ -0,0 +1,43 @@
=begin
WSDL4R - WSDL SOAP documentation element.
Copyright (C) 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
class Documentation < Info
def initialize
super
end
def parse_element(element)
# Accepts any element.
self
end
def parse_attr(attr, value)
# Accepts any attribute.
true
end
end
end

81
lib/wsdl/import.rb Normal file
View file

@ -0,0 +1,81 @@
=begin
WSDL4R - WSDL import definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
require 'wsdl/importer'
module WSDL
class Import < Info
attr_reader :namespace
attr_reader :location
attr_reader :content
def initialize
super
@namespace = nil
@location = nil
@content = nil
@web_client = nil
end
def parse_element(element)
case element
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NamespaceAttrName
@namespace = value
if @content
@content.targetnamespace = @namespace
end
@namespace
when LocationAttrName
@location = value
@content = import(@location)
if @content.is_a?(Definitions)
@content.root = root
if @namespace
@content.targetnamespace = @namespace
end
end
@location
else
nil
end
end
private
def import(location)
Importer.import(location)
end
end
end

75
lib/wsdl/importer.rb Normal file
View file

@ -0,0 +1,75 @@
=begin
WSDL4R - WSDL importer library.
Copyright (C) 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
class Importer
def self.import(location)
new.import(location)
end
def initialize
@web_client = nil
end
def import(location)
content = nil
if FileTest.exist?(location)
content = File.open(location).read
else
proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
content = web_client.new(proxy, "WSDL4R").get_content(location)
end
opt = {} # charset?
begin
WSDL::Parser.new(opt).parse(content)
rescue WSDL::Parser::ParseError => orgexcn
begin
require 'wsdl/xmlSchema/parser'
WSDL::XMLSchema::Parser.new(opt).parse(content)
rescue
raise orgexcn
end
end
end
private
def web_client
@web_client ||= begin
require 'http-access2'
if HTTPAccess2::VERSION < "2.0"
raise LoadError.new("http-access/2.0 or later is required.")
end
HTTPAccess2::Client
rescue LoadError
STDERR.puts "Loading http-access2 failed. Net/http is used." if $DEBUG
require 'soap/netHttpClient'
::SOAP::NetHttpClient
end
@web_client
end
end
end

44
lib/wsdl/info.rb Normal file
View file

@ -0,0 +1,44 @@
=begin
WSDL4R - WSDL information base.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
module WSDL
class Info
attr_accessor :parent
attr_accessor :id
def initialize
@parent = nil
@id = nil
end
def root
@parent.root
end
def parse_element(element); end # abstract
def parse_attr(attr, value); end # abstract
def parse_epilogue; end # abstract
end
end

65
lib/wsdl/message.rb Normal file
View file

@ -0,0 +1,65 @@
=begin
WSDL4R - WSDL message definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
class Message < Info
attr_reader :name # required
attr_reader :parts
def initialize
super
@name = nil
@parts = []
end
def targetnamespace
parent.targetnamespace
end
def parse_element(element)
case element
when PartName
o = Part.new
@parts << o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(parent.targetnamespace, value)
else
nil
end
end
end
end

144
lib/wsdl/operation.rb Normal file
View file

@ -0,0 +1,144 @@
=begin
WSDL4R - WSDL operation definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
class Operation < Info
class NameInfo
attr_reader :op_name
attr_reader :optype_name
attr_reader :parts
def initialize(op_name, optype_name, parts)
@op_name = op_name
@optype_name = optype_name
@parts = parts
end
end
attr_reader :name # required
attr_reader :parameter_order # optional
attr_reader :input
attr_reader :output
attr_reader :fault
attr_reader :type # required
def initialize
super
@name = nil
@type = nil
@parameter_order = nil
@input = nil
@output = nil
@fault = nil
end
def targetnamespace
parent.targetnamespace
end
def input_info
op_name = @name
optype_name = XSD::QName.new(targetnamespace, input.name ? input.name.name : @name.name)
NameInfo.new(op_name, optype_name, inputparts)
end
def output_info
op_name = @name
optype_name = XSD::QName.new(targetnamespace, output.name ? output.name.name : @name.name)
NameInfo.new(op_name, optype_name, outputparts)
end
def inputparts
sort_parts(input.find_message.parts)
end
def outputparts
sort_parts(output.find_message.parts)
end
def faultparts
sort_parts(fault.find_message.parts)
end
def outputname
XSD::QName.new(targetnamespace,
output.name ? output.name.name : @name.name + 'Response')
end
def parse_element(element)
case element
when InputName
o = Param.new
@input = o
o
when OutputName
o = Param.new
@output = o
o
when FaultName
o = Param.new
@fault = o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(targetnamespace, value)
when TypeAttrName
@type = value
when ParameterOrderAttrName
@parameter_order = value.split(/\s+/)
else
nil
end
end
private
def sort_parts(parts)
return parts.dup unless parameter_order
result = []
parameter_order.each do |orderitem|
if (ele = parts.find { |part| part.name == orderitem })
result << ele
end
end
if result.length == 0
return parts.dup
end
if parts.length != result.length
raise RuntimeError.new("Incomplete prarmeterOrder list.")
end
result
end
end
end

View file

@ -0,0 +1,91 @@
=begin
WSDL4R - WSDL bound operation definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
class OperationBinding < Info
attr_reader :name # required
attr_reader :input
attr_reader :output
attr_reader :fault
attr_reader :soapoperation
def initialize
super
@name = nil
@input = nil
@output = nil
@fault = nil
@soapoperation = nil
end
def targetnamespace
parent.targetnamespace
end
def porttype
root.porttype(parent.type)
end
def find_operation
porttype.operations[@name]
end
def parse_element(element)
case element
when InputName
o = Param.new
@input = o
o
when OutputName
o = Param.new
@output = o
o
when FaultName
o = Param.new
@fault = o
o
when SOAPOperationName
o = WSDL::SOAP::Operation.new
@soapoperation = o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(targetnamespace, value)
else
nil
end
end
end
end

85
lib/wsdl/param.rb Normal file
View file

@ -0,0 +1,85 @@
=begin
WSDL4R - WSDL param definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
class Param < Info
attr_reader :message # required
attr_reader :name # optional but required for fault.
attr_reader :soapbody
attr_reader :soapheader
attr_reader :soapfault
def initialize
super
@message = nil
@name = nil
@soapbody = nil
@soapheader = []
@soapfault = nil
end
def targetnamespace
parent.targetnamespace
end
def find_message
root.message(@message)
end
def parse_element(element)
case element
when SOAPBodyName
o = WSDL::SOAP::Body.new
@soapbody = o
o
when SOAPHeaderName
o = WSDL::SOAP::Header.new
@soapheader << o
o
when SOAPFaultName
o = WSDL::SOAP::Fault.new
@soap_fault = o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when MessageAttrName
@message = value
when NameAttrName
@name = XSD::QName.new(targetnamespace, value)
else
nil
end
end
end
end

170
lib/wsdl/parser.rb Normal file
View file

@ -0,0 +1,170 @@
=begin
WSDL4R - WSDL XML Instance parser library.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'xsd/qname'
require 'xsd/ns'
require 'xsd/charset'
require 'xsd/datatypes'
require 'xsd/xmlparser'
require 'wsdl/wsdl'
require 'wsdl/data'
require 'wsdl/xmlSchema/data'
require 'wsdl/soap/data'
module WSDL
class Parser
include WSDL
class ParseError < Error; end
class FormatDecodeError < ParseError; end
class UnknownElementError < FormatDecodeError; end
class UnknownAttributeError < FormatDecodeError; end
class UnexpectedElementError < FormatDecodeError; end
class ElementConstraintError < FormatDecodeError; end
class AttributeConstraintError < FormatDecodeError; end
private
class ParseFrame
attr_reader :ns
attr_reader :name
attr_accessor :node
private
def initialize(ns, name, node)
@ns = ns
@name = name
@node = node
end
end
public
def initialize(opt = {})
@parser = XSD::XMLParser.create_parser(self, opt)
@parsestack = nil
@lastnode = nil
end
def parse(string_or_readable)
@parsestack = []
@lastnode = nil
@textbuf = ''
@parser.do_parse(string_or_readable)
@lastnode
end
def charset
@parser.charset
end
def start_element(name, attrs)
lastframe = @parsestack.last
ns = parent = nil
if lastframe
ns = lastframe.ns.clone_ns
parent = lastframe.node
else
ns = XSD::NS.new
parent = nil
end
attrs = XSD::XMLParser.filter_ns(ns, attrs)
node = decode_tag(ns, name, attrs, parent)
@parsestack << ParseFrame.new(ns, name, node)
end
def characters(text)
lastframe = @parsestack.last
if lastframe
# Need not to be cloned because character does not have attr.
ns = lastframe.ns
decode_text(ns, text)
else
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)
@lastnode = lastframe.node
end
private
def decode_tag(ns, name, attrs, parent)
o = nil
element = ns.parse(name)
if !parent
if element == DefinitionsName
o = Definitions.parse_element(element)
else
raise UnknownElementError.new("Unknown element #{ element }.")
end
else
o = parent.parse_element(element)
unless o
STDERR.puts("Unknown element #{ element }.")
o = Documentation.new # which accepts any element.
end
o.parent = parent
end
attrs.each do |key, value|
attr = unless /:/ =~ key
XSD::QName.new(nil, key)
else
ns.parse(key)
end
value_ele = if /:/ !~ value
value
elsif /^http:\/\// =~ value # ToDo: ugly.
value
else
begin
ns.parse(value)
rescue
value
end
end
unless o.parse_attr(attr, value_ele)
STDERR.puts("Unknown attr #{ attr }.")
# raise UnknownAttributeError.new("Unknown attr #{ attr }.")
end
end
o
end
def decode_tag_end(ns, node)
node.parse_epilogue
end
def decode_text(ns, text)
@textbuf << text
end
end
end

63
lib/wsdl/part.rb Normal file
View file

@ -0,0 +1,63 @@
=begin
WSDL4R - WSDL part definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
class Part < Info
attr_reader :name # required
attr_reader :element # optional
attr_reader :type # optional
def initialize
super
@name = nil
@element = nil
@type = nil
end
def parse_element(element)
case element
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = value
when ElementAttrName
@element = value
when TypeAttrName
@type = value
else
nil
end
end
end
end

95
lib/wsdl/port.rb Normal file
View file

@ -0,0 +1,95 @@
=begin
WSDL4R - WSDL port definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
class Port < Info
attr_reader :name # required
attr_reader :binding # required
attr_reader :soap_address
def initialize
super
@name = nil
@binding = nil
@soap_address = nil
end
def targetnamespace
parent.targetnamespace
end
def porttype
root.porttype(find_binding.type)
end
def find_binding
root.binding(@binding)
end
def inputoperation_map
result = {}
find_binding.operations.each do |op_bind|
op_info = op_bind.soapoperation.input_info
result[op_info.op_name] = op_info
end
result
end
def outputoperation_map
result = {}
find_binding.operations.each do |op_bind|
op_info = op_bind.soapoperation.output_info
result[op_info.op_name] = op_info
end
result
end
def parse_element(element)
case element
when SOAPAddressName
o = WSDL::SOAP::Address.new
@soap_address = o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(targetnamespace, value)
when BindingAttrName
@binding = value
else
nil
end
end
end
end

83
lib/wsdl/portType.rb Normal file
View file

@ -0,0 +1,83 @@
=begin
WSDL4R - WSDL portType definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
require 'xsd/namedelements'
module WSDL
class PortType < Info
attr_reader :name # required
attr_reader :operations
def targetnamespace
parent.targetnamespace
end
def initialize
super
@name = nil
@operations = XSD::NamedElements.new
end
def find_binding
root.bindings.find { |item| item.type == @name }
end
def locations
bind_name = find_binding.name
result = []
root.services.each do |service|
service.ports.each do |port|
if port.binding == bind_name
result << port.soap_address.location if port.soap_address
end
end
end
result
end
def parse_element(element)
case element
when OperationName
o = Operation.new
@operations << o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(targetnamespace, value)
else
nil
end
end
end
end

72
lib/wsdl/service.rb Normal file
View file

@ -0,0 +1,72 @@
=begin
WSDL4R - WSDL service definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
require 'xsd/namedelements'
module WSDL
class Service < Info
attr_reader :name # required
attr_reader :ports
attr_reader :soap_address
def initialize
super
@name = nil
@ports = XSD::NamedElements.new
@soap_address = nil
end
def targetnamespace
parent.targetnamespace
end
def parse_element(element)
case element
when PortName
o = Port.new
@ports << o
o
when SOAPAddressName
o = WSDL::SOAP::Address.new
@soap_address = o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(targetnamespace, value)
else
nil
end
end
end
end

51
lib/wsdl/soap/address.rb Normal file
View file

@ -0,0 +1,51 @@
=begin
WSDL4R - WSDL SOAP address definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module SOAP
class Address < Info
attr_reader :location
def initialize
super
@location = nil
end
def parse_element(element)
nil
end
def parse_attr(attr, value)
case attr
when LocationAttrName
@location = value
else
nil
end
end
end
end
end

59
lib/wsdl/soap/binding.rb Normal file
View file

@ -0,0 +1,59 @@
=begin
WSDL4R - WSDL SOAP binding definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module SOAP
class Binding < Info
attr_reader :style
attr_reader :transport
def initialize
super
@style = nil
@transport = nil
end
def parse_element(element)
nil
end
def parse_attr(attr, value)
case attr
when StyleAttrName
if ["document", "rpc"].include?(value)
@style = value.intern
else
raise AttributeConstraintError.new("Unexpected value #{ value }.")
end
when TransportAttrName
@transport = value
else
nil
end
end
end
end
end

63
lib/wsdl/soap/body.rb Normal file
View file

@ -0,0 +1,63 @@
=begin
WSDL4R - WSDL SOAP body definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module SOAP
class Body < Info
attr_reader :parts
attr_reader :use # required
attr_reader :encodingstyle
attr_reader :namespace
def initialize
super
@parts = nil
@use = nil
@encodingstyle = nil
@namespace = nil
end
def parse_element(element)
nil
end
def parse_attr(attr, value)
case attr
when PartsAttrName
@parts = value
when UseAttrName
@use = value
when EncodingStyleAttrName
@encodingstyle = value
when NamespaceAttrName
@namespace = value
else
nil
end
end
end
end
end

View file

@ -0,0 +1,96 @@
=begin
WSDL4R - SOAP complexType definition for WSDL.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/xmlSchema/complexType'
module WSDL
module XMLSchema
class ComplexType < Info
def compoundtype
@compoundtype ||= check_type
end
def check_type
if content
:TYPE_STRUCT
elsif complexcontent and complexcontent.base == ::SOAP::ValueArrayName
:TYPE_ARRAY
else
raise NotImplementedError.new("Unknown kind of complexType.")
end
end
def child_type(name = nil)
case compoundtype
when :TYPE_STRUCT
if ele = find_element(name)
ele.type
elsif ele = find_element_by_name(name.name)
ele.type
else
nil
end
when :TYPE_ARRAY
@contenttype ||= content_arytype
end
end
def child_defined_complextype(name)
unless compoundtype == :TYPE_STRUCT
raise RuntimeError.new("Assert: not for struct")
end
unless ele = find_element(name)
if name.namespace.nil?
ele = find_element_by_name(name.name)
end
end
unless ele
raise RuntimeError.new("Cannot find #{name} as a children of #{@name}.")
end
ele.local_complextype
end
def find_arytype
complexcontent.attributes.each do |attribute|
if attribute.ref == ::SOAP::AttrArrayTypeName
return attribute.arytype
end
end
nil
end
private
def content_arytype
unless compoundtype == :TYPE_ARRAY
raise RuntimeError.new("Assert: not for array")
end
arytype = find_arytype
ns = arytype.namespace
name = arytype.name.sub(/\[(?:,)*\]$/, '')
XSD::QName.new(ns, name)
end
end
end
end

52
lib/wsdl/soap/data.rb Normal file
View file

@ -0,0 +1,52 @@
=begin
WSDL4R - WSDL SOAP binding data definitions.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'xsd/qname'
require 'wsdl/soap/definitions'
require 'wsdl/soap/binding'
require 'wsdl/soap/operation'
require 'wsdl/soap/body'
require 'wsdl/soap/header'
require 'wsdl/soap/headerfault'
require 'wsdl/soap/fault'
require 'wsdl/soap/address'
require 'wsdl/soap/complexType'
module WSDL
module SOAP
HeaderFaultName = XSD::QName.new(SOAPBindingNamespace, 'headerfault')
LocationAttrName = XSD::QName.new(nil, 'location')
StyleAttrName = XSD::QName.new(nil, 'style')
TransportAttrName = XSD::QName.new(nil, 'transport')
UseAttrName = XSD::QName.new(nil, 'use')
PartsAttrName = XSD::QName.new(nil, 'parts')
PartAttrName = XSD::QName.new(nil, 'part')
NameAttrName = XSD::QName.new(nil, 'name')
MessageAttrName = XSD::QName.new(nil, 'message')
EncodingStyleAttrName = XSD::QName.new(nil, 'encodingStyle')
NamespaceAttrName = XSD::QName.new(nil, 'namespace')
SOAPActionAttrName = XSD::QName.new(nil, 'soapAction')
end
end

View file

@ -0,0 +1,130 @@
=begin
WSDL4R - WSDL additional definitions for SOAP.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
require 'xsd/namedelements'
require 'soap/mapping'
module WSDL
class Definitions < Info
def soap_rpc_complextypes(binding)
types = rpc_operation_complextypes(binding)
types << array_complextype
types << fault_complextype
types << exception_complextype
types
end
private
def rpc_operation_complextypes(binding)
types = XSD::NamedElements.new
binding.operations.each do |op_bind|
if op_bind_rpc?(op_bind)
operation = op_bind.find_operation
if op_bind.input
type = XMLSchema::ComplexType.new(operation_input_name(operation))
message = messages[operation.input.message]
type.sequence_elements = elements_from_message(message)
types << type
end
if op_bind.output
type = XMLSchema::ComplexType.new(operation_output_name(operation))
message = messages[operation.output.message]
type.sequence_elements = elements_from_message(message)
types << type
end
end
end
types
end
def operation_input_name(operation)
operation.input.name || operation.name
end
def operation_output_name(operation)
operation.output.name ||
XSD::QName.new(operation.name.namespace, operation.name.name + "Response")
end
def op_bind_rpc?(op_bind)
op_bind.soapoperation and op_bind.soapoperation.operation_style == :rpc
end
def elements_from_message(message)
message.parts.collect { |part|
qname = XSD::QName.new(nil, part.name)
XMLSchema::Element.new(qname, part.type)
}
end
def array_complextype
type = XMLSchema::ComplexType.new(::SOAP::ValueArrayName)
type.complexcontent = XMLSchema::ComplexContent.new
type.complexcontent.base = ::SOAP::ValueArrayName
attr = XMLSchema::Attribute.new
attr.ref = ::SOAP::AttrArrayTypeName
anytype = XSD::AnyTypeName.dup
anytype.name += '[]'
attr.arytype = anytype
type.complexcontent.attributes << attr
type
end
=begin
<xs:complexType name="Fault" final="extension">
<xs:sequence>
<xs:element name="faultcode" type="xs:QName" />
<xs:element name="faultstring" type="xs:string" />
<xs:element name="faultactor" type="xs:anyURI" minOccurs="0" />
<xs:element name="detail" type="tns:detail" minOccurs="0" />
</xs:sequence>
</xs:complexType>
=end
def fault_complextype
type = XMLSchema::ComplexType.new(::SOAP::EleFaultName)
faultcode = XMLSchema::Element.new(::SOAP::EleFaultCodeName, XSD::XSDQName::Type)
faultstring = XMLSchema::Element.new(::SOAP::EleFaultStringName, XSD::XSDString::Type)
faultactor = XMLSchema::Element.new(::SOAP::EleFaultActorName, XSD::XSDAnyURI::Type)
faultactor.minoccurs = 0
detail = XMLSchema::Element.new(::SOAP::EleFaultDetailName, XSD::AnyTypeName)
detail.minoccurs = 0
type.all_elements = [faultcode, faultstring, faultactor, detail]
type.final = 'extension'
type
end
def exception_complextype
type = XMLSchema::ComplexType.new(XSD::QName.new(
::SOAP::Mapping::RubyCustomTypeNamespace, 'SOAPException'))
excn_name = XMLSchema::Element.new(XSD::QName.new(nil, 'exceptionTypeName'), XSD::XSDString::Type)
cause = XMLSchema::Element.new(XSD::QName.new(nil, 'cause'), XSD::AnyTypeName)
backtrace = XMLSchema::Element.new(XSD::QName.new(nil, 'backtrace'), ::SOAP::ValueArrayName)
message = XMLSchema::Element.new(XSD::QName.new(nil, 'message'), XSD::XSDString::Type)
type.all_elements = [excn_name, cause, backtrace, message]
type
end
end
end

63
lib/wsdl/soap/fault.rb Normal file
View file

@ -0,0 +1,63 @@
=begin
WSDL4R - WSDL SOAP body definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module SOAP
class Fault < Info
attr_reader :name # required
attr_reader :use # required
attr_reader :encodingstyle
attr_reader :namespace
def initialize
super
@name = nil
@use = nil
@encodingstyle = nil
@namespace = nil
end
def parse_element(element)
nil
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = value
when UseAttrName
@use = value
when EncodingStyleAttrName
@encodingstyle = value
when NamespaceAttrName
@namespace = value
else
nil
end
end
end
end
end

90
lib/wsdl/soap/header.rb Normal file
View file

@ -0,0 +1,90 @@
=begin
WSDL4R - WSDL SOAP body definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module SOAP
class Header < Info
attr_reader :headerfault
attr_reader :message # required
attr_reader :part # required
attr_reader :use # required
attr_reader :encodingstyle
attr_reader :namespace
def initialize
super
@message = nil
@part = nil
@use = nil
@encodingstyle = nil
@namespace = nil
@headerfault = nil
end
def find_message
root.message(@message)
end
def find_part
find_message.parts.each do |part|
if part.name == @part
return part
end
end
nil
end
def parse_element(element)
case element
when HeaderFaultName
o = WSDL::SOAP::HeaderFault.new
@headerfault = o
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when MessageAttrName
@message = value
when PartAttrName
@part = value
when UseAttrName
@use = value
when EncodingStyleAttrName
@encodingstyle = value
when NamespaceAttrName
@namespace = value
else
nil
end
end
end
end
end

View file

@ -0,0 +1,67 @@
=begin
WSDL4R - WSDL SOAP body definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module SOAP
class HeaderFault < Info
attr_reader :message # required
attr_reader :part # required
attr_reader :use # required
attr_reader :encodingstyle
attr_reader :namespace
def initialize
super
@message = nil
@part = nil
@use = nil
@encodingstyle = nil
@namespace = nil
end
def parse_element(element)
nil
end
def parse_attr(attr, value)
case attr
when MessageAttrName
@message = value
when PartAttrName
@part = value
when UseAttrName
@use = value
when EncodingStyleAttrName
@encodingstyle = value
when NamespaceAttrName
@namespace = value
else
nil
end
end
end
end
end

131
lib/wsdl/soap/operation.rb Normal file
View file

@ -0,0 +1,131 @@
=begin
WSDL4R - WSDL SOAP operation definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module SOAP
class Operation < Info
class OperationInfo
attr_reader :style
attr_reader :op_name
attr_reader :optype_name
attr_reader :headerparts
attr_reader :bodyparts
attr_reader :faultpart
attr_reader :soapaction
def initialize(style, op_name, optype_name, headerparts, bodyparts, faultpart, soapaction)
@style = style
@op_name = op_name
@optype_name = optype_name
@headerparts = headerparts
@bodyparts = bodyparts
@faultpart = faultpart
@soapaction = soapaction
end
end
attr_reader :soapaction
attr_reader :style
def initialize
super
@soapaction = nil
@style = nil
end
def parse_element(element)
nil
end
def parse_attr(attr, value)
case attr
when StyleAttrName
if ["document", "rpc"].include?(value)
@style = value.intern
else
raise AttributeConstraintError.new("Unexpected value #{ value }.")
end
when SOAPActionAttrName
@soapaction = value
else
nil
end
end
def input_info
name_info = parent.find_operation.input_info
param_info(name_info, parent.input)
end
def output_info
name_info = parent.find_operation.output_info
param_info(name_info, parent.output)
end
def operation_style
return @style if @style
if parent_binding.soapbinding
return parent_binding.soapbinding.style
end
nil
end
private
def parent_binding
parent.parent
end
def param_info(name_info, param)
op_name = name_info.op_name
optype_name = name_info.optype_name
soapheader = param.soapheader
headerparts = soapheader.collect { |item| item.find_part }
soapbody = param.soapbody
if soapbody.encodingstyle and
soapbody.encodingstyle != ::SOAP::EncodingNamespace
raise NotImplementedError.new(
"EncodingStyle '#{ soapbody.encodingstyle }' not supported.")
end
if soapbody.namespace
op_name = op_name.dup
op_name.namespace = soapbody.namespace
end
if soapbody.parts
raise NotImplementedError.new("soap:body parts")
else
bodyparts = name_info.parts
end
faultpart = nil
soapaction = parent.soapoperation.soapaction
OperationInfo.new(operation_style, op_name, optype_name, headerparts, bodyparts, faultpart, soapaction)
end
end
end
end

54
lib/wsdl/types.rb Normal file
View file

@ -0,0 +1,54 @@
=begin
WSDL4R - WSDL types definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
class Types < Info
attr_reader :schemas
def initialize
super
@schemas = []
end
def parse_element(element)
case element
when SchemaName
o = XMLSchema::Schema.new
@schemas << o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
nil
end
end
end

34
lib/wsdl/wsdl.rb Normal file
View file

@ -0,0 +1,34 @@
=begin
WSDL4R - Base definitions.
Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'xsd/qname'
module WSDL
Version = '0.0.2'
Namespace = 'http://schemas.xmlsoap.org/wsdl/'
SOAPBindingNamespace ='http://schemas.xmlsoap.org/wsdl/soap/'
class Error < StandardError; end
end

76
lib/wsdl/xmlSchema/all.rb Normal file
View file

@ -0,0 +1,76 @@
=begin
WSDL4R - XMLSchema complexType definition for WSDL.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module XMLSchema
class All < Info
attr_reader :minoccurs
attr_reader :maxoccurs
attr_reader :elements
def initialize
super()
@minoccurs = 1
@maxoccurs = 1
@elements = []
end
def targetnamespace
parent.targetnamespace
end
def <<(element)
@elements << element
end
def parse_element(element)
case element
when AnyName
o = Any.new
@elements << o
o
when ElementName
o = Element.new
@elements << o
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when MaxOccursAttrName
@maxoccurs = value
when MinOccursAttrName
@minoccurs = value
else
nil
end
end
end
end
end

67
lib/wsdl/xmlSchema/any.rb Normal file
View file

@ -0,0 +1,67 @@
=begin
WSDL4R - XMLSchema any definition for WSDL.
Copyright (C) 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module XMLSchema
class Any < Info
attr_accessor :maxoccurs
attr_accessor :minoccurs
attr_accessor :namespace
attr_accessor :process_contents
def initialize
super()
@maxoccurs = 1
@minoccurs = 1
@namespace = '##any'
@process_contents = 'strict'
end
def targetnamespace
parent.targetnamespace
end
def parse_element(element)
nil
end
def parse_attr(attr, value)
case attr
when MaxOccursAttrName
@maxoccurs = value
when MinOccursAttrName
@minoccurs = value
when NamespaceAttrName
@namespace = value
when ProcessContentsAttrName
@process_contents = value
else
nil
end
end
end
end
end

View file

@ -0,0 +1,85 @@
=begin
WSDL4R - XMLSchema attribute definition for WSDL.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module XMLSchema
class Attribute < Info
attr_accessor :ref
attr_accessor :use
attr_accessor :form
attr_accessor :name
attr_accessor :type
attr_accessor :default
attr_accessor :fixed
attr_accessor :arytype
def initialize
super
@ref = nil
@use = nil
@form = nil
@name = nil
@type = nil
@default = nil
@fixed = nil
@arytype = nil
end
def parse_element(element)
nil
end
def parse_attr(attr, value)
case attr
when RefAttrName
@ref = value
when UseAttrName
@use = value
when FormAttrName
@form = value
when NameAttrName
@name = value
when TypeAttrName
@type = value
when DefaultAttrName
@default = value
when FixedAttrName
@fixed = value
when ArrayTypeAttrName
@arytype = if value.is_a?(XSD::QName)
value
else
XSD::QName.new(XSD::Namespace, value)
end
else
nil
end
end
end
end
end

View file

@ -0,0 +1,76 @@
=begin
WSDL4R - XMLSchema complexType definition for WSDL.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module XMLSchema
class Choice < Info
attr_reader :minoccurs
attr_reader :maxoccurs
attr_reader :elements
def initialize
super()
@minoccurs = 1
@maxoccurs = 1
@elements = []
end
def targetnamespace
parent.targetnamespace
end
def <<(element)
@elements << element
end
def parse_element(element)
case element
when AnyName
o = Any.new
@elements << o
o
when ElementName
o = Element.new
@elements << o
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when MaxOccursAttrName
@maxoccurs = value
when MinOccursAttrName
@minoccurs = value
else
nil
end
end
end
end
end

View file

@ -0,0 +1,90 @@
=begin
WSDL4R - XMLSchema complexContent definition for WSDL.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
require 'xsd/namedelements'
module WSDL
module XMLSchema
class ComplexContent < Info
attr_accessor :base
attr_reader :derivetype
attr_reader :content
attr_reader :attributes
def initialize
super
@base = nil
@derivetype = nil
@content = nil
@attributes = XSD::NamedElements.new
end
def parse_element(element)
case element
when RestrictionName, ExtensionName
@derivetype = element.name
self
when AllName
if @derivetype.nil?
raise Parser::ElementConstraintError.new("base attr not found.")
end
@content = All.new
@content
when SequenceName
if @derivetype.nil?
raise Parser::ElementConstraintError.new("base attr not found.")
end
@content = Sequence.new
@content
when ChoiceName
if @derivetype.nil?
raise Parser::ElementConstraintError.new("base attr not found.")
end
@content = Choice.new
@content
when AttributeName
if @derivetype.nil?
raise Parser::ElementConstraintError.new("base attr not found.")
end
o = Attribute.new
@attributes << o
o
end
end
def parse_attr(attr, value)
if @derivetype.nil?
return nil
end
case attr
when BaseAttrName
@base = value
else
nil
end
end
end
end
end

View file

@ -0,0 +1,130 @@
=begin
WSDL4R - XMLSchema complexType definition for WSDL.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
require 'wsdl/xmlSchema/content'
require 'xsd/namedelements'
module WSDL
module XMLSchema
class ComplexType < Info
attr_accessor :name
attr_accessor :complexcontent
attr_accessor :content
attr_accessor :final
attr_accessor :mixed
attr_reader :attributes
def initialize(name = nil)
super()
@name = name
@complexcontent = nil
@content = nil
@final = nil
@mixed = false
@attributes = XSD::NamedElements.new
end
def targetnamespace
parent.targetnamespace
end
def each_element
if @content
@content.elements.each do |element|
yield(element.name, element)
end
end
end
def find_element(name)
if @content
@content.elements.each do |element|
return element if name == element.name
end
end
nil
end
def find_element_by_name(name)
if @content
@content.elements.each do |element|
return element if name == element.name.name
end
end
nil
end
def sequence_elements=(elements)
@content = Sequence.new
elements.each do |element|
@content << element
end
end
def all_elements=(elements)
@content = All.new
elements.each do |element|
@content << element
end
end
def parse_element(element)
case element
when AllName
@content = All.new
@content
when SequenceName
@content = Sequence.new
@content
when ChoiceName
@content = Choice.new
@content
when ComplexContentName
@complexcontent = ComplexContent.new
@complexcontent
when AttributeName
o = Attribute.new
@attributes << o
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when FinalAttrName
@final = value
when MixedAttrName
@mixed = (value == 'true')
when NameAttrName
@name = XSD::QName.new(targetnamespace, value)
else
nil
end
end
end
end
end

View file

@ -0,0 +1,107 @@
=begin
WSDL4R - XMLSchema complexType definition for WSDL.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module XMLSchema
class Content < Info
attr_accessor :final
attr_accessor :mixed
attr_accessor :type
attr_reader :contents
attr_reader :elements
def initialize
super()
@final = nil
@mixed = false
@type = nil
@contents = []
@elements = []
end
def targetnamespace
parent.targetnamespace
end
def <<(content)
@contents << content
update_elements
end
def each
@contents.each do |content|
yield content
end
end
def parse_element(element)
case element
when AllName, SequenceName, ChoiceName
o = Content.new
o.type = element.name
@contents << o
o
when AnyName
o = Any.new
@contents << o
o
when ElementName
o = Element.new
@contents << o
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when FinalAttrName
@final = value
when MixedAttrName
@mixed = (value == 'true')
else
nil
end
end
def parse_epilogue
update_elements
end
private
def update_elements
@elements = []
@contents.each do |content|
if content.is_a?(Element)
@elements << [content.name, content]
end
end
end
end
end
end

View file

@ -0,0 +1,75 @@
=begin
WSDL4R - XMLSchema data definitions.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/xmlSchema/schema'
require 'wsdl/xmlSchema/import'
require 'wsdl/xmlSchema/complexType'
require 'wsdl/xmlSchema/complexContent'
require 'wsdl/xmlSchema/any'
require 'wsdl/xmlSchema/element'
require 'wsdl/xmlSchema/all'
require 'wsdl/xmlSchema/choice'
require 'wsdl/xmlSchema/sequence'
require 'wsdl/xmlSchema/attribute'
require 'wsdl/xmlSchema/unique'
module WSDL
module XMLSchema
AllName = XSD::QName.new(XSD::Namespace, 'all')
AnyName = XSD::QName.new(XSD::Namespace, 'any')
ArrayTypeAttrName = XSD::QName.new(Namespace, 'arrayType')
AttributeName = XSD::QName.new(XSD::Namespace, 'attribute')
ChoiceName = XSD::QName.new(XSD::Namespace, 'choice')
ComplexContentName = XSD::QName.new(XSD::Namespace, 'complexContent')
ComplexTypeName = XSD::QName.new(XSD::Namespace, 'complexType')
ElementName = XSD::QName.new(XSD::Namespace, 'element')
ExtensionName = XSD::QName.new(XSD::Namespace, 'extension')
ImportName = XSD::QName.new(XSD::Namespace, 'import')
RestrictionName = XSD::QName.new(XSD::Namespace, 'restriction')
SequenceName = XSD::QName.new(XSD::Namespace, 'sequence')
SchemaName = XSD::QName.new(XSD::Namespace, 'schema')
SimpleTypeName = XSD::QName.new(XSD::Namespace, 'simpleType')
UniqueName = XSD::QName.new(XSD::Namespace, 'unique')
AttributeFormDefaultAttrName = XSD::QName.new(nil, 'attributeFormDefault')
BaseAttrName = XSD::QName.new(nil, 'base')
DefaultAttrName = XSD::QName.new(nil, 'default')
ElementFormDefaultAttrName = XSD::QName.new(nil, 'elementFormDefault')
FinalAttrName = XSD::QName.new(nil, 'final')
FixedAttrName = XSD::QName.new(nil, 'fixed')
FormAttrName = XSD::QName.new(nil, 'form')
IdAttrName = XSD::QName.new(nil, 'id')
MaxOccursAttrName = XSD::QName.new(nil, 'maxOccurs')
MinOccursAttrName = XSD::QName.new(nil, 'minOccurs')
MixedAttrName = XSD::QName.new(nil, 'mixed')
NameAttrName = XSD::QName.new(nil, 'name')
NamespaceAttrName = XSD::QName.new(nil, 'namespace')
NillableAttrName = XSD::QName.new(nil, 'nillable')
RefAttrName = XSD::QName.new(nil, 'ref')
SchemaLocationAttrName = XSD::QName.new(nil, 'schemaLocation')
TargetNamespaceAttrName = XSD::QName.new(nil, 'targetNamespace')
TypeAttrName = XSD::QName.new(nil, 'type')
UseAttrName = XSD::QName.new(nil, 'use')
end
end

View file

@ -0,0 +1,115 @@
=begin
WSDL4R - XMLSchema element definition for WSDL.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module XMLSchema
class Element < Info
attr_accessor :name # required
attr_accessor :type
attr_accessor :local_complextype
attr_accessor :constraint
attr_accessor :maxoccurs
attr_accessor :minoccurs
attr_accessor :nillable
def initialize(name = nil, type = XSD::AnyTypeName)
super()
@name = name
@type = type
@local_complextype = nil
@constraint = nil
@maxoccurs = 1
@minoccurs = 1
@nillable = nil
end
def targetnamespace
parent.targetnamespace
end
def parse_element(element)
case element
when ComplexTypeName
@type = nil
@local_complextype = ComplexType.new
@local_complextype
when UniqueName
@constraint = Unique.new
@constraint
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
#@name = XSD::QName.new(nil, value)
@name = XSD::QName.new(targetnamespace, value)
when TypeAttrName
@type = if value.is_a?(XSD::QName)
value
else
XSD::QName.new(XSD::Namespace, value)
end
when MaxOccursAttrName
case parent
when All
if value != '1'
raise Parser::AttrConstraintError.new(
"Cannot parse #{ value } for #{ attr }.")
end
@maxoccurs = value
when Sequence
@maxoccurs = value
else
raise NotImplementedError.new
end
@maxoccurs
when MinOccursAttrName
case parent
when All
if ['0', '1'].include?(value)
@minoccurs = value
else
raise Parser::AttrConstraintError.new(
"Cannot parse #{ value } for #{ attr }.")
end
when Sequence
@minoccurs = value
else
raise NotImplementedError.new
end
@minoccurs
when NillableAttrName
@nillable = (value == 'true')
else
nil
end
end
end
end
end

View file

@ -0,0 +1,55 @@
=begin
WSDL4R - XMLSchema import definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module XMLSchema
class Import < Info
attr_reader :namespace
attr_reader :schemalocation
def initialize
super
@namespace = nil
@schemalocation = nil
end
def parse_element(element)
nil
end
def parse_attr(attr, value)
case attr
when NamespaceAttrName
@namespace = value
when SchemaLocationAttrName
@schemalocation = value
else
nil
end
end
end
end
end

View file

@ -0,0 +1,172 @@
=begin
WSDL4R - WSDL XML Instance parser library.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'xsd/qname'
require 'xsd/ns'
require 'xsd/charset'
require 'xsd/datatypes'
require 'xsd/xmlparser'
require 'wsdl/xmlSchema/data'
module WSDL
module XMLSchema
class Parser
include XSD
class ParseError < Error; end
class FormatDecodeError < Error; end
class UnknownElementError < FormatDecodeError; end
class UnknownAttributeError < FormatDecodeError; end
class UnexpectedElementError < FormatDecodeError; end
class ElementConstraintError < FormatDecodeError; end
class AttributeConstraintError < FormatDecodeError; end
private
class ParseFrame
attr_reader :ns
attr_reader :name
attr_accessor :node
private
def initialize(ns, name, node)
@ns = ns
@name = name
@node = node
end
end
public
def initialize(opt = {})
@parser = XSD::XMLParser.create_parser(self, opt)
@parsestack = nil
@lastnode = nil
end
def parse(string_or_readable)
@parsestack = []
@lastnode = nil
@textbuf = ''
@parser.do_parse(string_or_readable)
@lastnode
end
def charset
@parser.charset
end
def start_element(name, attrs)
lastframe = @parsestack.last
ns = parent = nil
if lastframe
ns = lastframe.ns.clone_ns
parent = lastframe.node
else
ns = XSD::NS.new
parent = nil
end
attrs = XSD::XMLParser.filter_ns(ns, attrs)
node = decode_tag(ns, name, attrs, parent)
@parsestack << ParseFrame.new(ns, name, node)
end
def characters(text)
lastframe = @parsestack.last
if lastframe
# Need not to be cloned because character does not have attr.
ns = lastframe.ns
decode_text(ns, text)
else
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)
@lastnode = lastframe.node
end
private
def decode_tag(ns, name, attrs, parent)
o = nil
element = ns.parse(name)
if !parent
if element == SchemaName
o = Schema.parse_element(element)
else
raise UnknownElementError.new("Unknown element #{ element }.")
end
else
o = parent.parse_element(element)
unless o
raise UnknownElementError.new("Unknown element #{ element }.")
end
o.parent = parent
end
attrs.each do |key, value|
attr = unless /:/ =~ key
XSD::QName.new(nil, key)
else
ns.parse(key)
end
value_ele = if /:/ !~ value
value
elsif /^http:\/\// =~ value # ToDo: ugly.
value
else
begin
ns.parse(value)
rescue
value
end
end
if attr == IdAttrName
o.id = value_ele
else
unless o.parse_attr(attr, value_ele)
STDERR.puts("Unknown attr #{ attr }.")
# raise UnknownAttributeError.new("Unknown attr #{ attr }.")
end
end
end
o
end
def decode_tag_end(ns, node)
node.parse_epilogue
end
def decode_text(ns, text)
@textbuf << text
end
end
end
end

View file

@ -0,0 +1,105 @@
=begin
WSDL4R - XMLSchema schema definition for WSDL.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
require 'xsd/namedelements'
module WSDL
module XMLSchema
class Schema < Info
attr_reader :targetnamespace # required
attr_reader :complextypes
attr_reader :elements
attr_reader :attributes
attr_reader :imports
attr_accessor :attributeformdefault
attr_accessor :elementformdefault
def initialize
super
@targetnamespace = nil
@complextypes = XSD::NamedElements.new
@elements = XSD::NamedElements.new
@attributes = XSD::NamedElements.new
@imports = []
@elementformdefault = nil
end
def parse_element(element)
case element
when ImportName
o = Import.new
@imports << o
o
when ComplexTypeName
o = ComplexType.new
@complextypes << o
o
when ElementName
o = Element.new
@elements << o
o
when AttributeName
o = Attribute.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when TargetNamespaceAttrName
@targetnamespace = value
when AttributeFormDefaultAttrName
@attributeformdefault = value
when ElementFormDefaultAttrName
@elementformdefault = value
else
nil
end
end
def collect_elements
result = XSD::NamedElements.new
result.concat(@elements)
result
end
def collect_complextypes
result = XSD::NamedElements.new
result.concat(@complextypes)
result
end
def self.parse_element(element)
if element == SchemaName
Schema.new
else
nil
end
end
end
end
end

View file

@ -0,0 +1,76 @@
=begin
WSDL4R - XMLSchema complexType definition for WSDL.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module XMLSchema
class Sequence < Info
attr_reader :minoccurs
attr_reader :maxoccurs
attr_reader :elements
def initialize
super()
@minoccurs = 1
@maxoccurs = 1
@elements = []
end
def targetnamespace
parent.targetnamespace
end
def <<(element)
@elements << element
end
def parse_element(element)
case element
when AnyName
o = Any.new
@elements << o
o
when ElementName
o = Element.new
@elements << o
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when MaxOccursAttrName
@maxoccurs = value
when MinOccursAttrName
@minoccurs = value
else
nil
end
end
end
end
end

View file

@ -0,0 +1,45 @@
=begin
WSDL4R - XMLSchema unique element.
Copyright (C) 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'wsdl/info'
module WSDL
module XMLSchema
class Unique < Info
def initialize
super
end
def parse_element(element)
# Accepts any element.
self
end
def parse_attr(attr, value)
# Accepts any attribute.
true
end
end
end
end

175
lib/xsd/charset.rb Normal file
View file

@ -0,0 +1,175 @@
=begin
XSD4R - Charset handling library.
Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
module XSD
module Charset
@encoding = $KCODE
class XSDError < StandardError; end
class CharsetError < XSDError; end
class UnknownCharsetError < CharsetError; end
class CharsetConversionError < CharsetError; end
public
###
## Maps
#
EncodingConvertMap = {}
def Charset.init
begin
require 'xsd/iconvcharset'
@encoding = 'UTF8'
EncodingConvertMap[['UTF8', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", "utf-8", str) }
EncodingConvertMap[['EUC' , 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", "euc-jp", str) }
EncodingConvertMap[['EUC' , 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv("shift-jis", "euc-jp", str) }
if /(mswin|bccwin|mingw|cygwin)/ =~ RUBY_PLATFORM
EncodingConvertMap[['UTF8', 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv("cp932", "utf-8", str) }
EncodingConvertMap[['SJIS', 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", "cp932", str) }
EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", "cp932", str) }
else
EncodingConvertMap[['UTF8', 'SJIS']] = Proc.new { |str| IconvCharset.safe_iconv("shift-jis", "utf-8", str) }
EncodingConvertMap[['SJIS', 'UTF8']] = Proc.new { |str| IconvCharset.safe_iconv("utf-8", "shift-jis", str) }
EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| IconvCharset.safe_iconv("euc-jp", "shift-jis", str) }
end
rescue LoadError
begin
require 'nkf'
EncodingConvertMap[['EUC' , 'SJIS']] = Proc.new { |str| NKF.nkf('-sXm0', str) }
EncodingConvertMap[['SJIS', 'EUC' ]] = Proc.new { |str| NKF.nkf('-eXm0', str) }
rescue LoadError
end
begin
require 'uconv'
@encoding = 'UTF8'
EncodingConvertMap[['UTF8', 'EUC' ]] = Uconv.method(:u8toeuc)
EncodingConvertMap[['UTF8', 'SJIS']] = Uconv.method(:u8tosjis)
EncodingConvertMap[['EUC' , 'UTF8']] = Uconv.method(:euctou8)
EncodingConvertMap[['SJIS', 'UTF8']] = Uconv.method(:sjistou8)
rescue LoadError
end
end
end
self.init
CharsetMap = {
'NONE' => 'us-ascii',
'EUC' => 'euc-jp',
'SJIS' => 'shift_jis',
'UTF8' => 'utf-8',
}
###
## handlers
#
def Charset.encoding
@encoding
end
def Charset.encoding_label
charset_label(@encoding)
end
def Charset.encoding_to_xml(str, charset)
encoding_conv(str, @encoding, charset_str(charset))
end
def Charset.encoding_from_xml(str, charset)
encoding_conv(str, charset_str(charset), @encoding)
end
def Charset.encoding_conv(str, enc_from, enc_to)
if enc_from == enc_to or enc_from == 'NONE' or enc_to == 'NONE'
str
elsif converter = EncodingConvertMap[[enc_from, enc_to]]
converter.call(str)
else
raise CharsetConversionError.new(
"Converter not found: #{ enc_from } -> #{ enc_to }")
end
end
def Charset.charset_label(encoding)
CharsetMap[encoding.upcase]
end
def Charset.charset_str(label)
CharsetMap.index(label.downcase)
end
# Original regexps: http://www.din.or.jp/~ohzaki/perl.htm
# ascii_euc = '[\x00-\x7F]'
ascii_euc = '[\x9\xa\xd\x20-\x7F]' # XML 1.0 restricted.
twobytes_euc = '(?:[\x8E\xA1-\xFE][\xA1-\xFE])'
threebytes_euc = '(?:\x8F[\xA1-\xFE][\xA1-\xFE])'
character_euc = "(?:#{ ascii_euc }|#{ twobytes_euc }|#{ threebytes_euc })"
EUCRegexp = Regexp.new("\\A#{ character_euc }*\\z", nil, "NONE")
# onebyte_sjis = '[\x00-\x7F\xA1-\xDF]'
onebyte_sjis = '[\x9\xa\xd\x20-\x7F\xA1-\xDF]' # XML 1.0 restricted.
twobytes_sjis = '(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC])'
character_sjis = "(?:#{ onebyte_sjis }|#{ twobytes_sjis })"
SJISRegexp = Regexp.new("\\A#{ character_sjis }*\\z", nil, "NONE")
# 0xxxxxxx
#ascii_utf8 = '[\0-\x7F]'
ascii_utf8 = '[\x9\xA\xD\x20-\x7F]' # XML 1.0 restricted.
# 110yyyyy 10xxxxxx
twobytes_utf8 = '(?:[\xC0-\xDF][\x80-\xBF])'
# 1110zzzz 10yyyyyy 10xxxxxx
threebytes_utf8 = '(?:[\xE0-\xEF][\x80-\xBF][\x80-\xBF])'
# 11110uuu 10uuuzzz 10yyyyyy 10xxxxxx
fourbytes_utf8 = '(?:[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF])'
character_utf8 = "(?:#{ ascii_utf8 }|#{ twobytes_utf8 }|#{ threebytes_utf8 }|#{ fourbytes_utf8 })"
UTF8Regexp = Regexp.new("\\A#{ character_utf8 }*\\z", nil, "NONE")
def Charset.is_utf8(str)
UTF8Regexp =~ str
end
def Charset.is_euc(str)
EUCRegexp =~ str
end
def Charset.is_sjis(str)
SJISRegexp =~ str
end
def Charset.is_ces(str, code = $KCODE)
case code
when 'NONE'
true
when 'UTF8'
is_utf8(str)
when 'EUC'
is_euc(str)
when 'SJIS'
is_sjis(str)
else
raise UnknownCharsetError.new("Unknown charset: #{ code }")
end
end
end
end

1094
lib/xsd/datatypes.rb Normal file

File diff suppressed because it is too large Load diff

31
lib/xsd/datatypes1999.rb Normal file
View file

@ -0,0 +1,31 @@
=begin
XSD4R - XML Schema Datatype 1999 support
Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'xsd/datatypes'
module XSD
Namespace.replace('http://www.w3.org/1999/XMLSchema')
InstanceNamespace.replace('http://www.w3.org/1999/XMLSchema-instance')
AnyTypeLiteral.replace('ur-type')
AnySimpleTypeLiteral.replace('ur-type')
NilLiteral.replace('null')
NilValue.replace('1')
DateTimeLiteral.replace('timeInstant')
end

44
lib/xsd/iconvcharset.rb Normal file
View file

@ -0,0 +1,44 @@
=begin
XSD4R - Charset handling with iconv.
Copyright (C) 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'iconv'
module XSD
class IconvCharset
def self.safe_iconv(to, from, str)
iconv = Iconv.new(to, from)
out = ""
begin
out << iconv.iconv(str)
rescue Iconv::IllegalSequence => e
out << e.success
ch, str = e.failed.split(//, 2)
out << '?'
STDERR.puts("Failed to convert #{ch}")
retry
end
return out
end
end
end

86
lib/xsd/namedelements.rb Normal file
View file

@ -0,0 +1,86 @@
=begin
XSD4R - WSDL named element collection.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
module XSD
class NamedElements
include Enumerable
def initialize
@elements = []
@cache = {}
end
def dup
o = NamedElements.new
o.elements = @elements.dup
o
end
def size
@elements.size
end
def [](idx)
if idx.is_a?(Numeric)
@elements[idx]
else
@cache[idx] ||= @elements.find { |item| item.name == idx }
end
end
def find_name(name)
@elements.find { |item| item.name.name == name }
end
def each
@elements.each do |element|
yield(element)
end
end
def <<(rhs)
@elements << rhs
self
end
def +(rhs)
o = NamedElements.new
o.elements = @elements + rhs.elements
o
end
def concat(rhs)
@elements.concat(rhs.elements)
self
end
protected
def elements=(rhs)
@elements = rhs
end
def elements
@elements
end
end
end

141
lib/xsd/ns.rb Normal file
View file

@ -0,0 +1,141 @@
=begin
XSD4R - XML Schema Namespace library
Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'xsd/datatypes'
module XSD
class NS
class Assigner
def initialize
@count = 0
end
def assign(ns)
@count += 1
"n#{ @count }"
end
end
attr_reader :default_namespace
class FormatError < Error; end
public
def initialize(tag2ns = {})
@tag2ns = tag2ns
@assigner = nil
@ns2tag = {}
@tag2ns.each do |tag, ns|
@ns2tag[ns] = tag
end
@default_namespace = nil
end
def assign(ns, tag = nil)
if (tag == '')
@default_namespace = ns
tag
else
@assigner ||= Assigner.new
tag ||= @assigner.assign(ns)
@ns2tag[ns] = tag
@tag2ns[tag] = ns
tag
end
end
def assigned?(ns)
@ns2tag.key?(ns)
end
def assigned_tag?(tag)
@tag2ns.key?(tag)
end
def clone_ns
cloned = NS.new(@tag2ns.dup)
cloned.assigner = @assigner
cloned.assign(@default_namespace, '') if @default_namespace
cloned
end
def name(name)
if (name.namespace == @default_namespace)
name.name
elsif @ns2tag.key?(name.namespace)
@ns2tag[name.namespace] + ':' << name.name
else
raise FormatError.new('Namespace: ' << name.namespace << ' not defined yet.')
end
end
def compare(ns, name, rhs)
if (ns == @default_namespace)
return true if (name == rhs)
end
@tag2ns.each do |assigned_tag, assigned_ns|
if assigned_ns == ns && "#{ assigned_tag }:#{ name }" == rhs
return true
end
end
false
end
# $1 and $2 are necessary.
ParseRegexp = Regexp.new('^([^:]+)(?::(.+))?$')
def parse(elem)
ns = nil
name = nil
ParseRegexp =~ elem
if $2
ns = @tag2ns[$1]
name = $2
if !ns
raise FormatError.new('Unknown namespace qualifier: ' << $1)
end
elsif $1
ns = @default_namespace
name = $1
end
if !name
raise FormatError.new("Illegal element format: #{ elem }")
end
XSD::QName.new(ns, name)
end
def each_ns
@ns2tag.each do |ns, tag|
yield(ns, tag)
end
end
protected
def assigner=(assigner)
@assigner = assigner
end
end
end

77
lib/xsd/qname.rb Normal file
View file

@ -0,0 +1,77 @@
=begin
XSD4R - XML QName definition.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
module XSD
class QName
attr_accessor :namespace
attr_accessor :name
def initialize(namespace = nil, name = nil)
@namespace = namespace
@name = name
end
def dup_name(name)
self.class.new(@namespace, name)
end
def match(rhs)
unless self.class === rhs
return false
end
if rhs.namespace and (rhs.namespace != @namespace)
return false
end
if rhs.name and (rhs.name != @name)
return false
end
true
end
def ==(rhs)
(self.class === rhs && @namespace == rhs.namespace && @name == rhs.name)
end
def ===(rhs)
(self == rhs)
end
def eql?(rhs)
(self == rhs)
end
def hash
@namespace.hash ^ @name.hash
end
def to_s
"{#{ namespace }}#{ name }"
end
NormalizedNameRegexp = /^\{([^}]*)\}(.*)$/
def parse(str)
NormalizedNameRegexp =~ str
self.new($1, $2)
end
end
end

72
lib/xsd/xmlparser.rb Normal file
View file

@ -0,0 +1,72 @@
=begin
XSD4R - XML Instance parser library.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'xsd/xmlparser/parser'
module XSD
module XMLParser
def create_parser(host, opt)
XSD::XMLParser::Parser.create_parser(host, opt)
end
module_function :create_parser
# $1 is necessary.
NSParseRegexp = Regexp.new('^xmlns:?(.*)$')
def filter_ns(ns, attrs)
return attrs if attrs.nil? or attrs.empty?
newattrs = {}
attrs.each do |key, value|
if (NSParseRegexp =~ key)
# '' means 'default namespace'.
tag = $1 || ''
ns.assign(value, tag)
else
newattrs[key] = value
end
end
newattrs
end
module_function :filter_ns
end
end
# Try to load XML processor.
loaded = false
[
'xsd/xmlparser/xmlscanner',
'xsd/xmlparser/xmlparser',
'xsd/xmlparser/rexmlparser',
].each do |lib|
begin
require lib
loaded = true
break
rescue LoadError
end
end
unless loaded
raise RuntimeError.new("XML processor module not found.")
end

107
lib/xsd/xmlparser/parser.rb Normal file
View file

@ -0,0 +1,107 @@
=begin
XSD4R - XML Instance parser library.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'xsd/qname'
require 'xsd/ns'
require 'xsd/charset'
module XSD
module XMLParser
class Parser
class ParseError < Error; end
class FormatDecodeError < ParseError; end
class UnknownElementError < FormatDecodeError; end
class UnknownAttributeError < FormatDecodeError; end
class UnexpectedElementError < FormatDecodeError; end
class ElementConstraintError < FormatDecodeError; end
@@parser_factory = nil
def self.factory
@@parser_factory
end
def self.create_parser(host, opt = {})
@@parser_factory.new(host, opt)
end
def self.add_factory(factory)
if $DEBUG
puts "Set #{ factory } as XML processor."
end
@@parser_factory = factory
end
public
attr_accessor :charset
def initialize(host, opt = {})
@host = host
@charset = opt[:charset] || 'us-ascii'
end
def parse(string_or_readable)
@textbuf = ''
prologue
do_parse(string_or_readable)
epilogue
end
private
def do_parse(string_or_readable)
raise NotImplementError.new(
'Method do_parse must be defined in derived class.')
end
def start_element(name, attrs)
@host.start_element(name, attrs)
end
def characters(text)
@host.characters(text)
end
def end_element(name)
@host.end_element(name)
end
def prologue
end
def epilogue
end
def xmldecl_encoding=(charset)
if @charset.nil?
@charset = charset
else
# Definition in a stream (like HTTP) has a priority.
p "encoding definition: #{ charset } is ignored." if $DEBUG
end
end
end
end
end

View file

@ -0,0 +1,65 @@
=begin
XSD4R - REXMLParser XML parser library.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'xsd/xmlparser'
require 'rexml/streamlistener'
require 'rexml/document'
module XSD
module XMLParser
class REXMLParser < XSD::XMLParser::Parser
include REXML::StreamListener
def do_parse(string_or_readable)
source = nil
source = REXML::SourceFactory.create_from(string_or_readable)
source.encoding = charset if charset
# Listener passes a String in utf-8.
@charset = 'utf-8'
REXML::Document.parse_stream(source, self)
end
def epilogue
end
def tag_start(name, attrs)
start_element(name, attrs)
end
def tag_end(name)
end_element(name)
end
def text(text)
characters(text)
end
def xmldecl(version, encoding, standalone)
# Version should be checked.
end
add_factory(self)
end
end
end

View file

@ -0,0 +1,61 @@
=begin
XSD4R - XMLParser XML parser library.
Copyright (C) 2001, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'xsd/xmlparser'
require 'xml/parser'
module XSD
module XMLParser
class XMLParser < XSD::XMLParser::Parser
class Listener < XML::Parser
begin
require 'xml/encoding-ja'
include XML::Encoding_ja
rescue LoadError
# uconv may not be installed.
end
end
def do_parse(string_or_readable)
# XMLParser passes a String in utf-8.
@charset = 'utf-8'
@parser = Listener.new
@parser.parse(string_or_readable) do |type, name, data|
case type
when XML::Parser::START_ELEM
start_element(name, data)
when XML::Parser::END_ELEM
end_element(name)
when XML::Parser::CDATA
characters(data)
else
raise FormatDecodeError.new("Unexpected XML: #{ type }/#{ name }/#{ data }.")
end
end
end
add_factory(self)
end
end
end

View file

@ -0,0 +1,158 @@
=begin
XSD4R - XMLScan XML parser library.
Copyright (C) 2002, 2003 NAKAMURA, Hiroshi.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PRATICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 675 Mass
Ave, Cambridge, MA 02139, USA.
=end
require 'xsd/xmlparser'
require 'xmlscan/scanner'
module XSD
module XMLParser
class XMLScanner < XSD::XMLParser::Parser
include XMLScan::Visitor
def do_parse(string_or_readable)
@attrs = {}
@curattr = nil
@scanner = XMLScan::XMLScanner.new(self)
@scanner.kcode = ::XSD::Charset.charset_str(charset) if charset
@scanner.parse(string_or_readable)
end
def scanner_kcode=(charset)
@scanner.kcode = ::XSD::Charset.charset_str(charset) if charset
self.xmldecl_encoding = charset
end
ENTITY_REF_MAP = {
'lt' => '<',
'gt' => '>',
'amp' => '&',
'quot' => '"',
'apos' => '\''
}
def parse_error(msg)
raise ParseError.new(msg)
end
def wellformed_error(msg)
raise NotWellFormedError.new(msg)
end
def valid_error(msg)
raise NotValidError.new(msg)
end
def warning(msg)
p msg if $DEBUG
end
# def on_xmldecl; end
def on_xmldecl_version(str)
# 1.0 expected.
end
def on_xmldecl_encoding(str)
self.scanner_kcode = str
end
# def on_xmldecl_standalone(str); end
# def on_xmldecl_other(name, value); end
# def on_xmldecl_end; end
# def on_doctype(root, pubid, sysid); end
# def on_prolog_space(str); end
# def on_comment(str); end
# def on_pi(target, pi); end
def on_chardata(str)
characters(str)
end
# def on_cdata(str); end
def on_etag(name)
end_element(name)
end
def on_entityref(ref)
characters(ENTITY_REF_MAP[ref])
end
def on_charref(code)
characters([code].pack('U'))
end
def on_charref_hex(code)
on_charref(code)
end
# def on_start_document; end
# def on_end_document; end
def on_stag(name)
@attrs = {}
end
def on_attribute(name)
@attrs[name] = @curattr = ''
end
def on_attr_value(str)
@curattr << str
end
def on_attr_entityref(ref)
@curattr << ENTITY_REF_MAP[ref]
end
def on_attr_charref(code)
@curattr << [code].pack('U')
end
def on_attr_charref_hex(code)
on_attr_charref(code)
end
# def on_attribute_end(name); end
def on_stag_end_empty(name)
on_stag_end(name)
on_etag(name)
end
def on_stag_end(name)
start_element(name, @attrs)
end
add_factory(self)
end
end
end

16
sample/soap/babelfish.rb Normal file
View file

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
text = ARGV.shift || 'Hello world.'
lang = ARGV.shift || 'en_fr'
require 'soap/rpc/driver'
server = 'http://services.xmethods.net/perl/soaplite.cgi'
InterfaceNS = 'urn:xmethodsBabelFish'
wireDumpDev = nil # STDERR
drv = SOAP::RPC::Driver.new(server, InterfaceNS)
drv.wiredump_dev = wireDumpDev
drv.add_method_with_soapaction('BabelFish', InterfaceNS + "#BabelFish", 'translationmode', 'sourcedata')
p drv.BabelFish(lang, text)

17
sample/soap/calc/calc.rb Normal file
View file

@ -0,0 +1,17 @@
module CalcService
def self.add(lhs, rhs)
lhs + rhs
end
def self.sub(lhs, rhs)
lhs - rhs
end
def self.multi(lhs, rhs)
lhs * rhs
end
def self.div(lhs, rhs)
lhs / rhs
end
end

29
sample/soap/calc/calc2.rb Normal file
View file

@ -0,0 +1,29 @@
class CalcService2
def initialize(value = 0)
@value = value
end
def set(value)
@value = value
end
def get
@value
end
def +(rhs)
@value + rhs
end
def -(rhs)
@value - rhs
end
def *(rhs)
@value * rhs
end
def /(rhs)
@value / rhs
end
end

View file

@ -0,0 +1,26 @@
require 'soap/rpc/driver'
server = ARGV.shift || 'http://localhost:7000/'
# server = 'http://localhost:8808/server.cgi'
calc = SOAP::RPC::Driver.new(server, 'http://tempuri.org/calcService')
#calc.wiredump_dev = STDERR
calc.add_method('add', 'lhs', 'rhs')
calc.add_method('sub', 'lhs', 'rhs')
calc.add_method('multi', 'lhs', 'rhs')
calc.add_method('div', 'lhs', 'rhs')
puts 'add: 1 + 2 # => 3'
puts calc.add(1, 2)
puts 'sub: 1.1 - 2.2 # => -1.1'
puts calc.sub(1.1, 2.2)
puts 'multi: 1.1 * 2.2 # => 2.42'
puts calc.multi(1.1, 2.2)
puts 'div: 5 / 2 # => 2'
puts calc.div(5, 2)
puts 'div: 5.0 / 2 # => 2.5'
puts calc.div(5.0, 2)
puts 'div: 1.1 / 0 # => Infinity'
puts calc.div(1.1, 0)
puts 'div: 1 / 0 # => ZeroDivisionError'
puts calc.div(1, 0)

View file

@ -0,0 +1,29 @@
require 'soap/rpc/driver'
server = ARGV.shift || 'http://localhost:7000/'
# server = 'http://localhost:8808/server2.cgi'
var = SOAP::RPC::Driver.new( server, 'http://tempuri.org/calcService' )
var.add_method( 'set', 'newValue' )
var.add_method( 'get' )
var.add_method_as( '+', 'add', 'rhs' )
var.add_method_as( '-', 'sub', 'rhs' )
var.add_method_as( '*', 'multi', 'rhs' )
var.add_method_as( '/', 'div', 'rhs' )
puts 'var.set( 1 )'
puts '# Bare in mind that another client set another value to this service.'
puts '# This is only a sample for proof of concept.'
var.set( 1 )
puts 'var + 2 # => 1 + 2 = 3'
puts var + 2
puts 'var - 2.2 # => 1 - 2.2 = -1.2'
puts var - 2.2
puts 'var * 2.2 # => 1 * 2.2 = 2.2'
puts var * 2.2
puts 'var / 2 # => 1 / 2 = 0'
puts var / 2
puts 'var / 2.0 # => 1 / 2.0 = 0.5'
puts var / 2.0
puts 'var / 0 # => 1 / 0 => ZeroDivisionError'
puts var / 0

15
sample/soap/calc/httpd.rb Normal file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env ruby
require 'webrick'
require 'getopts'
getopts "", 'r:', 'p:8808'
s = WEBrick::HTTPServer.new(
:BindAddress => "0.0.0.0",
:Port => $OPT_p.to_i,
:DocumentRoot => $OPT_r || ".",
:CGIPathEnv => ENV['PATH']
)
trap(:INT){ s.shutdown }
s.start

View file

@ -0,0 +1,15 @@
#!/usr/bin/env ruby
require 'soap/rpc/cgistub'
class CalcServer < SOAP::RPC::CGIStub
def initialize(*arg)
super
require 'calc'
servant = CalcService
add_servant(servant, 'http://tempuri.org/calcService')
end
end
status = CalcServer.new('CalcServer', nil).start

View file

@ -0,0 +1,17 @@
#!/usr/bin/env ruby
require 'soap/rpc/standaloneServer'
require 'calc'
class CalcServer < SOAP::RPC::StandaloneServer
def initialize(*arg)
super
servant = CalcService
add_servant(servant, 'http://tempuri.org/calcService')
end
end
if $0 == __FILE__
status = CalcServer.new('CalcServer', nil, '0.0.0.0', 7000).start
end

View file

@ -0,0 +1,20 @@
#!/usr/bin/env ruby
require 'soap/rpc/standaloneServer'
require 'calc2'
class CalcServer2 < SOAP::RPC::StandaloneServer
def on_init
servant = CalcService2.new
add_method(servant, 'set', 'newValue')
add_method(servant, 'get')
add_method_as(servant, '+', 'add', 'lhs')
add_method_as(servant, '-', 'sub', 'lhs')
add_method_as(servant, '*', 'multi', 'lhs')
add_method_as(servant, '/', 'div', 'lhs')
end
end
if $0 == __FILE__
status = CalcServer2.new('CalcServer', 'http://tempuri.org/calcService', '0.0.0.0', 7000).start
end

43
sample/soap/digraph.rb Normal file
View file

@ -0,0 +1,43 @@
require 'soap/marshal'
class Node; include SOAP::Marshallable
attr_reader :first, :second, :str
def initialize(*init_next)
@first = init_next[0]
@second = init_next[1]
end
end
n9 = Node.new
n81 = Node.new(n9)
n82 = Node.new(n9)
n7 = Node.new(n81, n82)
n61 = Node.new(n7)
n62 = Node.new(n7)
n5 = Node.new(n61, n62)
n41 = Node.new(n5)
n42 = Node.new(n5)
n3 = Node.new(n41, n42)
n21 = Node.new(n3)
n22 = Node.new(n3)
n1 = Node.new(n21, n22)
File.open("digraph_marshalled_string.soap", "wb") do |f|
SOAP::Marshal.dump(n1, f)
end
marshalledString = File.open("digraph_marshalled_string.soap").read
puts marshalledString
newnode = SOAP::Marshal.unmarshal(marshalledString)
puts newnode.inspect
p newnode.first.first.__id__
p newnode.second.first.__id__
p newnode.first.first.first.first.__id__
p newnode.second.first.second.first.__id__
File.unlink("digraph_marshalled_string.soap")

View file

@ -0,0 +1,19 @@
#!/usr/bin/env ruby
require "soap/rpc/driver"
ExchangeServiceNamespace = 'http://tempuri.org/exchangeService'
server = ARGV.shift || "http://localhost:7000/"
# server = "http://localhost:8808/server.cgi"
logger = nil
wiredump_dev = nil
# logger = Logger.new(STDERR)
# wiredump_dev = STDERR
drv = SOAP::RPC::Driver.new(server, ExchangeServiceNamespace)
drv.wiredump_dev = wiredump_dev
drv.add_method("rate", "country1", "country2")
p drv.rate("USA", "Japan")

View file

@ -0,0 +1,17 @@
require 'soap/rpc/driver'
ExchangeServiceNamespace = 'http://tempuri.org/exchangeService'
class Exchange
ForeignServer = "http://services.xmethods.net/soap"
Namespace = "urn:xmethods-CurrencyExchange"
def initialize
@drv = SOAP::RPC::Driver.new(ForeignServer, Namespace)
@drv.add_method("getRate", "country1", "country2")
end
def rate(country1, country2)
return @drv.getRate(country1, country2)
end
end

View file

@ -0,0 +1,15 @@
#!/usr/bin/env ruby
require 'webrick'
require 'getopts'
getopts "", 'r:', 'p:8808'
s = WEBrick::HTTPServer.new(
:BindAddress => "0.0.0.0",
:Port => $OPT_p.to_i,
:DocumentRoot => $OPT_r || ".",
:CGIPathEnv => ENV['PATH']
)
trap(:INT){ s.shutdown }
s.start

View file

@ -0,0 +1,14 @@
#!/usr/local/bin/ruby
require 'soap/rpc/cgistub'
require 'exchange'
class ExchangeServer < SOAP::RPC::CGIStub
def initialize(*arg)
super
servant = Exchange.new
add_servant(servant)
end
end
status = ExchangeServer.new('SampleStructServer', ExchangeServiceNamespace).start

View file

@ -0,0 +1,16 @@
#!/usr/bin/env ruby
require 'soap/rpc/standaloneServer'
require 'exchange'
class ExchangeServer < SOAP::RPC::StandaloneServer
def initialize(*arg)
super
servant = Exchange.new
add_servant(servant)
end
end
if $0 == __FILE__
status = ExchangeServer.new('SampleStructServer', ExchangeServiceNamespace, '0.0.0.0', 7000).start
end

View file

@ -0,0 +1,6 @@
require 'soap/rpc/driver'
s = SOAP::RPC::Driver.new('http://localhost:2000/', 'urn:hws')
s.add_method("hello_world", "from")
p s.hello_world(self.to_s)

Some files were not shown because too many files have changed in this diff Show more