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

* lib/{soap,wsdl,xsd}, test/{soap,wsdl,xsd}: imported soap4r/1.5.4.

== SOAP client and server ==

	  === for both client side and server side ===

	  * improved document/literal service support.
	    style(rpc,document)/use(encoding, literal) combination are all
	    supported.  for the detail about combination, see
	    test/soap/test_style.rb.

	  * let WSDLEncodedRegistry#soap2obj map SOAP/OM to Ruby according to
	    WSDL as well as obj2soap.  closes #70.

	  * let SOAP::Mapping::Object handle XML attribute for doc/lit service.
	    you can set/get XML attribute via accessor methods which as a name
	    'xmlattr_' prefixed (<foo name="bar"/> -> Foo#xmlattr_name).

	  === client side ===

	  * WSDLDriver capitalized name operation bug fixed.  from
	    1.5.3-ruby1.8.2, operation which has capitalized name (such as
	    KeywordSearchRequest in AWS) is defined as a method having
	    uncapitalized name. (converted with GenSupport.safemethodname
	    to handle operation name 'foo-bar').  it introduced serious
	    incompatibility; in the past, it was defined as a capitalized.
	    define capitalized method as well under that circumstance.

	  * added new factory interface 'WSDLDriverFactory#create_rpc_driver'
	    to create RPC::Driver, not WSDLDriver (RPC::Driver and WSDLDriver
	    are merged).  'WSDLDriverFactory#create_driver' still creates
	    WSDLDriver for compatibility but it warns that the method is
	    deprecated.  please use create_rpc_driver instead of create_driver.

	  * allow to use an URI object as an endpoint_url even with net/http,
	    not http-access2.

	  === server side ===

	  * added mod_ruby support to SOAP::CGIStub.  rename a CGI script
	    server.cgi to server.rb and let mod_ruby's RubyHandler handles the
	    script.  CGIStub detects if it's running under mod_ruby environment
	    or not.

	  * added fcgi support to SOAP::CGIStub.  see the sample at
	    sample/soap/calc/server.fcgi.  (almost same as server.cgi but has
	    fcgi handler at the bottom.)

	  * allow to return a SOAPFault object to respond customized SOAP fault.

	  * added the interface 'generate_explicit_type' for server side
	    (CGIStub, HTTPServer).  call 'self.generate_explicit_type = true'
	    if you want to return simplified XML even if it's rpc/encoded
	    service.

	  == WSDL ==

	  === WSDL definition ===

	  * improved XML Schema support such as extension, restriction,
	    simpleType, complexType + simpleContent, ref, length, import,
	    include.

	  * reduced "unknown element/attribute" warnings (warn only 1 time for
	    each QName).

	  * importing XSD file at schemaLocation with xsd:import.

	  === code generation from WSDL ===

	  * generator crashed when there's '-' in defined element/attribute
	    name.

	  * added ApacheMap WSDL definition.

	* sample/{soap,wsdl}: removed.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@8502 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nahi 2005-05-22 13:20:28 +00:00
parent 15b7d43988
commit 991d0c409c
181 changed files with 3183 additions and 9380 deletions

View file

@ -1,4 +1,83 @@
XSun May 22 19:11:35 2005 GOTOU Yuuzou <gotoyuzo@notwork.org>
Sun May 22 21:54:06 2005 NAKAMURA, Hiroshi <nakahiro@sarion.co.jp>
* lib/{soap,wsdl,xsd}, test/{soap,wsdl,xsd}: imported soap4r/1.5.4.
== SOAP client and server ==
=== for both client side and server side ===
* improved document/literal service support.
style(rpc,document)/use(encoding, literal) combination are all
supported. for the detail about combination, see
test/soap/test_style.rb.
* let WSDLEncodedRegistry#soap2obj map SOAP/OM to Ruby according to
WSDL as well as obj2soap. closes #70.
* let SOAP::Mapping::Object handle XML attribute for doc/lit service.
you can set/get XML attribute via accessor methods which as a name
'xmlattr_' prefixed (<foo name="bar"/> -> Foo#xmlattr_name).
=== client side ===
* WSDLDriver capitalized name operation bug fixed. from
1.5.3-ruby1.8.2, operation which has capitalized name (such as
KeywordSearchRequest in AWS) is defined as a method having
uncapitalized name. (converted with GenSupport.safemethodname
to handle operation name 'foo-bar'). it introduced serious
incompatibility; in the past, it was defined as a capitalized.
define capitalized method as well under that circumstance.
* added new factory interface 'WSDLDriverFactory#create_rpc_driver'
to create RPC::Driver, not WSDLDriver (RPC::Driver and WSDLDriver
are merged). 'WSDLDriverFactory#create_driver' still creates
WSDLDriver for compatibility but it warns that the method is
deprecated. please use create_rpc_driver instead of create_driver.
* allow to use an URI object as an endpoint_url even with net/http,
not http-access2.
=== server side ===
* added mod_ruby support to SOAP::CGIStub. rename a CGI script
server.cgi to server.rb and let mod_ruby's RubyHandler handles the
script. CGIStub detects if it's running under mod_ruby environment
or not.
* added fcgi support to SOAP::CGIStub. see the sample at
sample/soap/calc/server.fcgi. (almost same as server.cgi but has
fcgi handler at the bottom.)
* allow to return a SOAPFault object to respond customized SOAP fault.
* added the interface 'generate_explicit_type' for server side
(CGIStub, HTTPServer). call 'self.generate_explicit_type = true'
if you want to return simplified XML even if it's rpc/encoded
service.
== WSDL ==
=== WSDL definition ===
* improved XML Schema support such as extension, restriction,
simpleType, complexType + simpleContent, ref, length, import,
include.
* reduced "unknown element/attribute" warnings (warn only 1 time for
each QName).
* importing XSD file at schemaLocation with xsd:import.
=== code generation from WSDL ===
* generator crashed when there's '-' in defined element/attribute
name.
* added ApacheMap WSDL definition.
* sample/{soap,wsdl}: removed.
Sun May 22 19:11:35 2005 GOTOU Yuuzou <gotoyuzo@notwork.org>
* ext/openssl/lib/openssl/ssl.rb (OpenSSL::SSL::SSLServer#intialize):
should initialize session id context. [ruby-core:4663]

View file

@ -1,5 +1,5 @@
# soap/baseData.rb: SOAP4R - Base type library
# Copyright (C) 2000, 2001, 2003, 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2000, 2001, 2003-2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -56,6 +56,14 @@ module SOAPType
@extraattr = {}
end
def inspect
if self.is_a?(XSD::NSDBase)
sprintf("#<%s:0x%x %s %s>", self.class.name, __id__, self.elename, self.type)
else
sprintf("#<%s:0x%x %s>", self.class.name, __id__, self.elename)
end
end
def rootnode
node = self
while node = node.parent
@ -399,7 +407,7 @@ public
def to_s()
str = ''
self.each do |key, data|
str << "#{ key }: #{ data }\n"
str << "#{key}: #{data}\n"
end
str
end
@ -442,6 +450,25 @@ public
@array
end
def to_obj
hash = {}
proptype = {}
each do |k, v|
value = v.respond_to?(:to_obj) ? v.to_obj : v.to_s
case proptype[k]
when :single
hash[k] = [hash[k], value]
proptype[k] = :multi
when :multi
hash[k] << value
else
hash[k] = value
proptype[k] = :single
end
end
hash
end
def each
for i in 0..(@array.length - 1)
yield(@array[i], @data[i])
@ -509,6 +536,10 @@ class SOAPElement
@text = text
end
def inspect
sprintf("#<%s:0x%x %s>", self.class.name, __id__, self.elename)
end
# Text interface.
attr_accessor :text
alias data text
@ -548,8 +579,19 @@ class SOAPElement
@text
else
hash = {}
proptype = {}
each do |k, v|
hash[k] = v.is_a?(SOAPElement) ? v.to_obj : v.to_s
value = v.respond_to?(:to_obj) ? v.to_obj : v.to_s
case proptype[k]
when :single
hash[k] = [hash[k], value]
proptype[k] = :multi
when :multi
hash[k] << value
else
hash[k] = value
proptype[k] = :single
end
end
hash
end
@ -566,20 +608,41 @@ class SOAPElement
o
end
def self.from_obj(hash_or_string)
def self.from_obj(obj, namespace = nil)
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 = k.is_a?(XSD::QName) ? k : XSD::QName.new(nil, k.to_s)
case obj
when nil
o.text = nil
when Hash
obj.each do |elename, value|
if value.is_a?(Array)
value.each do |subvalue|
child = from_obj(subvalue, namespace)
child.elename = to_elename(elename, namespace)
o.add(child)
end
else
o.text = hash_or_string
child = from_obj(value, namespace)
child.elename = to_elename(elename, namespace)
o.add(child)
end
end
else
o.text = obj.to_s
end
o
end
def self.to_elename(obj, namespace = nil)
if obj.is_a?(XSD::QName)
obj
elsif /\A(.+):([^:]+)\z/ =~ obj.to_s
XSD::QName.new($1, $2)
else
XSD::QName.new(namespace, obj.to_s)
end
end
private
def add_member(name, value)
@ -590,18 +653,32 @@ private
value
end
if RUBY_VERSION > "1.7.0"
def add_accessor(name)
methodname = name
if self.respond_to?(methodname)
methodname = safe_accessor_name(methodname)
end
sclass = class << self; self; end
sclass.__send__(:define_method, methodname, proc {
Mapping.define_singleton_method(self, methodname) do
@data[@array.index(name)]
})
sclass.__send__(:define_method, methodname + '=', proc { |value|
end
Mapping.define_singleton_method(self, methodname + '=') do |value|
@data[@array.index(name)] = value
})
end
end
else
def add_accessor(name)
methodname = safe_accessor_name(name)
instance_eval <<-EOS
def #{methodname}
@data[@array.index(#{name.dump})]
end
def #{methodname}=(value)
@data[@array.index(#{name.dump})] = value
end
EOS
end
end
def safe_accessor_name(name)
@ -624,7 +701,7 @@ public
def initialize(type = nil, rank = 1, arytype = nil)
super()
@type = type || XSD::QName.new
@type = type || ValueArrayName
@rank = rank
@data = Array.new
@sparse = false
@ -646,7 +723,7 @@ public
def [](*idxary)
if idxary.size != @rank
raise ArgumentError.new("Given #{ idxary.size } params does not match rank: #{ @rank }")
raise ArgumentError.new("given #{idxary.size} params does not match rank: #{@rank}")
end
retrieve(idxary)
@ -656,7 +733,8 @@ public
value = idxary.slice!(-1)
if idxary.size != @rank
raise ArgumentError.new("Given #{ idxary.size } params(#{ idxary }) does not match rank: #{ @rank }")
raise ArgumentError.new("given #{idxary.size} params(#{idxary})" +
" does not match rank: #{@rank}")
end
for i in 0..(idxary.size - 1)
@ -836,7 +914,7 @@ public
private
def self.create_arytype(typename, rank)
"#{ typename }[" << ',' * (rank - 1) << ']'
"#{typename}[" << ',' * (rank - 1) << ']'
end
TypeParseRegexp = Regexp.new('^(.+)\[([\d,]*)\]$')

View file

@ -1,5 +1,5 @@
# SOAP4R - SOAP elements library
# Copyright (C) 2000, 2001, 2003, 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2000, 2001, 2003-2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -99,7 +99,15 @@ class SOAPBody < SOAPStruct
super(nil)
@elename = EleBodyName
@encodingstyle = nil
add(data.elename.name, data) if data
if data
if data.respond_to?(:elename)
add(data.elename.name, data)
else
data.to_a.each do |datum|
add(datum.elename.name, datum)
end
end
end
@is_fault = is_fault
end
@ -129,7 +137,7 @@ class SOAPBody < SOAPStruct
end
end
raise SOAPParser::FormatDecodeError.new('No root element.')
raise Parser::FormatDecodeError.new('no root element')
end
end
@ -231,8 +239,7 @@ class SOAPEnvelope < XSD::NSDBase
end
def encode(generator, ns, attrs = {})
SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace,
SOAPNamespaceTag)
SOAPGenerator.assign_ns(attrs, ns, EnvelopeNamespace, SOAPNamespaceTag)
name = ns.name(@elename)
generator.encode_tag(name, attrs)

View file

@ -1,5 +1,5 @@
# SOAP4R - ASP.NET EncodingStyle handler library
# Copyright (C) 2001, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -30,7 +30,7 @@ class ASPDotNetHandler < Handler
def encode_data(generator, ns, qualified, data, parent)
attrs = {}
name = if qualified and data.elename.namespace
SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace)
SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace, '')
ns.name(data.elename)
else
data.elename.name
@ -61,8 +61,8 @@ class ASPDotNetHandler < Handler
yield(child, true)
end
else
raise EncodingStyleError.new("Unknown object:#{ data } in this encodingSt
yle.")
raise EncodingStyleError.new(
"unknown object:#{data} in this encodingStyle")
end
end
@ -119,7 +119,6 @@ yle.")
end
def decode_tag(ns, elename, attrs, parent)
# ToDo: check if @textbuf is empty...
@textbuf = ''
o = SOAPUnknown.new(self, elename)
o.parent = parent
@ -190,11 +189,11 @@ yle.")
end
when SOAPBasetype
raise EncodingStyleError.new("SOAP base type must not have a child.")
raise EncodingStyleError.new("SOAP base type must not have a child")
else
# SOAPUnknown does not have parent.
# raise EncodingStyleError.new("Illegal parent: #{ parent }.")
# raise EncodingStyleError.new("illegal parent: #{parent}")
end
end

View file

@ -1,5 +1,5 @@
# SOAP4R - XML Literal EncodingStyle handler library
# Copyright (C) 2001, 2003, 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2001, 2003-2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -29,11 +29,22 @@ class LiteralHandler < Handler
def encode_data(generator, ns, qualified, data, parent)
attrs = {}
name = if qualified and data.elename.namespace
SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace)
SOAPGenerator.assign_ns(attrs, ns, data.elename.namespace, '')
ns.name(data.elename)
else
data.elename.name
end
data.extraattr.each do |k, v|
if k.is_a?(XSD::QName)
if k.namespace
SOAPGenerator.assign_ns(attrs, ns, k.namespace)
k = ns.name(k)
else
k = k.name
end
end
attrs[k] = v
end
case data
when SOAPRawString
@ -62,13 +73,14 @@ class LiteralHandler < Handler
yield(child, true)
end
when SOAPElement
generator.encode_tag(name, attrs.update(data.extraattr))
generator.encode_tag(name, attrs)
generator.encode_rawstring(data.text) if data.text
data.each do |key, value|
yield(value, qualified)
end
else
raise EncodingStyleError.new("Unknown object:#{ data } in this encodingStyle.")
raise EncodingStyleError.new(
"unknown object:#{data} in this encodingStyle")
end
end
@ -78,7 +90,8 @@ class LiteralHandler < Handler
else
data.elename.name
end
cr = data.is_a?(SOAPElement) && !data.text
cr = (data.is_a?(SOAPCompoundtype) or
(data.is_a?(SOAPElement) and !data.text))
generator.encode_tag_end(name, cr)
end
@ -128,7 +141,6 @@ class LiteralHandler < Handler
end
def decode_tag(ns, elename, attrs, parent)
# ToDo: check if @textbuf is empty...
@textbuf = ''
o = SOAPUnknown.new(self, elename, decode_attrs(ns, attrs))
o.parent = parent
@ -172,21 +184,19 @@ class LiteralHandler < Handler
end
def decode_parent(parent, node)
return unless parent.node
case parent.node
when SOAPUnknown
newparent = parent.node.as_element
node.parent = newparent
parent.replace_node(newparent)
decode_parent(parent, node)
when SOAPElement
parent.node.add(node)
node.parent = parent.node
when SOAPStruct
parent.node.add(node.elename.name, node)
node.parent = parent.node
when SOAPArray
if node.position
parent.node[*(decode_arypos(node.position))] = node
@ -195,13 +205,8 @@ class LiteralHandler < Handler
parent.node.add(node)
end
node.parent = parent.node
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 }.")
raise EncodingStyleError.new("illegal parent: #{parent.node}")
end
end

View file

@ -1,5 +1,5 @@
# SOAP4R - SOAP EncodingStyle handler library
# Copyright (C) 2001, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2001, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -33,7 +33,7 @@ class SOAPHandler < Handler
attrs = encode_attrs(generator, ns, data, parent)
if parent && parent.is_a?(SOAPArray) && parent.position
attrs[ns.name(AttrPositionName)] = "[#{ parent.position.join(',') }]"
attrs[ns.name(AttrPositionName)] = "[#{parent.position.join(',')}]"
end
name = nil
@ -75,7 +75,7 @@ class SOAPHandler < Handler
end
else
raise EncodingStyleError.new(
"Unknown object:#{ data } in this encodingStyle.")
"unknown object:#{data} in this encodingStyle")
end
end
@ -156,7 +156,6 @@ class SOAPHandler < Handler
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)
@ -227,6 +226,7 @@ class SOAPHandler < Handler
end
def decode_parent(parent, node)
return unless parent.node
case parent.node
when SOAPUnknown
newparent = parent.node.as_struct
@ -247,10 +247,8 @@ class SOAPHandler < Handler
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 }.")
raise EncodingStyleError.new("illegal parent: #{parent.node}")
end
end
@ -266,7 +264,7 @@ private
def create_arytype(ns, data)
XSD::QName.new(data.arytype.namespace,
content_typename(data.arytype.name) + "[#{ data.size.join(',') }]")
content_typename(data.arytype.name) + "[#{data.size.join(',')}]")
end
def encode_attrs(generator, ns, data, parent)
@ -383,7 +381,7 @@ private
def decode_definedtype(elename, typename, typedef, arytypestr)
unless typedef
raise EncodingStyleError.new("Unknown type '#{ typename }'.")
raise EncodingStyleError.new("unknown type '#{typename}'")
end
if typedef.is_a?(::WSDL::XMLSchema::SimpleType)
decode_defined_simpletype(elename, typename, typedef, arytypestr)
@ -421,6 +419,10 @@ private
end
o.definedtype = typedef
return o
when :TYPE_EMPTY
o = SOAPNil.decode(elename)
o.definedtype = typedef
return o
else
raise RuntimeError.new(
"Unknown kind of complexType: #{typedef.compoundtype}")
@ -509,7 +511,7 @@ private
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').")
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
@ -523,7 +525,7 @@ private
when AttrRoot
root = RootLiteralMap[value] or
raise EncodingStyleError.new(
"Illegal root attribute value: #{ value }.")
"illegal root attribute value: #{value}")
next
when AttrOffset
offset = value
@ -578,7 +580,7 @@ private
ref.__setobj__(o)
false
else
raise EncodingStyleError.new("Unresolved reference: #{ ref.refid }.")
raise EncodingStyleError.new("unresolved reference: #{ref.refid}")
end
}
count -= 1

View file

@ -175,7 +175,12 @@ public
def self.assign_ns(attrs, ns, namespace, tag = nil)
if namespace and !ns.assigned?(namespace)
tag = ns.assign(namespace, tag)
attrs['xmlns:' << tag] = namespace
if tag == ''
attr = 'xmlns'
else
attr = "xmlns:#{tag}"
end
attrs[attr] = namespace
end
end

View file

@ -18,6 +18,12 @@ class HandlerSet
@store = XSD::NamedElements.new
end
def dup
obj = HandlerSet.new
obj.store = @store.dup
obj
end
def add(handler)
@store << handler
end
@ -51,6 +57,12 @@ class HandlerSet
end
end
end
protected
def store=(store)
@store = store
end
end

View file

@ -1,5 +1,5 @@
# SOAP4R - SOAP Simple header item handler
# Copyright (C) 2003, 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2003-2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -30,7 +30,7 @@ class SimpleHandler < SOAP::Header::Handler
def on_outbound
h = on_simple_outbound
h ? SOAPElement.from_obj(h) : nil
h ? SOAPElement.from_obj(h, elename.namespace) : nil
end
def on_inbound(header, mustunderstand)

View file

@ -37,22 +37,26 @@ class Factory
end
def setiv2soap(node, obj, map)
if obj.class.class_variables.include?('@@schema_element')
obj.class.class_eval('@@schema_element').each do |name, info|
type, qname = info
if qname
elename = qname.name
else
elename = Mapping.name2elename(name)
end
node.add(elename,
Mapping._obj2soap(obj.instance_variable_get('@' + name), map))
end
else
# should we sort instance_variables?
obj.instance_variables.each do |var|
name = var.sub(/^@/, '')
node.add(Mapping.name2elename(name),
elename = Mapping.name2elename(name)
node.add(elename,
Mapping._obj2soap(obj.instance_variable_get(var), map))
end
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
private
@ -68,7 +72,7 @@ private
node.each do |name, value|
vars[Mapping.elename2name(name)] = Mapping._soap2obj(value, map)
end
Mapping.set_instance_vars(obj, vars)
Mapping.set_attributes(obj, vars)
end
end
@ -156,20 +160,14 @@ class DateTimeFactory_ < Factory
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
if node.respond_to?(:to_obj)
obj = node.to_obj(obj_class)
return false if obj.nil?
mark_unmarshalled_obj(node, obj)
return true, obj
else
return false
end
mark_unmarshalled_obj(node, obj)
return true, obj
end
end

View file

@ -1,5 +1,5 @@
# SOAP4R - Ruby type mapping utility.
# Copyright (C) 2000, 2001, 2003, 2004 NAKAMURA Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2000, 2001, 2003-2005 NAKAMURA Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -23,10 +23,12 @@ module Mapping
# TraverseSupport breaks Thread.current[:SOAPMarshalDataKey].
module TraverseSupport
def mark_marshalled_obj(obj, soap_obj)
raise if obj.nil?
Thread.current[:SOAPMarshalDataKey][obj.__id__] = soap_obj
end
def mark_unmarshalled_obj(node, obj)
return if obj.nil?
# node.id is not Object#id but SOAPReference#id
Thread.current[:SOAPMarshalDataKey][node.id] = obj
end
@ -41,10 +43,10 @@ module Mapping
soap_obj
end
def self.soap2obj(node, registry = nil)
def self.soap2obj(node, registry = nil, klass = nil)
registry ||= Mapping::DefaultRegistry
Thread.current[:SOAPMarshalDataKey] = {}
obj = _soap2obj(node, registry)
obj = _soap2obj(node, registry, klass)
Thread.current[:SOAPMarshalDataKey] = nil
obj
end
@ -107,21 +109,21 @@ module Mapping
elsif registry
registry.obj2soap(obj, type)
else
raise MappingError.new("No mapping registry given.")
raise MappingError.new("no mapping registry given")
end
end
def self._soap2obj(node, registry)
def self._soap2obj(node, registry, klass = nil)
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)
return _soap2obj(target, registry, klass)
end
end
return registry.soap2obj(node)
return registry.soap2obj(node, klass)
end
if Object.respond_to?(:allocate)
@ -157,29 +159,6 @@ module Mapping
end
end
unless Object.respond_to?(:instance_variable_get)
class Object
def instance_variable_get(ivarname)
instance_eval(ivarname)
end
def instance_variable_set(ivarname, value)
instance_eval("#{ivarname} = value")
end
end
end
def self.set_instance_vars(obj, values)
values.each do |name, value|
setter = name + "="
if obj.respond_to?(setter)
obj.__send__(setter, value)
else
obj.instance_variable_set('@' + name, value)
end
end
end
# Allow only (Letter | '_') (Letter | Digit | '-' | '_')* here.
# Caution: '.' is not allowed here.
# To follow XML spec., it should be NCName.
@ -198,28 +177,51 @@ module Mapping
}
end
def self.class_from_name(name)
if /^[A-Z]/ !~ name
def self.const_from_name(name, lenient = false)
const = ::Object
name.sub(/\A::/, '').split('::').each do |const_str|
if XSD::CodeGen::GenSupport.safeconstname?(const_str)
if const.const_defined?(const_str)
const = const.const_get(const_str)
next
end
elsif lenient
const_str = XSD::CodeGen::GenSupport.safeconstname(const_str)
if const.const_defined?(const_str)
const = const.const_get(const_str)
next
end
end
return nil
end
klass = ::Object
name.split('::').each do |klass_str|
if klass.const_defined?(klass_str)
klass = klass.const_get(klass_str)
const
end
def self.class_from_name(name, lenient = false)
const = const_from_name(name, lenient)
if const.is_a?(::Class)
const
else
return nil
nil
end
end
klass
def self.module_from_name(name, lenient = false)
const = const_from_name(name, lenient)
if const.is_a?(::Module)
const
else
nil
end
end
def self.class2qname(klass)
name = if klass.class_variables.include?("@@schema_type")
name = if klass.class_variables.include?('@@schema_type')
klass.class_eval('@@schema_type')
else
nil
end
namespace = if klass.class_variables.include?("@@schema_ns")
namespace = if klass.class_variables.include?('@@schema_ns')
klass.class_eval('@@schema_ns')
else
nil
@ -250,19 +252,75 @@ module Mapping
end
end
def self.find_attribute(obj, attr_name)
def self.define_singleton_method(obj, name, &block)
sclass = (class << obj; self; end)
sclass.__send__(:define_method, name, &block)
end
def self.get_attribute(obj, attr_name)
if obj.is_a?(::Hash)
obj[attr_name] || obj[attr_name.intern]
else
name = ::XSD::CodeGen::GenSupport.safevarname(attr_name)
if obj.respond_to?(name)
obj.__send__(name)
else
name = XSD::CodeGen::GenSupport.safevarname(attr_name)
if obj.instance_variables.include?('@' + name)
obj.instance_variable_get('@' + name)
elsif ((obj.is_a?(::Struct) or obj.is_a?(Marshallable)) and
obj.respond_to?(name))
obj.__send__(name)
end
end
end
def self.set_attributes(obj, values)
if obj.is_a?(::SOAP::Mapping::Object)
values.each do |attr_name, value|
obj.__add_xmlele_value(attr_name, value)
end
else
values.each do |attr_name, value|
name = XSD::CodeGen::GenSupport.safevarname(attr_name)
setter = name + "="
if obj.respond_to?(setter)
obj.__send__(setter, value)
else
obj.instance_variable_set('@' + name, value)
begin
define_attr_accessor(obj, name,
proc { instance_variable_get('@' + name) },
proc { |value| instance_variable_set('@' + name, value) })
rescue TypeError
# singleton class may not exist (e.g. Float)
end
end
end
end
end
def self.define_attr_accessor(obj, name, getterproc, setterproc = nil)
define_singleton_method(obj, name, &getterproc)
define_singleton_method(obj, name + '=', &setterproc) if setterproc
end
def self.schema_element_definition(klass)
return nil unless klass.class_variables.include?('@@schema_element')
elements = {}
as_array = []
klass.class_eval('@@schema_element').each do |varname, definition|
class_name, name = definition
if /\[\]$/ =~ class_name
class_name = class_name.sub(/\[\]$/, '')
as_array << class_name
end
elements[name ? name.name : varname] = class_name
end
[elements, as_array]
end
def self.schema_attribute_definition(klass)
return nil unless klass.class_variables.include?('@@schema_attribute')
klass.class_eval('@@schema_attribute')
end
class << Mapping
private
def add_md_ary(md_ary, ary, indices, registry)

View file

@ -64,50 +64,105 @@ end
# For anyType object: SOAP::Mapping::Object not ::Object
class Object; include Marshallable
def initialize
@__soap_value_type = {}
@__soap_value = {}
@__xmlele_type = {}
@__xmlele = []
@__xmlattr = {}
end
def [](name)
@__soap_value[name]
def inspect
sprintf("#<%s:0x%x%s>", self.class.name, __id__,
@__xmlele.collect { |name, value| " #{name}=#{value.inspect}" }.join)
end
def []=(name, value)
@__soap_value[name] = value
def __xmlattr
@__xmlattr
end
def __soap_set_property(name, value)
unless @__soap_value.key?(name)
__define_attr_accessor(name)
end
__soap_set_property_value(name, value)
def __xmlele
@__xmlele
end
private
def [](qname)
unless qname.is_a?(XSD::QName)
qname = XSD::QName.new(nil, qname)
end
@__xmlele.each do |k, v|
return v if k == qname
end
nil
end
def __soap_set_property_value(name, value)
org = self[name]
case @__soap_value_type[name]
when :single
self[name] = [org, value]
@__soap_value_type[name] = :multi
when :multi
org << value
def []=(qname, value)
unless qname.is_a?(XSD::QName)
qname = XSD::QName.new(nil, qname)
end
found = false
@__xmlele.each do |pair|
if pair[0] == qname
found = true
pair[1] = value
end
end
unless found
__define_attr_accessor(qname)
@__xmlele << [qname, value]
end
@__xmlele_type[qname] = :single
end
def __add_xmlele_value(qname, value)
found = false
@__xmlele.map! do |k, v|
if k == qname
found = true
[k, __set_xmlele_value(k, v, value)]
else
self[name] = value
@__soap_value_type[name] = :single
[k, v]
end
end
unless found
__define_attr_accessor(qname)
@__xmlele << [qname, value]
@__xmlele_type[qname] = :single
end
value
end
def __define_attr_accessor(name)
sclass = class << self; self; end
sclass.__send__(:define_method, name, proc {
self[name]
})
sclass.__send__(:define_method, name + '=', proc { |value|
self[name] = value
})
private
if RUBY_VERSION > "1.7.0"
def __define_attr_accessor(qname)
name = XSD::CodeGen::GenSupport.safemethodname(qname.name)
Mapping.define_attr_accessor(self, name,
proc { self[qname] },
proc { |value| self[qname] = value })
end
else
def __define_attr_accessor(qname)
name = XSD::CodeGen::GenSupport.safemethodname(qname.name)
instance_eval <<-EOS
def #{name}
self[#{qname.dump}]
end
def #{name}=(value)
self[#{qname.dump}] = value
end
EOS
end
end
def __set_xmlele_value(key, org, value)
case @__xmlele_type[key]
when :multi
org << value
org
when :single
@__xmlele_type[key] = :multi
[org, value]
else
raise RuntimeError.new("unknown type")
end
end
end
@ -123,7 +178,7 @@ class Registry
@registry = registry
end
def obj2soap(obj, type_qname = nil)
def obj2soap(obj)
klass = obj.class
if map = @obj2soap[klass]
map.each do |soap_class, factory, info|
@ -131,7 +186,10 @@ class Registry
return ret if ret
end
end
ancestors = klass.ancestors[1..-3] # except itself, Object and Kernel
ancestors = klass.ancestors
ancestors.delete(klass)
ancestors.delete(::Object)
ancestors.delete(::Kernel)
ancestors.each do |klass|
if map = @obj2soap[klass]
map.each do |soap_class, factory, info|
@ -145,10 +203,10 @@ class Registry
nil
end
def soap2obj(node)
klass = node.class
if map = @soap2obj[klass]
def soap2obj(node, klass = nil)
if map = @soap2obj[node.class]
map.each do |obj_class, factory, info|
next if klass and obj_class != klass
conv, obj = factory.soap2obj(obj_class, node, info, @registry)
return true, obj if conv
end
@ -177,11 +235,13 @@ class Registry
end
def find_mapped_soap_class(target_obj_class)
@obj2soap[target_obj_class][0]
map = @obj2soap[target_obj_class]
map.empty? ? nil : map[0][1]
end
def find_mapped_obj_class(target_soap_class)
@soap2obj[target_soap_class][0]
map = @soap2obj[target_soap_class]
map.empty? ? nil : map[0][0]
end
end
@ -202,7 +262,6 @@ class Registry
[::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
[::String, ::SOAP::SOAPString, StringFactory],
[::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Date, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Date, ::SOAP::SOAPDate, DateTimeFactory],
[::Time, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Time, ::SOAP::SOAPTime, DateTimeFactory],
@ -266,7 +325,6 @@ class Registry
[::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
[::String, ::SOAP::SOAPString, StringFactory],
[::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Date, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Date, ::SOAP::SOAPDate, DateTimeFactory],
[::Time, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Time, ::SOAP::SOAPTime, DateTimeFactory],
@ -354,17 +412,17 @@ class Registry
end
alias set add
# This mapping registry ignores type hint.
# general Registry ignores type_qname
def obj2soap(obj, type_qname = nil)
soap = _obj2soap(obj, type_qname)
soap = _obj2soap(obj)
if @allow_original_mapping
addextend2soap(soap, obj)
end
soap
end
def soap2obj(node)
obj = _soap2obj(node)
def soap2obj(node, klass = nil)
obj = _soap2obj(node, klass)
if @allow_original_mapping
addextend2obj(obj, node.extraattr[RubyExtendName])
addiv2obj(obj, node.extraattr[RubyIVarName])
@ -382,7 +440,7 @@ class Registry
private
def _obj2soap(obj, type_qname)
def _obj2soap(obj)
ret = nil
if obj.is_a?(SOAPStruct) or obj.is_a?(SOAPArray)
obj.replace do |ele|
@ -393,7 +451,7 @@ private
return obj
end
begin
ret = @map.obj2soap(obj, type_qname) ||
ret = @map.obj2soap(obj) ||
@default_factory.obj2soap(nil, obj, nil, self)
return ret if ret
rescue MappingError
@ -408,12 +466,12 @@ private
end
# Might return nil as a mapping result.
def _soap2obj(node)
def _soap2obj(node, klass = nil)
if node.extraattr.key?(RubyTypeName)
conv, obj = @rubytype_factory.soap2obj(nil, node, nil, self)
return obj if conv
else
conv, obj = @map.soap2obj(node)
conv, obj = @map.soap2obj(node, klass)
return obj if conv
conv, obj = @default_factory.soap2obj(nil, node, nil, self)
return obj if conv
@ -435,14 +493,14 @@ private
attr.__getobj__.each do |name, value|
vars[name] = Mapping._soap2obj(value, self)
end
Mapping.set_instance_vars(obj, vars)
Mapping.set_attributes(obj, vars)
end
if RUBY_VERSION >= '1.8.0'
def addextend2obj(obj, attr)
return unless attr
attr.split(/ /).reverse_each do |mstr|
obj.extend(Mapping.class_from_name(mstr))
obj.extend(Mapping.module_from_name(mstr))
end
end
else
@ -450,8 +508,8 @@ private
def addextend2obj(obj, attr)
return unless attr
attr.split(/ /).reverse_each do |mstr|
m = Mapping.class_from_name(mstr)
obj.extend(m) if m.class == Module
m = Mapping.module_from_name(mstr)
obj.extend(m)
end
end
end

View file

@ -1,5 +1,5 @@
# SOAP4R - Ruby type mapping factory.
# Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -168,7 +168,7 @@ class RubytypeFactory < Factory
return nil
end
if obj.to_s[0] == ?#
raise TypeError.new("can't dump anonymous class #{ obj }")
raise TypeError.new("can't dump anonymous class #{obj}")
end
param = SOAPStruct.new(TYPE_CLASS)
mark_marshalled_obj(obj, param)
@ -179,7 +179,7 @@ class RubytypeFactory < Factory
return nil
end
if obj.to_s[0] == ?#
raise TypeError.new("can't dump anonymous module #{ obj }")
raise TypeError.new("can't dump anonymous module #{obj}")
end
param = SOAPStruct.new(TYPE_MODULE)
mark_marshalled_obj(obj, param)
@ -222,7 +222,12 @@ class RubytypeFactory < Factory
when ::SOAP::Mapping::Object
param = SOAPStruct.new(XSD::AnyTypeName)
mark_marshalled_obj(obj, param)
addiv2soapattr(param, obj, map)
obj.__xmlele.each do |key, value|
param.add(key.name, Mapping._obj2soap(value, map))
end
obj.__xmlattr.each do |key, value|
param.extraattr[key] = value
end
when ::Exception
typestr = Mapping.name2elename(obj.class.to_s)
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, typestr))
@ -258,12 +263,12 @@ private
def unknownobj2soap(soap_class, obj, info, map)
if obj.class.name.empty?
raise TypeError.new("can't dump anonymous class #{ obj }")
raise TypeError.new("can't dump anonymous class #{obj}")
end
singleton_class = class << obj; self; end
if !singleton_methods_true(obj).empty? or
!singleton_class.instance_variables.empty?
raise TypeError.new("singleton can't be dumped #{ obj }")
raise TypeError.new("singleton can't be dumped #{obj}")
end
if !(singleton_class.ancestors - obj.class.ancestors).empty?
typestr = Mapping.name2elename(obj.class.to_s)
@ -378,7 +383,11 @@ private
obj = klass.new
mark_unmarshalled_obj(node, obj)
node.each do |name, value|
obj.__soap_set_property(name, Mapping._soap2obj(value, map))
obj.__add_xmlele_value(XSD::QName.new(nil, name),
Mapping._soap2obj(value, map))
end
unless node.extraattr.empty?
obj.instance_variable_set('@__xmlattr', node.extraattr)
end
return true, obj
else
@ -387,7 +396,12 @@ private
end
def unknowntype2obj(node, info, map)
if node.is_a?(SOAPStruct)
case node
when SOAPBasetype
return true, node.data
when SOAPArray
return @array_factory.soap2obj(Array, node, info, map)
when SOAPStruct
obj = unknownstruct2obj(node, info, map)
return true, obj if obj
if !@allow_untyped_struct
@ -406,6 +420,9 @@ private
end
typestr = Mapping.elename2name(node.type.name)
klass = Mapping.class_from_name(typestr)
if klass.nil? and @allow_untyped_struct
klass = Mapping.class_from_name(typestr, true) # lenient
end
if klass.nil?
return nil
end
@ -414,7 +431,13 @@ private
end
klass_type = Mapping.class2qname(klass)
return nil unless node.type.match(klass_type)
obj = nil
begin
obj = Mapping.create_empty_object(klass)
rescue
# type name "data" tries Data.new which raises TypeError
nil
end
mark_unmarshalled_obj(node, obj)
setiv2obj(obj, node, map)
obj

View file

@ -1,11 +1,13 @@
# SOAP4R - WSDL encoded mapping registry.
# Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
# either the dual license version in 2003, or any later version.
require 'xsd/qname'
require 'xsd/namedelements'
require 'soap/baseData'
require 'soap/mapping/mapping'
require 'soap/mapping/typeMap'
@ -15,35 +17,33 @@ module SOAP
module Mapping
class WSDLEncodedRegistry
class WSDLEncodedRegistry < Registry
include TraverseSupport
attr_reader :definedelements
attr_reader :definedtypes
attr_accessor :excn_handler_obj2soap
attr_accessor :excn_handler_soap2obj
def initialize(definedtypes, config = {})
def initialize(definedtypes = XSD::NamedElements::Empty)
@definedtypes = definedtypes
@config = config
# @definedelements = definedelements needed?
@excn_handler_obj2soap = nil
@excn_handler_soap2obj = nil
# For mapping AnyType element.
@rubytype_factory = RubytypeFactory.new(
:allow_untyped_struct => true,
:allow_original_mapping => true
)
@schema_element_cache = {}
end
def obj2soap(obj, type_qname = nil)
def obj2soap(obj, qname = nil)
soap_obj = nil
if obj.nil?
soap_obj = SOAPNil.new
elsif type_qname.nil? or type_qname == XSD::AnyTypeName
soap_obj = @rubytype_factory.obj2soap(nil, obj, nil, self)
elsif obj.is_a?(XSD::NSDBase)
soap_obj = soap2soap(obj, type_qname)
elsif type = @definedtypes[type_qname]
soap_obj = obj2type(obj, type)
elsif (type = TypeMap[type_qname])
soap_obj = base2soap(obj, type)
if type = @definedtypes[qname]
soap_obj = obj2typesoap(obj, type)
else
soap_obj = any2soap(obj, qname)
end
return soap_obj if soap_obj
if @excn_handler_obj2soap
@ -52,15 +52,46 @@ class WSDLEncodedRegistry
}
return soap_obj if soap_obj
end
raise MappingError.new("Cannot map #{ obj.class.name } to SOAP/OM.")
if qname
raise MappingError.new("cannot map #{obj.class.name} as #{qname}")
else
raise MappingError.new("cannot map #{obj.class.name} to SOAP/OM")
end
end
def soap2obj(node)
raise RuntimeError.new("#{ self } is for obj2soap only.")
# map anything for now: must refer WSDL while mapping. [ToDo]
def soap2obj(node, obj_class = nil)
begin
return any2obj(node, obj_class)
rescue MappingError
end
if @excn_handler_soap2obj
begin
return @excn_handler_soap2obj.call(node) { |yield_node|
Mapping._soap2obj(yield_node, self)
}
rescue Exception
end
end
raise MappingError.new("cannot map #{node.type.name} to Ruby object")
end
private
def any2soap(obj, qname)
if obj.nil?
SOAPNil.new
elsif qname.nil? or qname == XSD::AnyTypeName
@rubytype_factory.obj2soap(nil, obj, nil, self)
elsif obj.is_a?(XSD::NSDBase)
soap2soap(obj, qname)
elsif (type = TypeMap[qname])
base2soap(obj, type)
else
nil
end
end
def soap2soap(obj, type_qname)
if obj.is_a?(SOAPBasetype)
obj
@ -82,25 +113,22 @@ private
end
end
def obj2type(obj, type)
def obj2typesoap(obj, type)
if type.is_a?(::WSDL::XMLSchema::SimpleType)
simple2soap(obj, type)
simpleobj2soap(obj, type)
else
complex2soap(obj, type)
complexobj2soap(obj, type)
end
end
def simple2soap(obj, type)
o = base2soap(obj, TypeMap[type.base])
if type.restriction.enumeration.empty?
STDERR.puts("#{type.name}: simpleType which is not enum type not supported.")
return o
end
def simpleobj2soap(obj, type)
type.check_lexical_format(obj)
return SOAPNil.new if obj.nil? # ToDo: check nillable.
o = base2soap(obj, TypeMap[type.base])
o
end
def complex2soap(obj, type)
def complexobj2soap(obj, type)
case type.compoundtype
when :TYPE_STRUCT
struct2soap(obj, type.name, type)
@ -108,8 +136,13 @@ private
array2soap(obj, type.name, type)
when :TYPE_MAP
map2soap(obj, type.name, type)
when :TYPE_SIMPLE
simpleobj2soap(obj, type.simplecontent)
when :TYPE_EMPTY
raise MappingError.new("should be empty") unless obj.nil?
SOAPNil.new
else
raise MappingError.new("Unknown compound type: #{ type.compoundtype }")
raise MappingError.new("unknown compound type: #{type.compoundtype}")
end
end
@ -126,28 +159,36 @@ private
end
def struct2soap(obj, type_qname, type)
return SOAPNil.new if obj.nil? # ToDo: check nillable.
soap_obj = SOAPStruct.new(type_qname)
unless obj.nil?
mark_marshalled_obj(obj, soap_obj)
elements2soap(obj, soap_obj, type.content.elements)
end
soap_obj
end
def array2soap(obj, type_qname, type)
return SOAPNil.new if obj.nil? # ToDo: check nillable.
arytype = type.child_type
soap_obj = SOAPArray.new(ValueArrayName, 1, arytype)
unless obj.nil?
mark_marshalled_obj(obj, soap_obj)
obj.each do |item|
soap_obj.add(Mapping._obj2soap(item, self, arytype))
end
end
soap_obj
end
MapKeyName = XSD::QName.new(nil, "key")
MapValueName = XSD::QName.new(nil, "value")
def map2soap(obj, type_qname, type)
return SOAPNil.new if obj.nil? # ToDo: check nillable.
keytype = type.child_type(MapKeyName) || XSD::AnyTypeName
valuetype = type.child_type(MapValueName) || XSD::AnyTypeName
soap_obj = SOAPStruct.new(MapQName)
unless obj.nil?
mark_marshalled_obj(obj, soap_obj)
obj.each do |key, value|
elem = SOAPStruct.new
@ -156,16 +197,71 @@ private
# ApacheAxis allows only 'item' here.
soap_obj.add("item", elem)
end
end
soap_obj
end
def elements2soap(obj, soap_obj, elements)
elements.each do |element|
name = element.name.name
child_obj = obj.instance_variable_get('@' + name)
soap_obj.add(name, Mapping._obj2soap(child_obj, self, element.type))
child_obj = Mapping.get_attribute(obj, name)
soap_obj.add(name,
Mapping._obj2soap(child_obj, self, element.type || element.name))
end
end
def any2obj(node, obj_class)
unless obj_class
typestr = XSD::CodeGen::GenSupport.safeconstname(node.elename.name)
obj_class = Mapping.class_from_name(typestr)
end
if obj_class and obj_class.class_variables.include?('@@schema_element')
soap2stubobj(node, obj_class)
else
Mapping._soap2obj(node, Mapping::DefaultRegistry, obj_class)
end
end
def soap2stubobj(node, obj_class)
obj = Mapping.create_empty_object(obj_class)
unless node.is_a?(SOAPNil)
add_elements2stubobj(node, obj)
end
obj
end
def add_elements2stubobj(node, obj)
elements, as_array = schema_element_definition(obj.class)
vars = {}
node.each do |name, value|
if class_name = elements[name]
if klass = Mapping.class_from_name(class_name)
# klass must be a SOAPBasetype or a class
if klass.ancestors.include?(::SOAP::SOAPBasetype)
if value.respond_to?(:data)
child = klass.new(value.data).data
else
child = klass.new(nil).data
end
else
child = Mapping._soap2obj(value, self, klass)
end
else
raise MappingError.new("unknown class: #{class_name}")
end
else # untyped element is treated as anyType.
child = Mapping._soap2obj(value, self)
end
vars[name] = child
end
Mapping.set_attributes(obj, vars)
end
# it caches @@schema_element. this means that @@schema_element must not be
# changed while a lifetime of a WSDLLiteralRegistry.
def schema_element_definition(klass)
@schema_element_cache[klass] ||= Mapping.schema_element_definition(klass)
end
end

View file

@ -1,5 +1,5 @@
# SOAP4R - WSDL literal mapping registry.
# Copyright (C) 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2004, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -10,48 +10,55 @@ require 'soap/baseData'
require 'soap/mapping/mapping'
require 'soap/mapping/typeMap'
require 'xsd/codegen/gensupport'
require 'xsd/namedelements'
module SOAP
module Mapping
class WSDLLiteralRegistry
class WSDLLiteralRegistry < Registry
attr_reader :definedelements
attr_reader :definedtypes
attr_accessor :excn_handler_obj2soap
attr_accessor :excn_handler_soap2obj
def initialize(definedelements = nil, definedtypes = nil)
@definedelements = definedelements
def initialize(definedtypes = XSD::NamedElements::Empty,
definedelements = XSD::NamedElements::Empty)
@definedtypes = definedtypes
@rubytype_factory = RubytypeFactory.new(:allow_original_mapping => false)
@definedelements = definedelements
@excn_handler_obj2soap = nil
@excn_handler_soap2obj = nil
@schema_element_cache = {}
@schema_attribute_cache = {}
end
def obj2soap(obj, qname)
ret = nil
if !@definedelements.nil? && ele = @definedelements[qname]
ret = _obj2soap(obj, ele)
elsif !@definedtypes.nil? && type = @definedtypes[qname]
ret = obj2type(obj, type)
soap_obj = nil
if ele = @definedelements[qname]
soap_obj = obj2elesoap(obj, ele)
elsif type = @definedtypes[qname]
soap_obj = obj2typesoap(obj, type)
else
ret = unknownobj2soap(obj, qname)
soap_obj = any2soap(obj, qname)
end
return ret if ret
return soap_obj if soap_obj
if @excn_handler_obj2soap
ret = @excn_handler_obj2soap.call(obj) { |yield_obj|
soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj|
Mapping._obj2soap(yield_obj, self)
}
return ret if ret
return soap_obj if soap_obj
end
raise MappingError.new("Cannot map #{ obj.class.name } to SOAP/OM.")
raise MappingError.new("cannot map #{obj.class.name} as #{qname}")
end
# node should be a SOAPElement
def soap2obj(node)
def soap2obj(node, obj_class = nil)
unless obj_class.nil?
raise MappingError.new("must not reach here")
end
begin
return soapele2obj(node)
return any2obj(node)
rescue MappingError
end
if @excn_handler_soap2obj
@ -62,84 +69,136 @@ class WSDLLiteralRegistry
rescue Exception
end
end
raise MappingError.new("Cannot map #{ node.type.name } to Ruby object.")
raise MappingError.new("cannot map #{node.type.name} to Ruby object")
end
private
def _obj2soap(obj, ele)
def obj2elesoap(obj, ele)
o = nil
if ele.type
if type = @definedtypes[ele.type]
o = obj2type(obj, type)
o = obj2typesoap(obj, type)
elsif type = TypeMap[ele.type]
o = base2soap(obj, type)
else
raise MappingError.new("Cannot find type #{ele.type}.")
raise MappingError.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_ele|
o.add(_obj2soap(Mapping.find_attribute(obj, child_ele.name.name),
child_ele))
end
o = obj2typesoap(obj, ele.local_complextype)
o.elename = ele.name
add_attributes2soap(obj, o)
elsif ele.local_simpletype
o = obj2typesoap(obj, ele.local_simpletype)
o.elename = ele.name
else
raise MappingError.new('Illegal schema?')
raise MappingError.new('illegal schema?')
end
o
end
def obj2type(obj, type)
def obj2typesoap(obj, type)
if type.is_a?(::WSDL::XMLSchema::SimpleType)
simple2soap(obj, type)
simpleobj2soap(obj, type)
else
complex2soap(obj, type)
complexobj2soap(obj, type)
end
end
def simple2soap(obj, type)
o = base2soap(obj, TypeMap[type.base])
if type.restriction.enumeration.empty?
STDERR.puts(
"#{type.name}: simpleType which is not enum type not supported.")
return o
end
def simpleobj2soap(obj, type)
type.check_lexical_format(obj)
return SOAPNil.new if obj.nil? # ToDo: check nillable.
o = base2soap(obj, TypeMap[type.base])
o
end
def complex2soap(obj, type)
def complexobj2soap(obj, type)
o = SOAPElement.new(type.name)
type.each_element do |child_ele|
o.add(_obj2soap(Mapping.find_attribute(obj, child_ele.name.name),
child_ele))
child = Mapping.get_attribute(obj, child_ele.name.name)
if child.nil?
if child_ele.nillable
# ToDo: test
# add empty element
o.add(obj2elesoap(nil))
elsif Integer(child_ele.minoccurs) == 0
# nothing to do
else
raise MappingError.new("nil not allowed: #{child_ele.name.name}")
end
elsif child_ele.map_as_array?
child.each do |item|
o.add(obj2elesoap(item, child_ele))
end
else
o.add(obj2elesoap(child, child_ele))
end
end
o
end
def unknownobj2soap(obj, name)
if obj.class.class_variables.include?('@@schema_element')
ele = SOAPElement.new(name)
def any2soap(obj, qname)
if obj.is_a?(SOAPElement)
obj
elsif obj.class.class_variables.include?('@@schema_element')
stubobj2soap(obj, qname)
elsif obj.is_a?(SOAP::Mapping::Object)
mappingobj2soap(obj, qname)
elsif obj.is_a?(Hash)
ele = SOAPElement.from_obj(obj)
ele.elename = qname
ele
else
# expected to be a basetype or an anyType.
# SOAPStruct, etc. is used instead of SOAPElement.
begin
ele = Mapping.obj2soap(obj)
ele.elename = qname
ele
rescue MappingError
ele = SOAPElement.new(qname, obj.to_s)
end
if obj.respond_to?(:__xmlattr)
obj.__xmlattr.each do |key, value|
ele.extraattr[key] = value
end
end
ele
end
end
def stubobj2soap(obj, qname)
ele = SOAPElement.new(qname)
add_elements2soap(obj, ele)
add_attributes2soap(obj, ele)
ele
elsif obj.is_a?(Hash)
ele = SOAPElement.from_obj(obj)
ele.elename = name
ele
else # expected to be a basetype or an anyType.
o = Mapping.obj2soap(obj)
o.elename = name
o
end
def mappingobj2soap(obj, qname)
ele = SOAPElement.new(qname)
obj.__xmlele.each do |key, value|
if value.is_a?(::Array)
value.each do |item|
ele.add(obj2soap(item, key))
end
else
ele.add(obj2soap(value, key))
end
end
obj.__xmlattr.each do |key, value|
ele.extraattr[key] = value
end
ele
end
def add_elements2soap(obj, ele)
elements, as_array = schema_element_definition(obj.class)
if elements
elements.each do |elename, type|
child = Mapping.find_attribute(obj, elename)
name = ::XSD::QName.new(nil, elename)
child = Mapping.get_attribute(obj, elename)
unless child.nil?
name = XSD::QName.new(nil, elename)
if as_array.include?(type)
child.each do |item|
ele.add(obj2soap(item, name))
@ -149,21 +208,25 @@ private
end
end
end
end
end
def add_attributes2soap(obj, ele)
attributes = schema_attribute_definition(obj.class)
attributes.each do |attrname, param|
attr = Mapping.find_attribute(obj, 'attr_' + attrname)
ele.extraattr[attrname] = attr
if attributes
attributes.each do |qname, param|
attr = obj.__send__('xmlattr_' +
XSD::CodeGen::GenSupport.safevarname(qname.name))
ele.extraattr[qname] = attr
end
end
end
def base2soap(obj, type)
soap_obj = nil
if type <= ::XSD::XSDString
soap_obj = type.new(::XSD::Charset.is_ces(obj, $KCODE) ?
::XSD::Charset.encoding_conv(obj, $KCODE, ::XSD::Charset.encoding) :
obj)
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
@ -176,35 +239,41 @@ private
end
klass = ::SOAP::Mapping::Object
obj = klass.new
node.each do |name, value|
obj.__soap_set_property(name, Mapping.soap2obj(value))
end
obj
end
def soapele2obj(node, obj_class = nil)
def any2obj(node, obj_class = nil)
unless obj_class
typestr = ::XSD::CodeGen::GenSupport.safeconstname(node.elename.name)
typestr = XSD::CodeGen::GenSupport.safeconstname(node.elename.name)
obj_class = Mapping.class_from_name(typestr)
end
if obj_class and obj_class.class_variables.include?('@@schema_element')
soapele2definedobj(node, obj_class)
elsif node.is_a?(SOAPElement)
node.to_obj
soapele2stubobj(node, obj_class)
elsif node.is_a?(SOAPElement) or node.is_a?(SOAPStruct)
# SOAPArray for literal?
soapele2plainobj(node)
else
result, obj = @rubytype_factory.soap2obj(nil, node, nil, self)
obj = Mapping._soap2obj(node, Mapping::DefaultRegistry, obj_class)
add_attributes2plainobj(node, obj)
obj
end
end
def soapele2definedobj(node, obj_class)
def soapele2stubobj(node, obj_class)
obj = Mapping.create_empty_object(obj_class)
add_elements2obj(node, obj)
add_attributes2obj(node, obj)
add_elements2stubobj(node, obj)
add_attributes2stubobj(node, obj)
obj
end
def add_elements2obj(node, obj)
def soapele2plainobj(node)
obj = anytype2obj(node)
add_elements2plainobj(node, obj)
add_attributes2plainobj(node, obj)
obj
end
def add_elements2stubobj(node, obj)
elements, as_array = schema_element_definition(obj.class)
vars = {}
node.each do |name, value|
@ -217,13 +286,13 @@ private
child = klass.new(nil).data
end
else
child = soapele2obj(value, klass)
child = any2obj(value, klass)
end
else
raise MappingError.new("Unknown class: #{class_name}")
raise MappingError.new("unknown class: #{class_name}")
end
else # untyped element is treated as anyType.
child = anytype2obj(value)
child = any2obj(value)
end
if as_array.include?(class_name)
(vars[name] ||= []) << child
@ -231,15 +300,14 @@ private
vars[name] = child
end
end
Mapping.set_instance_vars(obj, vars)
Mapping.set_attributes(obj, vars)
end
def add_attributes2obj(node, obj)
Mapping.set_instance_vars(obj, {'__soap_attribute' => {}})
vars = {}
attributes = schema_attribute_definition(obj.class)
attributes.each do |attrname, class_name|
attr = node.extraattr[::XSD::QName.new(nil, attrname)]
def add_attributes2stubobj(node, obj)
if attributes = schema_attribute_definition(obj.class)
define_xmlattr(obj)
attributes.each do |qname, class_name|
attr = node.extraattr[qname]
next if attr.nil? or attr.empty?
klass = Mapping.class_from_name(class_name)
if klass.ancestors.include?(::SOAP::SOAPBasetype)
@ -247,32 +315,77 @@ private
else
child = attr
end
vars['attr_' + attrname] = child
obj.__xmlattr[qname] = child
define_xmlattr_accessor(obj, qname)
end
end
end
def add_elements2plainobj(node, obj)
node.each do |name, value|
obj.__add_xmlele_value(XSD::QName.new(nil, name), any2obj(value))
end
end
def add_attributes2plainobj(node, obj)
return if node.extraattr.empty?
define_xmlattr(obj)
node.extraattr.each do |qname, value|
obj.__xmlattr[qname] = value
define_xmlattr_accessor(obj, qname)
end
end
if RUBY_VERSION > "1.7.0"
def define_xmlattr_accessor(obj, qname)
name = XSD::CodeGen::GenSupport.safemethodname(qname.name)
Mapping.define_attr_accessor(obj, 'xmlattr_' + name,
proc { @__xmlattr[qname] },
proc { |value| @__xmlattr[qname] = value })
end
else
def define_xmlattr_accessor(obj, qname)
name = XSD::CodeGen::GenSupport.safemethodname(qname.name)
obj.instance_eval <<-EOS
def #{name}
@__xmlattr[#{qname.dump}]
end
def #{name}=(value)
@__xmlattr[#{qname.dump}] = value
end
EOS
end
end
if RUBY_VERSION > "1.7.0"
def define_xmlattr(obj)
obj.instance_variable_set('@__xmlattr', {})
unless obj.respond_to?(:__xmlattr)
Mapping.define_attr_accessor(obj, :__xmlattr, proc { @__xmlattr })
end
end
else
def define_xmlattr(obj)
obj.instance_variable_set('@__xmlattr', {})
unless obj.respond_to?(:__xmlattr)
obj.instance_eval <<-EOS
def __xmlattr
@__xmlattr
end
EOS
end
end
Mapping.set_instance_vars(obj, vars)
end
# it caches @@schema_element. this means that @@schema_element must not be
# changed while a lifetime of a WSDLLiteralRegistry.
def schema_element_definition(klass)
if @schema_element_cache.key?(klass)
return @schema_element_cache[klass]
end
elements = {}
as_array = []
klass.class_eval('@@schema_element').each do |name, class_name|
if /\[\]$/ =~ class_name
class_name = class_name.sub(/\[\]$/, '')
as_array << class_name
end
elements[name] = class_name
end
@schema_element_cache[klass] = [elements, as_array]
return @schema_element_cache[klass]
@schema_element_cache[klass] ||= Mapping.schema_element_definition(klass)
end
def schema_attribute_definition(klass)
attributes = klass.class_eval('@@schema_attribute')
@schema_attribute_cache[klass] ||= Mapping.schema_attribute_definition(klass)
end
end

View file

@ -14,8 +14,9 @@ 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)
# Trying xsd:dateTime data to be recovered as aTime.
MarshalMappingRegistry = Mapping::Registry.new(
:allow_original_mapping => true)
MarshalMappingRegistry.add(
Time,
::SOAP::SOAPDateTime,

View file

@ -43,18 +43,23 @@ class NetHttpClient
raise NotImplementedError.new("not supported for now")
end
def proxy=(proxy_str)
if proxy_str.nil?
def proxy=(proxy)
if proxy.nil?
@proxy = nil
else
@proxy = URI.parse(proxy_str)
if proxy.is_a?(URI)
@proxy = proxy
else
@proxy = URI.parse(proxy)
end
if @proxy.scheme == nil or @proxy.scheme.downcase != 'http' or
@proxy.host == nil or @proxy.port == nil
raise ArgumentError.new("unsupported proxy `#{proxy_str}'")
raise ArgumentError.new("unsupported proxy `#{proxy}'")
end
end
reset_all
@proxy
end
end
def set_basic_auth(uri, user_id, passwd)
# net/http does not handle url.
@ -79,7 +84,9 @@ class NetHttpClient
end
def post(url, req_body, header = {})
unless url.is_a?(URI)
url = URI.parse(url)
end
extra = header.dup
extra['User-Agent'] = @agent if @agent
res = start(url) { |http|
@ -89,7 +96,9 @@ class NetHttpClient
end
def get_content(url, header = {})
unless url.is_a?(URI)
url = URI.parse(url)
end
extra = header.dup
extra['User-Agent'] = @agent if @agent
res = start(url) { |http|

View file

@ -1,5 +1,5 @@
# SOAP4R - CGI stub library
# Copyright (C) 2001, 2003, 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# SOAP4R - CGI/mod_ruby stub library
# Copyright (C) 2001, 2003-2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -10,7 +10,7 @@ require 'soap/streamHandler'
require 'webrick/httpresponse'
require 'webrick/httpstatus'
require 'logger'
require 'soap/rpc/router'
require 'soap/rpc/soaplet'
module SOAP
@ -26,57 +26,51 @@ module RPC
#
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
include WEBrick
class SOAPRequest
ALLOWED_LENGTH = 1024 * 1024
attr_reader :body
def initialize(stream = $stdin)
@method = ENV['REQUEST_METHOD']
@size = ENV['CONTENT_LENGTH'].to_i || 0
@contenttype = ENV['CONTENT_TYPE']
@soapaction = ENV['HTTP_SOAPAction']
@source = stream
@body = nil
def [](var); end
def meta_vars; end
end
def init
validate
@body = @source.read(@size)
self
class SOAPStdinRequest < SOAPRequest
attr_reader :body
def initialize(stream)
size = ENV['CONTENT_LENGTH'].to_i || 0
@body = stream.read(size)
end
def dump
@body.dup
def [](var)
ENV[var.gsub(/-/, '_').upcase]
end
def soapaction
@soapaction
def meta_vars
{
'HTTP_SOAPACTION' => ENV['HTTP_SOAPAction']
}
end
end
def contenttype
@contenttype
class SOAPFCGIRequest < SOAPRequest
attr_reader :body
def initialize(request)
@request = request
@body = @request.in.read
end
def to_s
"method: #{ @method }, size: #{ @size }"
def [](var)
@request.env[var.gsub(/-/, '_').upcase]
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
def meta_vars
{
'HTTP_SOAPACTION' => @request.env['HTTP_SOAPAction']
}
end
end
@ -85,33 +79,14 @@ class CGIStub < Logger::Application
set_log(STDERR)
self.level = ERROR
@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
@router = ::SOAP::RPC::Router.new(self.class.name)
@soaplet = ::SOAP::RPC::SOAPlet.new(@router)
on_init
end
def add_rpc_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
alias add_servant add_rpc_servant
def add_rpc_headerhandler(obj)
@router.headerhandler << obj
end
alias add_headerhandler add_rpc_headerhandler
def on_init
# Override this method in derived class to call 'add_method' to add methods.
# do extra initialization in a derived class if needed.
end
def mapping_registry
@ -122,83 +97,108 @@ class CGIStub < Logger::Application
@router.mapping_registry = value
end
def add_method(receiver, name, *param)
add_method_with_namespace_as(@default_namespace, receiver,
name, name, *param)
def generate_explicit_type
@router.generate_explicit_type
end
def add_method_as(receiver, name, name_as, *param)
add_method_with_namespace_as(@default_namespace, receiver,
name, name_as, *param)
def generate_explicit_type=(generate_explicit_type)
@router.generate_explicit_type = generate_explicit_type
end
def add_method_with_namespace(namespace, receiver, name, *param)
add_method_with_namespace_as(namespace, receiver, name, name, *param)
end
# servant entry interface
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)
def add_rpc_servant(obj, namespace = @default_namespace)
@router.add_rpc_servant(obj, namespace)
end
alias add_servant add_rpc_servant
def add_headerhandler(obj)
@router.add_headerhandler(obj)
end
alias add_rpc_headerhandler add_headerhandler
# method entry interface
def add_rpc_method(obj, name, *param)
add_rpc_method_with_namespace_as(@default_namespace, obj, name, name, *param)
end
alias add_method add_rpc_method
def add_rpc_method_as(obj, name, name_as, *param)
add_rpc_method_with_namespace_as(@default_namespace, obj, name, name_as, *param)
end
alias add_method_as add_rpc_method_as
def add_rpc_method_with_namespace(namespace, obj, name, *param)
add_rpc_method_with_namespace_as(namespace, obj, name, name, *param)
end
alias add_method_with_namespace add_rpc_method_with_namespace
def add_rpc_method_with_namespace_as(namespace, obj, name, name_as, *param)
qname = XSD::QName.new(namespace, name_as)
@router.add_method(receiver, qname, nil, name, param_def)
soapaction = nil
param_def = SOAPMethod.derive_rpc_param_def(obj, name, *param)
@router.add_rpc_operation(obj, qname, soapaction, name, param_def)
end
alias add_method_with_namespace_as add_rpc_method_with_namespace_as
def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {})
@router.add_rpc_operation(receiver, qname, soapaction, name, param_def, opt)
end
def route(conn_data)
@router.route(conn_data)
def add_document_operation(receiver, soapaction, name, param_def, opt = {})
@router.add_document_operation(receiver, soapaction, name, param_def, opt)
end
def create_fault_response(e)
@router.create_fault_response(e)
def set_fcgi_request(request)
@fcgi = request
end
private
HTTPVersion = WEBrick::HTTPVersion.new('1.0') # dummy; ignored
def run
prologue
httpversion = WEBrick::HTTPVersion.new('1.0')
@response = WEBrick::HTTPResponse.new({:HTTPVersion => httpversion})
conn_data = nil
res = WEBrick::HTTPResponse.new({:HTTPVersion => HTTPVersion})
begin
@log.info { "Received a request from '#{ @remote_user }@#{ @remote_host }'." }
# SOAP request parsing.
@request = SOAPRequest.new.init
@response['Status'] = 200
conn_data = ::SOAP::StreamHandler::ConnectionData.new
conn_data.receive_string = @request.dump
conn_data.receive_contenttype = @request.contenttype
@log.debug { "XML Request: #{conn_data.receive_string}" }
conn_data = route(conn_data)
@log.debug { "XML Response: #{conn_data.send_string}" }
if conn_data.is_fault
@response['Status'] = 500
@log.info { "received a request from '#{ @remote_host }'" }
if @fcgi
req = SOAPFCGIRequest.new(@fcgi)
else
req = SOAPStdinRequest.new($stdin)
end
@response['Cache-Control'] = 'private'
@response.body = conn_data.send_string
@response['content-type'] = conn_data.send_contenttype
rescue Exception
conn_data = create_fault_response($!)
@response['Cache-Control'] = 'private'
@response['Status'] = 500
@response.body = conn_data.send_string
@response['content-type'] = conn_data.send_contenttype || @mediatype
@soaplet.do_POST(req, res)
rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
res.set_error(ex)
rescue HTTPStatus::Error => ex
res.set_error(ex)
rescue HTTPStatus::Status => ex
res.status = ex.code
rescue StandardError, NameError => ex # for Ruby 1.6
res.set_error(ex, true)
ensure
if defined?(MOD_RUBY)
r = Apache.request
r.status = res.status
r.content_type = res.content_type
r.send_http_header
buf = res.body
else
buf = ''
@response.send_response(buf)
res.send_response(buf)
buf.sub!(/^[^\r]+\r\n/, '') # Trim status line.
@log.debug { "SOAP CGI Response:\n#{ buf }" }
print buf
epilogue
end
@log.debug { "SOAP CGI Response:\n#{ buf }" }
if @fcgi
@fcgi.out.print buf
@fcgi.finish
@fcgi = nil
else
print buf
end
end
0
end
def prologue; end
def epilogue; end
end

View file

@ -1,5 +1,5 @@
# SOAP4R - SOAP RPC driver
# Copyright (C) 2000, 2001, 2003, 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2000, 2001, 2003-2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -22,32 +22,55 @@ module RPC
class Driver
class EmptyResponseError < Error; end
class << self
if RUBY_VERSION >= "1.7.0"
def __attr_proxy(symbol, assignable = false)
name = symbol.to_s
self.__send__(:define_method, name, proc {
@servant.__send__(name)
@proxy.__send__(name)
})
if assignable
self.__send__(:define_method, name + '=', proc { |rhs|
@servant.__send__(name + '=', rhs)
@proxy.__send__(name + '=', rhs)
})
end
end
else
def __attr_proxy(symbol, assignable = false)
name = symbol.to_s
module_eval <<-EOS
def #{name}
@proxy.#{name}
end
EOS
if assignable
module_eval <<-EOS
def #{name}=(value)
@proxy.#{name} = value
end
EOS
end
end
end
end
__attr_proxy :options
__attr_proxy :headerhandler
__attr_proxy :streamhandler
__attr_proxy :test_loopback_response
__attr_proxy :endpoint_url, true
__attr_proxy :mapping_registry, true
__attr_proxy :soapaction, true
__attr_proxy :default_encodingstyle, true
__attr_proxy :generate_explicit_type, true
__attr_proxy :allow_unqualified_element, true
__attr_proxy :headerhandler
__attr_proxy :streamhandler
__attr_proxy :test_loopback_response
__attr_proxy :reset_stream
attr_reader :proxy
attr_reader :options
attr_accessor :soapaction
def inspect
"#<#{self.class}:#{@proxy.inspect}>"
end
def httpproxy
options["protocol.http.proxy"]
@ -81,10 +104,12 @@ class Driver
options["protocol.wiredump_file_base"] = wiredump_file_base
end
def initialize(endpoint_url, namespace, soapaction = nil)
@servant = Servant__.new(self, endpoint_url, namespace)
@servant.soapaction = soapaction
@proxy = @servant.proxy
def initialize(endpoint_url, namespace = nil, soapaction = nil)
@namespace = namespace
@soapaction = soapaction
@options = setup_options
@wiredump_file_base = nil
@proxy = Proxy.new(endpoint_url, @soapaction, @options)
end
def loadproperty(propertyname)
@ -93,28 +118,23 @@ class Driver
end
end
def inspect
"#<#{self.class}:#{@servant.inspect}>"
end
def add_rpc_method(name, *params)
param_def = create_rpc_param_def(params)
@servant.add_rpc_method(name, @servant.soapaction, name, param_def)
add_rpc_method_with_soapaction_as(name, name, @soapaction, *params)
end
def add_rpc_method_as(name, name_as, *params)
param_def = create_rpc_param_def(params)
@servant.add_rpc_method(name_as, @servant.soapaction, name, param_def)
add_rpc_method_with_soapaction_as(name, name_as, @soapaction, *params)
end
def add_rpc_method_with_soapaction(name, soapaction, *params)
param_def = create_rpc_param_def(params)
@servant.add_rpc_method(name, soapaction, name, param_def)
add_rpc_method_with_soapaction_as(name, name, soapaction, *params)
end
def add_rpc_method_with_soapaction_as(name, name_as, soapaction, *params)
param_def = create_rpc_param_def(params)
@servant.add_rpc_method(name_as, soapaction, name, param_def)
param_def = SOAPMethod.create_rpc_param_def(params)
qname = XSD::QName.new(@namespace, name_as)
@proxy.add_rpc_method(qname, soapaction, name, param_def)
add_rpc_method_interface(name, param_def)
end
# add_method is for shortcut of typical rpc/encoded method definition.
@ -123,138 +143,20 @@ class Driver
alias add_method_with_soapaction add_rpc_method_with_soapaction
alias add_method_with_soapaction_as add_rpc_method_with_soapaction_as
def add_document_method(name, req_qname, res_qname)
param_def = create_document_param_def(name, req_qname, res_qname)
@servant.add_document_method(name, @servant.soapaction, name, param_def)
def add_document_method(name, soapaction, req_qname, res_qname)
param_def = SOAPMethod.create_doc_param_def(req_qname, res_qname)
@proxy.add_document_method(soapaction, name, param_def)
add_document_method_interface(name, param_def)
end
def add_document_method_as(name, name_as, req_qname, res_qname)
param_def = create_document_param_def(name, req_qname, res_qname)
@servant.add_document_method(name_as, @servant.soapaction, name, param_def)
def add_rpc_operation(qname, soapaction, name, param_def, opt = {})
@proxy.add_rpc_operation(qname, soapaction, name, param_def, opt)
add_rpc_method_interface(name, param_def)
end
def add_document_method_with_soapaction(name, soapaction, req_qname,
res_qname)
param_def = create_document_param_def(name, req_qname, res_qname)
@servant.add_document_method(name, soapaction, name, param_def)
end
def add_document_method_with_soapaction_as(name, name_as, soapaction,
req_qname, res_qname)
param_def = create_document_param_def(name, req_qname, res_qname)
@servant.add_document_method(name_as, soapaction, name, param_def)
end
def reset_stream
@servant.reset_stream
end
def invoke(headers, body)
@servant.invoke(headers, body)
end
def call(name, *params)
@servant.call(name, *params)
end
private
def create_rpc_param_def(params)
if params.size == 1 and params[0].is_a?(Array)
params[0]
else
SOAPMethod.create_param_def(params)
end
end
def create_document_param_def(name, req_qname, res_qname)
[
['input', name, [nil, req_qname.namespace, req_qname.name]],
['output', name, [nil, res_qname.namespace, res_qname.name]]
]
end
def add_rpc_method_interface(name, param_def)
@servant.add_rpc_method_interface(name, param_def)
end
def add_document_method_interface(name, paramname)
@servant.add_document_method_interface(name, paramname)
end
class Servant__
attr_reader :proxy
attr_reader :options
attr_accessor :soapaction
def initialize(host, endpoint_url, namespace)
@host = host
@namespace = namespace
@soapaction = nil
@options = setup_options
@wiredump_file_base = nil
@endpoint_url = endpoint_url
@proxy = Proxy.new(endpoint_url, @soapaction, @options)
end
def inspect
"#<#{self.class}:#{@proxy.inspect}>"
end
def endpoint_url
@proxy.endpoint_url
end
def endpoint_url=(endpoint_url)
@proxy.endpoint_url = endpoint_url
end
def mapping_registry
@proxy.mapping_registry
end
def mapping_registry=(mapping_registry)
@proxy.mapping_registry = mapping_registry
end
def default_encodingstyle
@proxy.default_encodingstyle
end
def default_encodingstyle=(encodingstyle)
@proxy.default_encodingstyle = encodingstyle
end
def generate_explicit_type
@proxy.generate_explicit_type
end
def generate_explicit_type=(generate_explicit_type)
@proxy.generate_explicit_type = generate_explicit_type
end
def allow_unqualified_element
@proxy.allow_unqualified_element
end
def allow_unqualified_element=(allow_unqualified_element)
@proxy.allow_unqualified_element = allow_unqualified_element
end
def headerhandler
@proxy.headerhandler
end
def streamhandler
@proxy.streamhandler
end
def test_loopback_response
@proxy.test_loopback_response
end
def reset_stream
@proxy.reset_stream
def add_document_operation(soapaction, name, param_def, opt = {})
@proxy.add_document_operation(soapaction, name, param_def, opt)
add_document_method_interface(name, param_def)
end
def invoke(headers, body)
@ -275,48 +177,11 @@ private
@proxy.call(name, *params)
end
def add_rpc_method(name_as, soapaction, name, param_def)
qname = XSD::QName.new(@namespace, name_as)
@proxy.add_rpc_method(qname, soapaction, name, param_def)
add_rpc_method_interface(name, param_def)
end
def add_document_method(name_as, soapaction, name, param_def)
qname = XSD::QName.new(@namespace, name_as)
@proxy.add_document_method(qname, soapaction, name, param_def)
add_document_method_interface(name, param_def)
end
def add_rpc_method_interface(name, param_def)
param_count = 0
@proxy.operation[name].each_param_name(RPC::SOAPMethod::IN,
RPC::SOAPMethod::INOUT) do |param_name|
param_count += 1
end
sclass = class << @host; self; end
sclass.__send__(:define_method, name, proc { |*arg|
unless arg.size == param_count
raise ArgumentError.new(
"wrong number of arguments (#{arg.size} for #{param_count})")
end
@servant.call(name, *arg)
})
@host.method(name)
end
def add_document_method_interface(name, paramname)
sclass = class << @host; self; end
sclass.__send__(:define_method, name, proc { |param|
@servant.call(name, param)
})
@host.method(name)
end
private
private
def set_wiredump_file_base(name)
if @wiredump_file_base
@proxy.set_wiredump_file_base(@wiredump_file_base + "_#{ name }")
@proxy.set_wiredump_file_base("#{@wiredump_file_base}_#{name}")
end
end
@ -344,6 +209,42 @@ private
opt["protocol.http.no_proxy"] ||= Env::NO_PROXY
opt
end
def add_rpc_method_interface(name, param_def)
param_count = RPC::SOAPMethod.param_count(param_def,
RPC::SOAPMethod::IN, RPC::SOAPMethod::INOUT)
add_method_interface(name, param_count)
end
def add_document_method_interface(name, param_def)
param_count = RPC::SOAPMethod.param_count(param_def, RPC::SOAPMethod::IN)
add_method_interface(name, param_count)
end
if RUBY_VERSION > "1.7.0"
def add_method_interface(name, param_count)
::SOAP::Mapping.define_singleton_method(self, name) do |*arg|
unless arg.size == param_count
raise ArgumentError.new(
"wrong number of arguments (#{arg.size} for #{param_count})")
end
call(name, *arg)
end
self.method(name)
end
else
def add_method_interface(name, param_count)
instance_eval <<-EOS
def #{name}(*arg)
unless arg.size == #{param_count}
raise ArgumentError.new(
"wrong number of arguments (\#{arg.size} for #{param_count})")
end
call(#{name.dump}, *arg)
end
EOS
self.method(name)
end
end
end

View file

@ -1,5 +1,5 @@
# SOAP4R - RPC element definition.
# Copyright (C) 2000, 2001, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2000, 2001, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -77,6 +77,8 @@ class SOAPMethod < SOAPStruct
attr_reader :param_def
attr_reader :inparam
attr_reader :outparam
attr_reader :retval_name
attr_reader :retval_class_name
def initialize(qname, param_def = nil)
super(nil)
@ -93,6 +95,7 @@ class SOAPMethod < SOAPStruct
@inparam = {}
@outparam = {}
@retval_name = nil
@retval_class_name = nil
init_param(@param_def) if @param_def
end
@ -101,12 +104,12 @@ class SOAPMethod < SOAPStruct
@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
def input_params
collect_params(IN, INOUT)
end
def output_params
collect_params(OUT, INOUT)
end
def set_param(params)
@ -124,7 +127,30 @@ class SOAPMethod < SOAPStruct
end
end
def SOAPMethod.create_param_def(param_names)
def SOAPMethod.param_count(param_def, *type)
count = 0
param_def.each do |io_type, name, param_type|
if type.include?(io_type)
count += 1
end
end
count
end
def SOAPMethod.derive_rpc_param_def(obj, name, *param)
if param.size == 1 and param[0].is_a?(Array)
return param[0]
end
if param.empty?
method = obj.method(name)
param_names = (1..method.arity.abs).collect { |i| "p#{i}" }
else
param_names = param
end
create_rpc_param_def(param_names)
end
def SOAPMethod.create_rpc_param_def(param_names)
param_def = []
param_names.each do |param_name|
param_def.push([IN, param_name, nil])
@ -133,8 +159,29 @@ class SOAPMethod < SOAPStruct
param_def
end
def SOAPMethod.create_doc_param_def(req_qnames, res_qnames)
req_qnames = [req_qnames] if req_qnames.is_a?(XSD::QName)
res_qnames = [res_qnames] if res_qnames.is_a?(XSD::QName)
param_def = []
req_qnames.each do |qname|
param_def << [IN, qname.name, [nil, qname.namespace, qname.name]]
end
res_qnames.each do |qname|
param_def << [OUT, qname.name, [nil, qname.namespace, qname.name]]
end
param_def
end
private
def collect_params(*type)
names = []
@signature.each do |io_type, name, param_type|
names << name if type.include?(io_type)
end
names
end
def init_param(param_def)
param_def.each do |io_type, name, param_type|
case io_type
@ -148,12 +195,20 @@ private
@signature.push([INOUT, name, param_type])
@inoutparam_names.push(name)
when RETVAL
if (@retval_name)
raise MethodDefinitionError.new('Duplicated retval')
if @retval_name
raise MethodDefinitionError.new('duplicated retval')
end
@retval_name = name
@retval_class_name = nil
if param_type
if param_type[0].is_a?(String)
@retval_class_name = Mapping.class_from_name(param_type[0])
else
raise MethodDefinitionError.new("Unknown type: #{ io_type }")
@retval_class_name = param_type[0]
end
end
else
raise MethodDefinitionError.new("unknown type: #{io_type}")
end
end
end
@ -168,7 +223,7 @@ class SOAPMethodRequest < SOAPMethod
param_value = []
i = 0
params.each do |param|
param_name = "p#{ i }"
param_name = "p#{i}"
i += 1
param_def << [IN, param_name, nil]
param_value << [param_name, param]
@ -186,9 +241,9 @@ class SOAPMethodRequest < SOAPMethod
end
def each
each_param_name(IN, INOUT) do |name|
input_params.each do |name|
unless @inparam[name]
raise ParameterError.new("Parameter: #{ name } was not given.")
raise ParameterError.new("parameter: #{name} was not given")
end
yield(name, @inparam[name])
end
@ -200,10 +255,10 @@ class SOAPMethodRequest < SOAPMethod
req
end
def create_method_response
SOAPMethodResponse.new(
XSD::QName.new(@elename.namespace, @elename.name + 'Response'),
@param_def)
def create_method_response(response_name = nil)
response_name ||=
XSD::QName.new(@elename.namespace, @elename.name + 'Response')
SOAPMethodResponse.new(response_name, @param_def)
end
private
@ -211,7 +266,7 @@ 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")
raise MethodDefinitionError.new("element name '#{qname.name}' not allowed")
end
end
end
@ -236,11 +291,11 @@ class SOAPMethodResponse < SOAPMethod
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.")
output_params.each do |name|
unless @outparam[name]
raise ParameterError.new("parameter: #{name} was not given")
end
yield(param_name, @outparam[param_name])
yield(name, @outparam[name])
end
end
end

View file

@ -24,23 +24,22 @@ class HTTPServer < Logger::Application
super(config[:SOAPHTTPServerApplicationName] || self.class.name)
@default_namespace = config[:SOAPDefaultNamespace]
@webrick_config = config.dup
self.level = Logger::Severity::ERROR # keep silent by default
@webrick_config[:Logger] ||= @log
@server = nil
@soaplet = ::SOAP::RPC::SOAPlet.new
self.level = Logger::Severity::INFO
@log = @webrick_config[:Logger] # sync logger of App and HTTPServer
@router = ::SOAP::RPC::Router.new(self.class.name)
@soaplet = ::SOAP::RPC::SOAPlet.new(@router)
on_init
@server = WEBrick::HTTPServer.new(@webrick_config)
@server.mount('/', @soaplet)
end
def on_init
# define extra methods in derived class.
# do extra initialization in a derived class if needed.
end
def status
if @server
@server.status
else
nil
end
@server.status if @server
end
def shutdown
@ -48,31 +47,39 @@ class HTTPServer < Logger::Application
end
def mapping_registry
@soaplet.app_scope_router.mapping_registry
@router.mapping_registry
end
def mapping_registry=(mapping_registry)
@soaplet.app_scope_router.mapping_registry = mapping_registry
@router.mapping_registry = mapping_registry
end
def generate_explicit_type
@router.generate_explicit_type
end
def generate_explicit_type=(generate_explicit_type)
@router.generate_explicit_type = generate_explicit_type
end
# servant entry interface
def add_rpc_request_servant(factory, namespace = @default_namespace,
mapping_registry = nil)
@soaplet.add_rpc_request_servant(factory, namespace, mapping_registry)
def add_rpc_request_servant(factory, namespace = @default_namespace)
@router.add_rpc_request_servant(factory, namespace)
end
def add_rpc_servant(obj, namespace = @default_namespace)
@soaplet.add_rpc_servant(obj, namespace)
@router.add_rpc_servant(obj, namespace)
end
def add_rpc_request_headerhandler(factory)
@soaplet.add_rpc_request_headerhandler(factory)
def add_request_headerhandler(factory)
@router.add_request_headerhandler(factory)
end
def add_rpc_headerhandler(obj)
@soaplet.add_rpc_headerhandler(obj)
def add_headerhandler(obj)
@router.add_headerhandler(obj)
end
alias add_rpc_headerhandler add_headerhandler
# method entry interface
@ -81,52 +88,38 @@ class HTTPServer < Logger::Application
end
alias add_method add_rpc_method
def add_document_method(obj, name, req_qname, res_qname)
opt = {}
opt[:request_style] = opt[:response_style] = :document
opt[:request_use] = opt[:response_use] = :literal
param_def = [
['input', req_qname.name, [nil, req_qname.namespace, req_qname.name]],
['output', req_qname.name, [nil, res_qname.namespace, res_qname.name]]
]
@soaplet.app_scope_router.add_operation(req_qname, nil, obj, name,
param_def, opt)
end
def add_rpc_method_as(obj, name, name_as, *param)
qname = XSD::QName.new(@default_namespace, name_as)
soapaction = nil
param_def = create_param_def(obj, name, param)
add_operation(qname, soapaction, obj, name, param_def)
param_def = SOAPMethod.derive_rpc_param_def(obj, name, *param)
@router.add_rpc_operation(obj, qname, soapaction, name, param_def)
end
alias add_method_as add_rpc_method_as
def add_operation(qname, soapaction, obj, name, param_def, opt = {})
opt[:request_style] ||= :rpc
opt[:response_style] ||= :rpc
opt[:request_use] ||= :encoded
opt[:response_use] ||= :encoded
@soaplet.app_scope_router.add_operation(qname, soapaction, obj, name,
param_def, opt)
def add_document_method(obj, soapaction, name, req_qnames, res_qnames)
param_def = SOAPMethod.create_doc_param_def(req_qnames, res_qnames)
@router.add_document_operation(obj, soapaction, name, param_def)
end
def create_param_def(obj, name, param = nil)
if param.nil? or param.empty?
method = obj.method(name)
::SOAP::RPC::SOAPMethod.create_param_def(
(1..method.arity.abs).collect { |i| "p#{i}" })
elsif param.size == 1 and param[0].is_a?(Array)
param[0]
else
::SOAP::RPC::SOAPMethod.create_param_def(param)
def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {})
@router.add_rpc_operation(receiver, qname, soapaction, name, param_def, opt)
end
def add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt = {})
@router.add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt)
end
def add_document_operation(receiver, soapaction, name, param_def, opt = {})
@router.add_document_operation(receiver, soapaction, name, param_def, opt)
end
def add_document_request_operation(factory, soapaction, name, param_def, opt = {})
@router.add_document_request_operation(factory, soapaction, name, param_def, opt)
end
private
def run
@server = WEBrick::HTTPServer.new(@webrick_config)
@server.mount('/', @soaplet)
@server.start
end
end

View file

@ -1,5 +1,5 @@
# SOAP4R - RPC Proxy library.
# Copyright (C) 2000, 2003, 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2000, 2003-2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -78,30 +78,62 @@ public
@streamhandler.test_loopback_response
end
def add_rpc_method(qname, soapaction, name, param_def, opt = {})
def add_rpc_operation(qname, soapaction, name, param_def, opt = {})
opt[:request_qname] = qname
opt[:request_style] ||= :rpc
opt[:response_style] ||= :rpc
opt[:request_use] ||= :encoded
opt[:response_use] ||= :encoded
@operation[name] = Operation.new(qname, soapaction, name, param_def, opt)
@operation[name] = Operation.new(soapaction, param_def, opt)
end
def add_document_method(qname, soapaction, name, param_def, opt = {})
def add_document_operation(soapaction, name, param_def, opt = {})
opt[:request_style] ||= :document
opt[:response_style] ||= :document
opt[:request_use] ||= :literal
opt[:response_use] ||= :literal
@operation[name] = Operation.new(qname, soapaction, name, param_def, opt)
@operation[name] = Operation.new(soapaction, param_def, opt)
end
# add_method is for shortcut of typical rpc/encoded method definition.
alias add_method add_rpc_method
alias add_method add_rpc_operation
alias add_rpc_method add_rpc_operation
alias add_document_method add_document_operation
def invoke(req_header, req_body, opt = create_options)
def invoke(req_header, req_body, opt = nil)
opt ||= create_options
route(req_header, req_body, opt, opt)
end
def call(name, *params)
unless op_info = @operation[name]
raise MethodDefinitionError, "method: #{name} not defined"
end
req_header = create_request_header
req_body = SOAPBody.new(
op_info.request_body(params, @mapping_registry, @literal_mapping_registry)
)
reqopt = create_options({
:soapaction => op_info.soapaction || @soapaction,
:default_encodingstyle => op_info.request_default_encodingstyle})
resopt = create_options({
:default_encodingstyle => op_info.response_default_encodingstyle})
env = route(req_header, req_body, reqopt, resopt)
raise EmptyResponseError unless env
receive_headers(env.header)
begin
check_fault(env.body)
rescue ::SOAP::FaultError => e
op_info.raise_fault(e, @mapping_registry, @literal_mapping_registry)
end
op_info.response_obj(env.body, @mapping_registry, @literal_mapping_registry)
end
def route(req_header, req_body, reqopt, resopt)
req_env = SOAPEnvelope.new(req_header, req_body)
opt[:external_content] = nil
conn_data = marshal(req_env, opt)
if ext = opt[:external_content]
reqopt[:external_content] = nil
conn_data = marshal(req_env, reqopt)
if ext = reqopt[:external_content]
mime = MIMEMessage.new
ext.each do |k, v|
mime.add_attachment(v.data)
@ -111,33 +143,12 @@ public
conn_data.send_string = mime.content_str
conn_data.send_contenttype = mime.headers['content-type'].str
end
conn_data = @streamhandler.send(@endpoint_url, conn_data, opt[:soapaction])
conn_data = @streamhandler.send(@endpoint_url, conn_data,
reqopt[:soapaction])
if conn_data.receive_string.empty?
return nil
end
unmarshal(conn_data, opt)
end
def call(name, *params)
unless op_info = @operation[name]
raise MethodDefinitionError, "Method: #{name} not defined."
end
req_header = create_request_header
req_body = op_info.create_request_body(params, @mapping_registry,
@literal_mapping_registry)
opt = create_options({
:soapaction => op_info.soapaction || @soapaction,
:default_encodingstyle => op_info.response_default_encodingstyle})
env = invoke(req_header, req_body, opt)
receive_headers(env.header)
raise EmptyResponseError.new("Empty response.") unless env
begin
check_fault(env.body)
rescue ::SOAP::FaultError => e
Mapping.fault2exception(e)
end
op_info.create_response_obj(env, @mapping_registry,
@literal_mapping_registry)
unmarshal(conn_data, resopt)
end
def check_fault(body)
@ -217,98 +228,203 @@ private
attr_reader :request_use
attr_reader :response_use
def initialize(qname, soapaction, name, param_def, opt)
def initialize(soapaction, param_def, opt)
@soapaction = soapaction
@request_style = opt[:request_style]
@response_style = opt[:response_style]
@request_use = opt[:request_use]
@response_use = opt[:response_use]
@rpc_method_factory = @document_method_name = nil
check_style(@request_style)
check_style(@response_style)
check_use(@request_use)
check_use(@response_use)
if @request_style == :rpc
@rpc_method_factory = SOAPMethodRequest.new(qname, param_def,
@soapaction)
@rpc_request_qname = opt[:request_qname]
if @rpc_request_qname.nil?
raise MethodDefinitionError.new("rpc_request_qname must be given")
end
@rpc_method_factory =
RPC::SOAPMethodRequest.new(@rpc_request_qname, param_def, @soapaction)
else
@document_method_name = {}
@doc_request_qnames = []
@doc_response_qnames = []
param_def.each do |inout, paramname, typeinfo|
klass, namespace, name = typeinfo
case inout.to_s
when "input"
@document_method_name[:input] = ::XSD::QName.new(namespace, name)
when "output"
@document_method_name[:output] = ::XSD::QName.new(namespace, name)
klass_not_used, nsdef, namedef = typeinfo
if namedef.nil?
raise MethodDefinitionError.new("qname must be given")
end
case inout
when SOAPMethod::IN
@doc_request_qnames << XSD::QName.new(nsdef, namedef)
when SOAPMethod::OUT
@doc_response_qnames << XSD::QName.new(nsdef, namedef)
else
raise MethodDefinitionError, "unknown type: " + inout
raise MethodDefinitionError.new(
"illegal inout definition for document style: #{inout}")
end
end
end
end
def request_default_encodingstyle
(@request_style == :rpc) ? EncodingNamespace : LiteralNamespace
(@request_use == :encoded) ? EncodingNamespace : LiteralNamespace
end
def response_default_encodingstyle
(@response_style == :rpc) ? EncodingNamespace : LiteralNamespace
(@response_use == :encoded) ? EncodingNamespace : LiteralNamespace
end
# for rpc
def each_param_name(*target)
def request_body(values, mapping_registry, literal_mapping_registry)
if @request_style == :rpc
@rpc_method_factory.each_param_name(*target) do |name|
yield(name)
end
request_rpc(values, mapping_registry, literal_mapping_registry)
else
yield(@document_method_name[:input].name)
request_doc(values, mapping_registry, literal_mapping_registry)
end
end
def create_request_body(values, mapping_registry, literal_mapping_registry)
if @request_style == :rpc
values = Mapping.obj2soap(values, mapping_registry).to_a
method = @rpc_method_factory.dup
params = {}
idx = 0
method.each_param_name(::SOAP::RPC::SOAPMethod::IN,
::SOAP::RPC::SOAPMethod::INOUT) do |name|
params[name] = values[idx] || SOAPNil.new
idx += 1
end
method.set_param(params)
SOAPBody.new(method)
else
name = @document_method_name[:input]
document = literal_mapping_registry.obj2soap(values[0], name)
SOAPBody.new(document)
end
end
def create_response_obj(env, mapping_registry, literal_mapping_registry)
def response_obj(body, mapping_registry, literal_mapping_registry)
if @response_style == :rpc
ret = env.body.response ?
Mapping.soap2obj(env.body.response, mapping_registry) : nil
if env.body.outparams
outparams = env.body.outparams.collect { |outparam|
Mapping.soap2obj(outparam)
}
[ret].concat(outparams)
response_rpc(body, mapping_registry, literal_mapping_registry)
else
ret
response_doc(body, mapping_registry, literal_mapping_registry)
end
end
def raise_fault(e, mapping_registry, literal_mapping_registry)
if @response_style == :rpc
Mapping.fault2exception(e, mapping_registry)
else
Mapping.soap2obj(env.body.root_node, literal_mapping_registry)
Mapping.fault2exception(e, literal_mapping_registry)
end
end
private
ALLOWED_STYLE = [:rpc, :document]
def check_style(style)
unless ALLOWED_STYLE.include?(style)
raise MethodDefinitionError, "unknown style: " + style
unless [:rpc, :document].include?(style)
raise MethodDefinitionError.new("unknown style: #{style}")
end
end
def check_use(use)
unless [:encoded, :literal].include?(use)
raise MethodDefinitionError.new("unknown use: #{use}")
end
end
def request_rpc(values, mapping_registry, literal_mapping_registry)
if @request_use == :encoded
request_rpc_enc(values, mapping_registry)
else
request_rpc_lit(values, literal_mapping_registry)
end
end
def request_doc(values, mapping_registry, literal_mapping_registry)
if @request_use == :encoded
request_doc_enc(values, mapping_registry)
else
request_doc_lit(values, literal_mapping_registry)
end
end
def request_rpc_enc(values, mapping_registry)
method = @rpc_method_factory.dup
names = method.input_params
obj = create_request_obj(names, values)
soap = Mapping.obj2soap(obj, mapping_registry, @rpc_request_qname)
method.set_param(soap)
method
end
def request_rpc_lit(values, mapping_registry)
method = @rpc_method_factory.dup
params = {}
idx = 0
method.input_params.each do |name|
params[name] = Mapping.obj2soap(values[idx], mapping_registry,
XSD::QName.new(nil, name))
idx += 1
end
method.set_param(params)
method
end
def request_doc_enc(values, mapping_registry)
(0...values.size).collect { |idx|
ele = Mapping.obj2soap(values[idx], mapping_registry)
ele.elename = @doc_request_qnames[idx]
ele
}
end
def request_doc_lit(values, mapping_registry)
(0...values.size).collect { |idx|
ele = Mapping.obj2soap(values[idx], mapping_registry,
@doc_request_qnames[idx])
ele.encodingstyle = LiteralNamespace
ele
}
end
def response_rpc(body, mapping_registry, literal_mapping_registry)
if @response_use == :encoded
response_rpc_enc(body, mapping_registry)
else
response_rpc_lit(body, literal_mapping_registry)
end
end
def response_doc(body, mapping_registry, literal_mapping_registry)
if @response_use == :encoded
return *response_doc_enc(body, mapping_registry)
else
return *response_doc_lit(body, literal_mapping_registry)
end
end
def response_rpc_enc(body, mapping_registry)
ret = nil
if body.response
ret = Mapping.soap2obj(body.response, mapping_registry,
@rpc_method_factory.retval_class_name)
end
if body.outparams
outparams = body.outparams.collect { |outparam|
Mapping.soap2obj(outparam, mapping_regisry)
}
[ret].concat(outparams)
else
ret
end
end
def response_rpc_lit(body, mapping_registry)
body.root_node.collect { |key, value|
Mapping.soap2obj(value, mapping_registry,
@rpc_method_factory.retval_class_name)
}
end
def response_doc_enc(body, mapping_registry)
body.collect { |key, value|
Mapping.soap2obj(value, mapping_registry)
}
end
def response_doc_lit(body, mapping_registry)
body.collect { |key, value|
Mapping.soap2obj(value, mapping_registry)
}
end
def create_request_obj(names, params)
o = Object.new
for idx in 0 ... params.length
o.instance_variable_set('@' + names[idx], params[idx])
end
o
end
end
end

View file

@ -1,5 +1,5 @@
# SOAP4R - RPC Routing library
# Copyright (C) 2001, 2002 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2001, 2002, 2004, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -25,101 +25,229 @@ class Router
include SOAP
attr_reader :actor
attr_accessor :allow_unqualified_element
attr_accessor :default_encodingstyle
attr_accessor :mapping_registry
attr_accessor :literal_mapping_registry
attr_reader :headerhandler
attr_accessor :generate_explicit_type
def initialize(actor)
@actor = actor
@allow_unqualified_element = false
@default_encodingstyle = nil
@mapping_registry = nil
@headerhandler = Header::HandlerSet.new
@literal_mapping_registry = ::SOAP::Mapping::WSDLLiteralRegistry.new
@operation = {}
@generate_explicit_type = true
@operation_by_soapaction = {}
@operation_by_qname = {}
@headerhandlerfactory = []
end
def add_rpc_method(receiver, qname, soapaction, name, param_def, opt = {})
opt[:request_style] ||= :rpc
opt[:response_style] ||= :rpc
opt[:request_use] ||= :encoded
opt[:response_use] ||= :encoded
add_operation(qname, soapaction, receiver, name, param_def, opt)
###
## header handler interface
#
def add_request_headerhandler(factory)
unless factory.respond_to?(:create)
raise TypeError.new("factory must respond to 'create'")
end
@headerhandlerfactory << factory
end
def add_document_method(receiver, qname, soapaction, name, param_def, opt = {})
opt[:request_style] ||= :document
opt[:response_style] ||= :document
opt[:request_use] ||= :encoded
opt[:response_use] ||= :encoded
if opt[:request_style] == :document
inputdef = param_def.find { |inout, paramname, typeinfo| inout == "input" }
klass, nsdef, namedef = inputdef[2]
qname = ::XSD::QName.new(nsdef, namedef)
end
add_operation(qname, soapaction, receiver, name, param_def, opt)
def add_headerhandler(handler)
@headerhandler.add(handler)
end
def add_operation(qname, soapaction, receiver, name, param_def, opt)
@operation[fqname(qname)] = Operation.new(qname, soapaction, receiver,
name, param_def, opt)
###
## servant definition interface
#
def add_rpc_request_servant(factory, namespace)
unless factory.respond_to?(:create)
raise TypeError.new("factory must respond to 'create'")
end
obj = factory.create # a dummy instance for introspection
::SOAP::RPC.defined_methods(obj).each do |name|
begin
qname = XSD::QName.new(namespace, name)
param_def = ::SOAP::RPC::SOAPMethod.derive_rpc_param_def(obj, name)
opt = create_styleuse_option(:rpc, :encoded)
add_rpc_request_operation(factory, qname, nil, name, param_def, opt)
rescue SOAP::RPC::MethodDefinitionError => e
p e if $DEBUG
end
end
end
# add_method is for shortcut of typical use="encoded" method definition.
alias add_method add_rpc_method
def add_rpc_servant(obj, namespace)
::SOAP::RPC.defined_methods(obj).each do |name|
begin
qname = XSD::QName.new(namespace, name)
param_def = ::SOAP::RPC::SOAPMethod.derive_rpc_param_def(obj, name)
opt = create_styleuse_option(:rpc, :encoded)
add_rpc_operation(obj, qname, nil, name, param_def, opt)
rescue SOAP::RPC::MethodDefinitionError => e
p e if $DEBUG
end
end
end
alias add_servant add_rpc_servant
###
## operation definition interface
#
def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {})
ensure_styleuse_option(opt, :rpc, :encoded)
opt[:request_qname] = qname
op = ApplicationScopeOperation.new(soapaction, receiver, name, param_def,
opt)
if opt[:request_style] != :rpc
raise RPCRoutingError.new("illegal request_style given")
end
assign_operation(soapaction, qname, op)
end
alias add_method add_rpc_operation
alias add_rpc_method add_rpc_operation
def add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt = {})
ensure_styleuse_option(opt, :rpc, :encoded)
opt[:request_qname] = qname
op = RequestScopeOperation.new(soapaction, factory, name, param_def, opt)
if opt[:request_style] != :rpc
raise RPCRoutingError.new("illegal request_style given")
end
assign_operation(soapaction, qname, op)
end
def add_document_operation(receiver, soapaction, name, param_def, opt = {})
#
# adopt workaround for doc/lit wrapper method
# (you should consider to simply use rpc/lit service)
#
#unless soapaction
# raise RPCRoutingError.new("soapaction is a must for document method")
#end
ensure_styleuse_option(opt, :document, :literal)
op = ApplicationScopeOperation.new(soapaction, receiver, name, param_def,
opt)
if opt[:request_style] != :document
raise RPCRoutingError.new("illegal request_style given")
end
assign_operation(soapaction, first_input_part_qname(param_def), op)
end
alias add_document_method add_document_operation
def add_document_request_operation(factory, soapaction, name, param_def, opt = {})
#
# adopt workaround for doc/lit wrapper method
# (you should consider to simply use rpc/lit service)
#
#unless soapaction
# raise RPCRoutingError.new("soapaction is a must for document method")
#end
ensure_styleuse_option(opt, :document, :literal)
op = RequestScopeOperation.new(soapaction, receiver, name, param_def, opt)
if opt[:request_style] != :document
raise RPCRoutingError.new("illegal request_style given")
end
assign_operation(soapaction, first_input_part_qname(param_def), op)
end
def route(conn_data)
soap_response = nil
begin
# we cannot set request_default_encodingsyle before parsing the content.
env = unmarshal(conn_data)
if env.nil?
raise ArgumentError.new("Illegal SOAP marshal format.")
raise ArgumentError.new("illegal SOAP marshal format")
end
receive_headers(env.header)
request = env.body.request
op = @operation[fqname(request.elename)]
unless op
raise RPCRoutingError.new("Method: #{request.elename} not supported.")
op = lookup_operation(conn_data.soapaction, env.body)
headerhandler = @headerhandler.dup
@headerhandlerfactory.each do |f|
headerhandler.add(f.create)
end
soap_response = op.call(request, @mapping_registry, @literal_mapping_registry)
receive_headers(headerhandler, env.header)
soap_response = default_encodingstyle = nil
begin
soap_response =
op.call(env.body, @mapping_registry, @literal_mapping_registry)
default_encodingstyle = op.response_default_encodingstyle
rescue Exception
soap_response = fault($!)
conn_data.is_fault = true
default_encodingstyle = nil
end
marshal(conn_data, op, soap_response)
conn_data
conn_data.is_fault = true if soap_response.is_a?(SOAPFault)
header = call_headers(headerhandler)
body = SOAPBody.new(soap_response)
env = SOAPEnvelope.new(header, body)
marshal(conn_data, env, default_encodingstyle)
end
# Create fault response string.
def create_fault_response(e, charset = nil)
header = SOAPHeader.new
body = SOAPBody.new(fault(e))
env = SOAPEnvelope.new(header, body)
opt = options
def create_fault_response(e)
env = SOAPEnvelope.new(SOAPHeader.new, SOAPBody.new(fault(e)))
opt = {}
opt[:external_content] = nil
opt[:charset] = charset
response_string = Processor.marshal(env, opt)
conn_data = StreamHandler::ConnectionData.new(response_string)
conn_data.is_fault = true
if ext = opt[:external_content]
mime = MIMEMessage.new
ext.each do |k, v|
mime.add_attachment(v.data)
end
mime.add_part(conn_data.send_string + "\r\n")
mime.close
conn_data.send_string = mime.content_str
conn_data.send_contenttype = mime.headers['content-type'].str
mimeize(conn_data, ext)
end
conn_data
end
private
def call_headers
headers = @headerhandler.on_outbound
def first_input_part_qname(param_def)
param_def.each do |inout, paramname, typeinfo|
if inout == SOAPMethod::IN
klass, nsdef, namedef = typeinfo
return XSD::QName.new(nsdef, namedef)
end
end
nil
end
def create_styleuse_option(style, use)
opt = {}
opt[:request_style] = opt[:response_style] = style
opt[:request_use] = opt[:response_use] = use
opt
end
def ensure_styleuse_option(opt, style, use)
opt[:request_style] ||= style
opt[:response_style] ||= style
opt[:request_use] ||= use
opt[:response_use] ||= use
end
def assign_operation(soapaction, qname, op)
assigned = false
if soapaction and !soapaction.empty?
@operation_by_soapaction[soapaction] = op
assigned = true
end
if qname
@operation_by_qname[qname] = op
assigned = true
end
unless assigned
raise RPCRoutingError.new("cannot assign operation")
end
end
def lookup_operation(soapaction, body)
if op = @operation_by_soapaction[soapaction]
return op
end
qname = body.root_node.elename
if op = @operation_by_qname[qname]
return op
end
if soapaction
raise RPCRoutingError.new("operation: #{soapaction} not supported")
else
raise RPCRoutingError.new("operation: #{qname} not supported")
end
end
def call_headers(headerhandler)
headers = headerhandler.on_outbound
if headers.empty?
nil
else
@ -131,12 +259,12 @@ private
end
end
def receive_headers(headers)
@headerhandler.on_inbound(headers) if headers
def receive_headers(headerhandler, headers)
headerhandler.on_inbound(headers) if headers
end
def unmarshal(conn_data)
opt = options
opt = {}
contenttype = conn_data.receive_contenttype
if /#{MIMEMessage::MultipartContentType}/i =~ contenttype
opt[:external_content] = {}
@ -160,19 +288,20 @@ private
env
end
def marshal(conn_data, op, soap_response)
response_opt = options
response_opt[:external_content] = nil
if op and !conn_data.is_fault and op.response_use == :document
response_opt[:default_encodingstyle] =
::SOAP::EncodingStyle::ASPDotNetHandler::Namespace
end
header = call_headers
body = SOAPBody.new(soap_response)
env = SOAPEnvelope.new(header, body)
response_string = Processor.marshal(env, response_opt)
def marshal(conn_data, env, default_encodingstyle = nil)
opt = {}
opt[:external_content] = nil
opt[:default_encodingstyle] = default_encodingstyle
opt[:generate_explicit_type] = @generate_explicit_type
response_string = Processor.marshal(env, opt)
conn_data.send_string = response_string
if ext = response_opt[:external_content]
if ext = opt[:external_content]
mimeize(conn_data, ext)
end
conn_data
end
def mimeize(conn_data, ext)
mime = MIMEMessage.new
ext.each do |k, v|
mime.add_attachment(v.data)
@ -181,7 +310,7 @@ private
mime.close
conn_data.send_string = mime.content_str
conn_data.send_contenttype = mime.headers['content-type'].str
end
conn_data
end
# Create fault response.
@ -194,21 +323,7 @@ private
Mapping.obj2soap(detail, @mapping_registry))
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
class Operation
attr_reader :receiver
attr_reader :name
attr_reader :soapaction
attr_reader :request_style
@ -216,62 +331,148 @@ private
attr_reader :request_use
attr_reader :response_use
def initialize(qname, soapaction, receiver, name, param_def, opt)
def initialize(soapaction, name, param_def, opt)
@soapaction = soapaction
@receiver = receiver
@name = name
@request_style = opt[:request_style]
@response_style = opt[:response_style]
@request_use = opt[:request_use]
@response_use = opt[:response_use]
check_style(@request_style)
check_style(@response_style)
check_use(@request_use)
check_use(@response_use)
if @response_style == :rpc
@rpc_response_factory =
RPC::SOAPMethodRequest.new(qname, param_def, @soapaction)
request_qname = opt[:request_qname] or raise
@rpc_method_factory =
RPC::SOAPMethodRequest.new(request_qname, param_def, @soapaction)
@rpc_response_qname = opt[:response_qname]
else
outputdef = param_def.find { |inout, paramname, typeinfo| inout == "output" }
klass, nsdef, namedef = outputdef[2]
@document_response_qname = ::XSD::QName.new(nsdef, namedef)
@doc_request_qnames = []
@doc_response_qnames = []
param_def.each do |inout, paramname, typeinfo|
klass, nsdef, namedef = typeinfo
case inout
when SOAPMethod::IN
@doc_request_qnames << XSD::QName.new(nsdef, namedef)
when SOAPMethod::OUT
@doc_response_qnames << XSD::QName.new(nsdef, namedef)
else
raise ArgumentError.new(
"illegal inout definition for document style: #{inout}")
end
end
end
end
def call(request, mapping_registry, literal_mapping_registry)
if @request_style == :rpc
param = Mapping.soap2obj(request, mapping_registry)
result = rpc_call(request, param)
else
param = Mapping.soap2obj(request, literal_mapping_registry)
result = document_call(request, param)
def request_default_encodingstyle
(@request_use == :encoded) ? EncodingNamespace : LiteralNamespace
end
if @response_style == :rpc
rpc_response(result, mapping_registry)
def response_default_encodingstyle
(@response_use == :encoded) ? EncodingNamespace : LiteralNamespace
end
def call(body, mapping_registry, literal_mapping_registry)
if @request_style == :rpc
values = request_rpc(body, mapping_registry, literal_mapping_registry)
else
document_response(result, literal_mapping_registry)
values = request_document(body, mapping_registry, literal_mapping_registry)
end
result = receiver.method(@name.intern).call(*values)
return result if result.is_a?(SOAPFault)
if @response_style == :rpc
response_rpc(result, mapping_registry, literal_mapping_registry)
else
response_doc(result, mapping_registry, literal_mapping_registry)
end
end
private
def rpc_call(request, param)
def receiver
raise NotImplementedError.new('must be defined in derived class')
end
def request_rpc(body, mapping_registry, literal_mapping_registry)
request = body.request
unless request.is_a?(SOAPStruct)
raise RPCRoutingError.new("Not an RPC style.")
raise RPCRoutingError.new("not an RPC style")
end
if @request_use == :encoded
request_rpc_enc(request, mapping_registry)
else
request_rpc_lit(request, literal_mapping_registry)
end
values = request.collect { |key, value| param[key] }
@receiver.method(@name.intern).call(*values)
end
def document_call(request, param)
@receiver.method(@name.intern).call(param)
def request_document(body, mapping_registry, literal_mapping_registry)
# ToDo: compare names with @doc_request_qnames
if @request_use == :encoded
request_doc_enc(body, mapping_registry)
else
request_doc_lit(body, literal_mapping_registry)
end
end
def rpc_response(result, mapping_registry)
soap_response = @rpc_response_factory.create_method_response
def request_rpc_enc(request, mapping_registry)
param = Mapping.soap2obj(request, mapping_registry)
request.collect { |key, value|
param[key]
}
end
def request_rpc_lit(request, mapping_registry)
request.collect { |key, value|
Mapping.soap2obj(value, mapping_registry)
}
end
def request_doc_enc(body, mapping_registry)
body.collect { |key, value|
Mapping.soap2obj(value, mapping_registry)
}
end
def request_doc_lit(body, mapping_registry)
body.collect { |key, value|
Mapping.soap2obj(value, mapping_registry)
}
end
def response_rpc(result, mapping_registry, literal_mapping_registry)
if @response_use == :encoded
response_rpc_enc(result, mapping_registry)
else
response_rpc_lit(result, literal_mapping_registry)
end
end
def response_doc(result, mapping_registry, literal_mapping_registry)
if @doc_response_qnames.size == 1 and !result.is_a?(Array)
result = [result]
end
if result.size != @doc_response_qnames.size
raise "required #{@doc_response_qnames.size} responses " +
"but #{result.size} given"
end
if @response_use == :encoded
response_doc_enc(result, mapping_registry)
else
response_doc_lit(result, literal_mapping_registry)
end
end
def response_rpc_enc(result, mapping_registry)
soap_response =
@rpc_method_factory.create_method_response(@rpc_response_qname)
if soap_response.have_outparam?
unless result.is_a?(Array)
raise RPCRoutingError.new("Out parameter was not returned.")
raise RPCRoutingError.new("out parameter was not returned")
end
outparams = {}
i = 1
soap_response.each_param_name('out', 'inout') do |outparam|
soap_response.output_params.each do |outparam|
outparams[outparam] = Mapping.obj2soap(result[i], mapping_registry)
i += 1
end
@ -283,8 +484,83 @@ private
soap_response
end
def document_response(result, literal_mapping_registry)
literal_mapping_registry.obj2soap(result, @document_response_qname)
def response_rpc_lit(result, mapping_registry)
soap_response =
@rpc_method_factory.create_method_response(@rpc_response_qname)
if soap_response.have_outparam?
unless result.is_a?(Array)
raise RPCRoutingError.new("out parameter was not returned")
end
outparams = {}
i = 1
soap_response.output_params.each do |outparam|
outparams[outparam] = Mapping.obj2soap(result[i], mapping_registry,
XSD::QName.new(nil, outparam))
i += 1
end
soap_response.set_outparam(outparams)
soap_response.retval = Mapping.obj2soap(result[0], mapping_registry,
XSD::QName.new(nil, soap_response.elename))
else
soap_response.retval = Mapping.obj2soap(result, mapping_registry,
XSD::QName.new(nil, soap_response.elename))
end
soap_response
end
def response_doc_enc(result, mapping_registry)
(0...result.size).collect { |idx|
ele = Mapping.obj2soap(result[idx], mapping_registry)
ele.elename = @doc_response_qnames[idx]
ele
}
end
def response_doc_lit(result, mapping_registry)
(0...result.size).collect { |idx|
mapping_registry.obj2soap(result[idx], @doc_response_qnames[idx])
}
end
def check_style(style)
unless [:rpc, :document].include?(style)
raise ArgumentError.new("unknown style: #{style}")
end
end
def check_use(use)
unless [:encoded, :literal].include?(use)
raise ArgumentError.new("unknown use: #{use}")
end
end
end
class ApplicationScopeOperation < Operation
def initialize(soapaction, receiver, name, param_def, opt)
super(soapaction, name, param_def, opt)
@receiver = receiver
end
private
def receiver
@receiver
end
end
class RequestScopeOperation < Operation
def initialize(soapaction, receiver_factory, name, param_def, opt)
super(soapaction, name, param_def, opt)
unless receiver_factory.respond_to?(:create)
raise TypeError.new("factory must respond to 'create'")
end
@receiver_factory = receiver_factory
end
private
def receiver
@receiver_factory.create
end
end
end

View file

@ -1,5 +1,5 @@
# SOAP4R - SOAP handler servlet for WEBrick
# Copyright (C) 2001, 2002, 2003, 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2001-2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -14,7 +14,23 @@ begin
require 'stringio'
require 'zlib'
rescue LoadError
STDERR.puts "Loading stringio or zlib failed. No gzipped response support." if $DEBUG
warn("Loading stringio or zlib failed. No gzipped response supported.") if $DEBUG
end
warn("Overriding WEBrick::Log#debug") if $DEBUG
require 'webrick/log'
module WEBrick
class Log < BasicLog
alias __debug debug
def debug(msg = nil)
if block_given? and msg.nil?
__debug(yield)
else
__debug(msg)
end
end
end
end
@ -24,61 +40,28 @@ module RPC
class SOAPlet < WEBrick::HTTPServlet::AbstractServlet
public
attr_reader :app_scope_router
attr_reader :options
def initialize
@rpc_router_map = {}
@app_scope_router = ::SOAP::RPC::Router.new(self.class.name)
@headerhandlerfactory = []
@app_scope_headerhandler = nil
def initialize(router = nil)
@router = router || ::SOAP::RPC::Router.new(self.class.name)
@options = {}
@config = {}
end
# for backward compatibility
def app_scope_router
@router
end
# for backward compatibility
def add_servant(obj, namespace)
@router.add_rpc_servant(obj, namespace)
end
def allow_content_encoding_gzip=(allow)
@options[:allow_content_encoding_gzip] = allow
end
# Add servant factory whose object has request scope. A servant object is
# instanciated for each request.
#
# Bear in mind that servant factories 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 factory.
# I mean, use Driver#add_method_with_soapaction instead of Driver#add_method
# at client side.
#
# A factory must respond to :create.
#
def add_rpc_request_servant(factory, namespace, mapping_registry = nil)
unless factory.respond_to?(:create)
raise TypeError.new("factory must respond to 'create'")
end
router = setup_rpc_request_router(namespace)
router.factory = factory
router.mapping_registry = mapping_registry
end
# Add servant object which has application scope.
def add_rpc_servant(obj, namespace)
router = @app_scope_router
SOAPlet.add_rpc_servant_to_router(router, obj, namespace)
add_rpc_router(namespace, router)
end
alias add_servant add_rpc_servant
def add_rpc_request_headerhandler(factory)
unless factory.respond_to?(:create)
raise TypeError.new("factory must respond to 'create'")
end
@headerhandlerfactory << factory
end
def add_rpc_headerhandler(obj)
@app_scope_headerhandler = obj
end
alias add_headerhandler add_rpc_headerhandler
###
## Servlet interfaces for WEBrick.
#
@ -93,19 +76,43 @@ public
def do_GET(req, res)
res.header['Allow'] = 'POST'
raise WEBrick::HTTPStatus::MethodNotAllowed, "GET request not allowed."
raise WEBrick::HTTPStatus::MethodNotAllowed, "GET request not allowed"
end
def do_POST(req, res)
@config[:Logger].debug { "SOAP request: " + req.body }
soapaction = parse_soapaction(req.meta_vars['HTTP_SOAPACTION'])
router = lookup_router(soapaction)
with_headerhandler(router) do |router|
logger.debug { "SOAP request: " + req.body } if logger
begin
conn_data = ::SOAP::StreamHandler::ConnectionData.new
setup_req(conn_data, req)
conn_data = @router.route(conn_data)
setup_res(conn_data, req, res)
rescue Exception => e
conn_data = @router.create_fault_response(e)
res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR
res.body = conn_data.send_string
res['content-type'] = conn_data.send_contenttype || "text/xml"
end
if res.body.is_a?(IO)
res.chunked = true
logger.debug { "SOAP response: (chunked response not logged)" } if logger
else
logger.debug { "SOAP response: " + res.body } if logger
end
end
private
def logger
@config[:Logger]
end
def setup_req(conn_data, req)
conn_data.receive_string = req.body
conn_data.receive_contenttype = req['content-type']
conn_data = router.route(conn_data)
conn_data.soapaction = parse_soapaction(req.meta_vars['HTTP_SOAPACTION'])
end
def setup_res(conn_data, req, res)
res['content-type'] = conn_data.send_contenttype
if conn_data.is_fault
res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR
@ -117,87 +124,15 @@ public
else
res.body = conn_data.send_string
end
rescue Exception => e
conn_data = router.create_fault_response(e)
res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR
res.body = conn_data.send_string
res['content-type'] = conn_data.send_contenttype || "text/xml"
end
end
if res.body.is_a?(IO)
res.chunked = true
@config[:Logger].debug { "SOAP response: (chunked response not logged)" }
else
@config[:Logger].debug { "SOAP response: " + res.body }
end
end
private
class RequestRouter < ::SOAP::RPC::Router
attr_accessor :factory
def initialize(style = :rpc, namespace = nil)
super(namespace)
@style = style
@namespace = namespace
@factory = nil
end
def route(soap_string)
obj = @factory.create
namespace = self.actor
router = ::SOAP::RPC::Router.new(@namespace)
if @style == :rpc
SOAPlet.add_rpc_servant_to_router(router, obj, namespace)
else
raise RuntimeError.new("'document' style not supported.")
end
router.route(soap_string)
end
end
def setup_rpc_request_router(namespace)
router = @rpc_router_map[namespace] || RequestRouter.new(:rpc, namespace)
add_rpc_router(namespace, router)
router
end
def add_rpc_router(namespace, router)
@rpc_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
@rpc_router_map[namespace] || @app_scope_router
else
@app_scope_router
if !soapaction.nil? and !soapaction.empty?
if /^"(.+)"$/ =~ soapaction
return $1
end
end
def with_headerhandler(router)
if @app_scope_headerhandler and
!router.headerhandler.include?(@app_scope_headerhandler)
router.headerhandler.add(@app_scope_headerhandler)
end
handlers = @headerhandlerfactory.collect { |f| f.create }
begin
handlers.each { |h| router.headerhandler.add(h) }
yield(router)
ensure
handlers.each { |h| router.headerhandler.delete(h) }
end
nil
end
def encode_gzip(req, outstring)
@ -219,32 +154,6 @@ private
req['accept-encoding'] and
req['accept-encoding'].split(/,\s*/).include?('gzip')
end
class << self
public
def add_rpc_servant_to_router(router, obj, namespace)
::SOAP::RPC.defined_methods(obj).each do |name|
begin
add_rpc_servant_method_to_router(router, obj, namespace, name)
rescue SOAP::RPC::MethodDefinitionError => e
p e if $DEBUG
end
end
end
def add_rpc_servant_method_to_router(router, obj, namespace, name,
style = :rpc, use = :encoded)
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 }" })
opt = {}
opt[:request_style] = opt[:response_style] = style
opt[:request_use] = opt[:response_use] = use
router.add_operation(qname, soapaction, obj, name, param_def, opt)
end
end
end

View file

@ -13,7 +13,7 @@ require 'xsd/charset'
module SOAP
Version = '1.5.3-ruby1.8.2'
VERSION = Version = '1.5.4'
PropertyName = 'soap/property'
EnvelopeNamespace = 'http://schemas.xmlsoap.org/soap/envelope/'
@ -75,6 +75,7 @@ class ArrayIndexOutOfBoundsError < Error; end
class ArrayStoreError < Error; end
class RPCRoutingError < Error; end
class EmptyResponseError < Error; end
class UnhandledMustUnderstandHeaderError < Error; end
@ -101,6 +102,7 @@ class FaultError < Error
end
end
module Env
def self.getenv(name)
ENV[name.downcase] || ENV[name.upcase]
@ -113,3 +115,25 @@ end
end
unless Object.respond_to?(:instance_variable_get)
class Object
def instance_variable_get(ivarname)
instance_eval(ivarname)
end
def instance_variable_set(ivarname, value)
instance_eval("#{ivarname} = value")
end
end
end
unless Kernel.respond_to?(:warn)
module Kernel
def warn(msg)
STDERR.puts(msg + "\n") unless $VERBOSE.nil?
end
end
end

View file

@ -7,12 +7,12 @@
require 'soap/soap'
require 'soap/property'
require 'soap/httpconfigloader'
begin
require 'stringio'
require 'zlib'
rescue LoadError
STDERR.puts "Loading stringio or zlib failed. No gzipped response support." if $DEBUG
warn("Loading stringio or zlib failed. No gzipped response support.") if $DEBUG
end
@ -27,7 +27,7 @@ class StreamHandler
end
HTTPAccess2::Client
rescue LoadError
STDERR.puts "Loading http-access2 failed. Net/http is used." if $DEBUG
warn("Loading http-access2 failed. Net/http is used.") if $DEBUG
require 'soap/netHttpClient'
SOAP::NetHttpClient
end
@ -40,6 +40,7 @@ class StreamHandler
attr_accessor :receive_string
attr_accessor :receive_contenttype
attr_accessor :is_fault
attr_accessor :soapaction
def initialize(send_string = nil)
@send_string = send_string
@ -47,6 +48,7 @@ class StreamHandler
@receive_string = nil
@receive_contenttype = nil
@is_fault = false
@soapaction = nil
end
end
@ -79,7 +81,7 @@ public
super()
@client = Client.new(nil, "SOAP4R/#{ Version }")
@wiredump_file_base = nil
@charset = @wiredump_dev = @nil
@charset = @wiredump_dev = nil
@options = options
set_options
@client.debug_dev = @wiredump_dev
@ -100,7 +102,8 @@ public
end
def send(endpoint_url, conn_data, soapaction = nil, charset = @charset)
send_post(endpoint_url, conn_data, soapaction, charset)
conn_data.soapaction ||= soapaction # for backward conpatibility
send_post(endpoint_url, conn_data, charset)
end
def reset(endpoint_url = nil)
@ -115,24 +118,7 @@ public
private
def set_options
@client.proxy = @options["proxy"]
@options.add_hook("proxy") do |key, value|
@client.proxy = value
end
@client.no_proxy = @options["no_proxy"]
@options.add_hook("no_proxy") do |key, value|
@client.no_proxy = value
end
if @client.respond_to?(:protocol_version=)
@client.protocol_version = @options["protocol_version"]
@options.add_hook("protocol_version") do |key, value|
@client.protocol_version = value
end
end
set_cookie_store_file(@options["cookie_store_file"])
@options.add_hook("cookie_store_file") do |key, value|
set_cookie_store_file(value)
end
HTTPConfigLoader.set_options(@client, @options)
@charset = @options["charset"] || XSD::Charset.charset_label($KCODE)
@options.add_hook("charset") do |key, value|
@charset = value
@ -142,96 +128,23 @@ private
@wiredump_dev = value
@client.debug_dev = @wiredump_dev
end
ssl_config = @options["ssl_config"] ||= ::SOAP::Property.new
set_ssl_config(ssl_config)
ssl_config.add_hook(true) do |key, value|
set_ssl_config(ssl_config)
end
basic_auth = @options["basic_auth"] ||= ::SOAP::Property.new
set_basic_auth(basic_auth)
basic_auth.add_hook do |key, value|
set_basic_auth(basic_auth)
end
@options.add_hook("connect_timeout") do |key, value|
@client.connect_timeout = value
end
@options.add_hook("send_timeout") do |key, value|
@client.send_timeout = value
end
@options.add_hook("receive_timeout") do |key, value|
@client.receive_timeout = value
set_cookie_store_file(@options["cookie_store_file"])
@options.add_hook("cookie_store_file") do |key, value|
set_cookie_store_file(value)
end
ssl_config = @options["ssl_config"]
basic_auth = @options["basic_auth"]
@options.lock(true)
ssl_config.unlock
basic_auth.unlock
end
def set_basic_auth(basic_auth)
basic_auth.values.each do |url, userid, passwd|
@client.set_basic_auth(url, userid, passwd)
end
end
def set_cookie_store_file(value)
@cookie_store = value
@client.set_cookie_store(@cookie_store) if @cookie_store
end
def set_ssl_config(ssl_config)
ssl_config.each do |key, value|
cfg = @client.ssl_config
case key
when 'client_cert'
cfg.client_cert = cert_from_file(value)
when 'client_key'
cfg.client_key = key_from_file(value)
when 'client_ca'
cfg.client_ca = value
when 'ca_path'
cfg.set_trust_ca(value)
when 'ca_file'
cfg.set_trust_ca(value)
when 'crl'
cfg.set_crl(value)
when 'verify_mode'
cfg.verify_mode = ssl_config_int(value)
when 'verify_depth'
cfg.verify_depth = ssl_config_int(value)
when 'options'
cfg.options = value
when 'ciphers'
cfg.ciphers = value
when 'verify_callback'
cfg.verify_callback = value
when 'cert_store'
cfg.cert_store = value
else
raise ArgumentError.new("unknown ssl_config property #{key}")
end
end
end
def ssl_config_int(value)
if value.nil? or value.empty?
nil
else
begin
Integer(value)
rescue ArgumentError
::SOAP::Property::Util.const_from_name(value)
end
end
end
def cert_from_file(filename)
OpenSSL::X509::Certificate.new(File.open(filename) { |f| f.read })
end
def key_from_file(filename)
OpenSSL::PKey::RSA.new(File.open(filename) { |f| f.read })
end
def send_post(endpoint_url, conn_data, soapaction, charset)
def send_post(endpoint_url, conn_data, charset)
conn_data.send_contenttype ||= StreamHandler.create_media_type(charset)
if @wiredump_file_base
@ -243,7 +156,7 @@ private
extra = {}
extra['Content-Type'] = conn_data.send_contenttype
extra['SOAPAction'] = "\"#{ soapaction }\""
extra['SOAPAction'] = "\"#{ conn_data.soapaction }\""
extra['Accept-Encoding'] = 'gzip' if send_accept_encoding_gzip?
send_string = conn_data.send_string
@wiredump_dev << "Wire dump:\n\n" if @wiredump_dev

View file

@ -1,5 +1,5 @@
# SOAP4R - SOAP WSDL driver
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -9,19 +9,11 @@
require 'wsdl/parser'
require 'wsdl/importer'
require 'xsd/qname'
require 'soap/element'
require 'soap/baseData'
require 'soap/streamHandler'
require 'soap/mimemessage'
require 'soap/mapping'
require 'xsd/codegen/gensupport'
require 'soap/mapping/wsdlencodedregistry'
require 'soap/mapping/wsdlliteralregistry'
require 'soap/rpc/rpc'
require 'soap/rpc/element'
require 'soap/rpc/proxy'
require 'soap/processor'
require 'soap/header/handlerset'
require 'xsd/codegen/gensupport'
require 'soap/rpc/driver'
require 'wsdl/soap/methodDefCreator'
module SOAP
@ -32,35 +24,27 @@ class WSDLDriverFactory
attr_reader :wsdl
def initialize(wsdl, logdev = nil)
@logdev = logdev
def initialize(wsdl)
@wsdl = import(wsdl)
@methoddefcreator = WSDL::SOAP::MethodDefCreator.new(@wsdl)
end
def inspect
"#<#{self.class}:#{@wsdl.name}>"
end
def create_rpc_driver(servicename = nil, portname = nil)
port = find_port(servicename, portname)
drv = SOAP::RPC::Driver.new(port.soap_address.location)
init_driver(drv, port)
add_operation(drv, port)
drv
end
# depricated old interface
def create_driver(servicename = nil, portname = nil)
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
warn("WSDLDriverFactory#create_driver is depricated. Use create_rpc_driver instead.")
port = find_port(servicename, portname)
WSDLDriver.new(@wsdl, port, @logdev)
end
@ -69,14 +53,110 @@ class WSDLDriverFactory
private
def find_port(servicename = nil, portname = nil)
service = port = nil
if servicename
service = @wsdl.service(
XSD::QName.new(@wsdl.targetnamespace, servicename))
else
service = @wsdl.services[0]
end
if service.nil?
raise FactoryError.new("service #{servicename} not found in WSDL")
end
if portname
port = service.ports[XSD::QName.new(@wsdl.targetnamespace, portname)]
else
port = 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
port
end
def init_driver(drv, port)
wsdl_elements = @wsdl.collect_elements
wsdl_types = @wsdl.collect_complextypes + @wsdl.collect_simpletypes
rpc_decode_typemap = wsdl_types +
@wsdl.soap_rpc_complextypes(port.find_binding)
drv.proxy.mapping_registry =
Mapping::WSDLEncodedRegistry.new(rpc_decode_typemap)
drv.proxy.literal_mapping_registry =
Mapping::WSDLLiteralRegistry.new(wsdl_types, wsdl_elements)
end
def add_operation(drv, port)
port.find_binding.operations.each do |op_bind|
op_name = op_bind.soapoperation_name
soapaction = op_bind.soapaction || ''
orgname = op_name.name
name = XSD::CodeGen::GenSupport.safemethodname(orgname)
param_def = create_param_def(op_bind)
opt = {}
opt[:request_style] = opt[:response_style] = op_bind.soapoperation_style
opt[:request_use] = (op_bind.input.soapbody.use || 'literal').intern
opt[:response_use] = (op_bind.output.soapbody.use || 'literal').intern
if op_bind.soapoperation_style == :rpc
drv.add_rpc_operation(op_name, soapaction, name, param_def, opt)
else
drv.add_document_operation(soapaction, name, param_def, opt)
end
if orgname != name and orgname.capitalize == name.capitalize
::SOAP::Mapping.define_singleton_method(drv, orgname) do |*arg|
__send__(name, *arg)
end
end
end
end
def import(location)
WSDL::Importer.import(location)
end
def create_param_def(op_bind)
op = op_bind.find_operation
if op_bind.soapoperation_style == :rpc
param_def = @methoddefcreator.collect_rpcparameter(op)
else
param_def = @methoddefcreator.collect_documentparameter(op)
end
# the first element of typedef in param_def is a String like
# "::SOAP::SOAPStruct". turn this String to a class.
param_def.collect { |io, typedef, name|
typedef[0] = Mapping.class_from_name(typedef[0])
[io, name, typedef]
}
end
def partqname(part)
if part.type
part.type
else
part.element
end
end
def param_def(type, name, klass, partqname)
[type, name, [klass, partqname.namespace, partqname.name]]
end
def filter_parts(partsdef, partssource)
parts = partsdef.split(/\s+/)
partssource.find_all { |part| parts.include?(part.name) }
end
end
class WSDLDriver
class << self
def __attr_proxy(symbol, assignable = false)
end
if RUBY_VERSION >= "1.7.0"
def __attr_proxy(symbol, assignable = false)
name = symbol.to_s
self.__send__(:define_method, name, proc {
@ -88,6 +168,23 @@ class WSDLDriver
})
end
end
else
def __attr_proxy(symbol, assignable = false)
name = symbol.to_s
module_eval <<-EOS
def #{name}
@servant.#{name}
end
EOS
if assignable
module_eval <<-EOS
def #{name}=(value)
@servant.#{name} = value
end
EOS
end
end
end
end
__attr_proxy :options
@ -179,8 +276,10 @@ class WSDLDriver
@wsdl_types = @wsdl.collect_complextypes + @wsdl.collect_simpletypes
@rpc_decode_typemap = @wsdl_types +
@wsdl.soap_rpc_complextypes(port.find_binding)
@wsdl_mapping_registry = Mapping::WSDLEncodedRegistry.new(@rpc_decode_typemap)
@doc_mapper = Mapping::WSDLLiteralRegistry.new(@wsdl_elements, @wsdl_types)
@wsdl_mapping_registry = Mapping::WSDLEncodedRegistry.new(
@rpc_decode_typemap)
@doc_mapper = Mapping::WSDLLiteralRegistry.new(
@wsdl_types, @wsdl_elements)
endpoint_url = @port.soap_address.location
# Convert a map which key is QName, to a Hash which key is String.
@operation = {}
@ -222,15 +321,16 @@ class WSDLDriver
def rpc_call(name, *values)
set_wiredump_file_base(name)
unless op_info = @operation[name]
raise MethodDefinitionError, "Method: #{name} not defined."
raise RuntimeError, "method: #{name} not defined"
end
req_header = create_request_header
req_body = create_request_body(op_info, *values)
opt = create_options({
:soapaction => op_info.soapaction || @soapaction,
reqopt = create_options({
:soapaction => op_info.soapaction || @soapaction})
resopt = create_options({
:decode_typemap => @rpc_decode_typemap})
env = @proxy.invoke(req_header, req_body, opt)
raise EmptyResponseError.new("Empty response.") unless env
env = @proxy.route(req_header, req_body, reqopt, resopt)
raise EmptyResponseError unless env
receive_headers(env.header)
begin
@proxy.check_fault(env.body)
@ -249,21 +349,6 @@ class WSDLDriver
end
end
def document_call(name, param)
set_wiredump_file_base(name)
op_info = @operation[name]
req_header = header_from_obj(header_obj, op_info)
req_body = body_from_obj(body_obj, op_info)
env = @proxy.invoke(req_header, req_body, op_info.soapaction || @soapaction, @wsdl_types)
raise EmptyResponseError.new("Empty response.") unless env
if env.body.fault
raise ::SOAP::FaultError.new(env.body.fault)
end
res_body_obj = env.body.response ?
Mapping.soap2obj(env.body.response, @mapping_registry) : nil
return env.header, res_body_obj
end
# req_header: [[element, mustunderstand, encodingstyle(QName/String)], ...]
# req_body: SOAPBasetype/SOAPCompoundtype
def document_send(name, header_obj, body_obj)
@ -275,7 +360,7 @@ class WSDLDriver
:soapaction => op_info.soapaction || @soapaction,
:decode_typemap => @wsdl_types})
env = @proxy.invoke(req_header, req_body, opt)
raise EmptyResponseError.new("Empty response.") unless env
raise EmptyResponseError unless env
if env.body.fault
raise ::SOAP::FaultError.new(env.body.fault)
end
@ -297,7 +382,7 @@ class WSDLDriver
def set_wiredump_file_base(name)
if @wiredump_file_base
@proxy.set_wiredump_file_base(@wiredump_file_base + "_#{ name }")
@proxy.set_wiredump_file_base(@wiredump_file_base + "_#{name}")
end
end
@ -326,7 +411,7 @@ class WSDLDriver
def create_method_struct(op_info, *params)
parts_names = op_info.bodyparts.collect { |part| part.name }
obj = create_method_obj(parts_names, params)
method = Mapping.obj2soap(obj, @wsdl_mapping_registry, op_info.optype_name)
method = Mapping.obj2soap(obj, @wsdl_mapping_registry, op_info.op_name)
if method.members.size != parts_names.size
new_method = SOAPStruct.new
method.each do |key, value|
@ -356,7 +441,7 @@ class WSDLDriver
if obj.nil?
nil
else
raise RuntimeError.new("No header definition in schema.")
raise RuntimeError.new("no header definition in schema: #{obj}")
end
elsif op_info.headerparts.size == 1
part = op_info.headerparts[0]
@ -366,7 +451,7 @@ class WSDLDriver
else
header = SOAPHeader.new()
op_info.headerparts.each do |part|
child = Mapping.find_attribute(obj, part.name)
child = Mapping.get_attribute(obj, part.name)
ele = headeritem_from_obj(child, part.element || part.eletype)
header.add(part.name, ele)
end
@ -391,7 +476,7 @@ class WSDLDriver
if obj.nil?
nil
else
raise RuntimeError.new("No body found in schema.")
raise RuntimeError.new("no body found in schema")
end
elsif op_info.bodyparts.size == 1
part = op_info.bodyparts[0]
@ -400,7 +485,7 @@ class WSDLDriver
else
body = SOAPBody.new
op_info.bodyparts.each do |part|
child = Mapping.find_attribute(obj, part.name)
child = Mapping.get_attribute(obj, part.name)
ele = bodyitem_from_obj(child, part.element || part.type)
body.add(ele.elename.name, ele)
end
@ -419,39 +504,40 @@ class WSDLDriver
end
def add_method_interface(op_info)
name = ::XSD::CodeGen::GenSupport.safemethodname(op_info.op_name.name)
name = XSD::CodeGen::GenSupport.safemethodname(op_info.op_name.name)
orgname = op_info.op_name.name
parts_names = op_info.bodyparts.collect { |part| part.name }
case op_info.style
when :document
add_document_method_interface(name)
if orgname != name and orgname.capitalize == name.capitalize
add_document_method_interface(orgname, parts_names)
end
add_document_method_interface(name, parts_names)
when :rpc
parts_names = op_info.bodyparts.collect { |part| part.name }
orgname = op_info.op_name.name
if orgname != name and orgname.capitalize == name.capitalize
add_rpc_method_interface(orgname, parts_names)
end
add_rpc_method_interface(name, parts_names)
else
raise RuntimeError.new("Unknown style: #{op_info.style}")
raise RuntimeError.new("unknown style: #{op_info.style}")
end
end
def add_rpc_method_interface(name, parts_names)
sclass = class << @host; self; end
sclass.__send__(:define_method, name, proc { |*arg|
::SOAP::Mapping.define_singleton_method(@host, name) do |*arg|
unless arg.size == parts_names.size
raise ArgumentError.new(
"wrong number of arguments (#{arg.size} for #{parts_names.size})")
end
@servant.rpc_call(name, *arg)
})
end
@host.method(name)
end
def add_document_method_interface(name)
sclass = class << @host; self; end
sclass.__send__(:define_method, name, proc { |h, b|
def add_document_method_interface(name, parts_names)
::SOAP::Mapping.define_singleton_method(@host, name) do |*arg|
@servant.document_send(name, h, b)
})
end
@host.method(name)
end
@ -476,5 +562,3 @@ end
end

View file

@ -18,19 +18,16 @@ class Definitions < Info
attr_reader :targetnamespace
attr_reader :imports
# Overrides Info#root
def root
@root
end
def root=(root)
@root = root
end
attr_accessor :location
attr_reader :importedschema
def initialize
super
@name = nil
@targetnamespace = nil
@location = nil
@importedschema = {}
@types = nil
@imports = []
@messages = XSD::NamedElements.new
@ -53,6 +50,19 @@ class Definitions < Info
end
end
def collect_attributes
result = XSD::NamedElements.new
if @types
@types.schemas.each do |schema|
result.concat(schema.collect_attributes)
end
end
@imports.each do |import|
result.concat(import.content.collect_attributes)
end
result
end
def collect_elements
result = XSD::NamedElements.new
if @types

View file

@ -45,7 +45,15 @@ class Import < Info
end
@namespace
when LocationAttrName
@location = value.source
@location = URI.parse(value.source)
if @location.relative? and !parent.location.nil? and
!parent.location.relative?
@location = parent.location + @location
end
if root.importedschema.key?(@location)
@content = root.importedschema[@location]
else
root.importedschema[@location] = nil # placeholder
@content = import(@location)
if @content.is_a?(Definitions)
@content.root = root
@ -53,6 +61,8 @@ class Import < Info
@content.targetnamespace = @namespace
end
end
root.importedschema[@location] = @content
end
@location
else
nil
@ -62,7 +72,7 @@ class Import < Info
private
def import(location)
Importer.import(location)
Importer.import(location, root)
end
end

View file

@ -1,69 +1,37 @@
# WSDL4R - WSDL importer library.
# Copyright (C) 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
# either the dual license version in 2003, or any later version.
require 'wsdl/info'
require 'wsdl/xmlSchema/importer'
require 'wsdl/parser'
require 'soap/soap'
require 'soap/property'
module WSDL
class Importer
def self.import(location)
new.import(location)
end
def initialize
@web_client = nil
end
def import(location)
STDERR.puts("importing: #{location}") if $DEBUG
content = nil
if FileTest.exist?(location)
content = File.open(location).read
else
client = web_client.new(nil, "WSDL4R")
if opt = ::SOAP::Property.loadproperty(::SOAP::PropertyName)
client.proxy = opt["client.protocol.http.proxy"]
client.no_proxy = opt["client.protocol.http.no_proxy"]
end
client.proxy ||= ::SOAP::Env::HTTP_PROXY
client.no_proxy ||= ::SOAP::Env::NO_PROXY
content = client.get_content(location)
end
opt = {}
begin
WSDL::Parser.new(opt).parse(content)
rescue WSDL::Parser::ParseError => orgexcn
require 'wsdl/xmlSchema/parser'
WSDL::XMLSchema::Parser.new(opt).parse(content)
end
class Importer < WSDL::XMLSchema::Importer
def self.import(location, originalroot = nil)
new.import(location, originalroot)
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.")
def parse(content, location, originalroot)
opt = {
:location => location,
:originalroot => originalroot
}
begin
WSDL::Parser.new(opt).parse(content)
rescue WSDL::Parser::ParseError
super(content, location, originalroot)
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

View file

@ -10,16 +10,22 @@ module WSDL
class Info
attr_accessor :root
attr_accessor :parent
attr_accessor :id
def initialize
@root = nil
@parent = nil
@id = nil
end
def root
@parent.root
def inspect
if self.respond_to?(:name)
sprintf("#<%s:0x%x %s>", self.class.name, __id__, self.name)
else
sprintf("#<%s:0x%x>", self.class.name, __id__)
end
end
def parse_element(element); end # abstract

View file

@ -46,21 +46,23 @@ class Operation < Info
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)
typename = input.find_message.name
NameInfo.new(@name, typename, 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)
typename = output.find_message.name
NameInfo.new(@name, typename, outputparts)
end
def inputparts
sort_parts(input.find_message.parts)
end
def inputname
XSD::QName.new(targetnamespace, input.name ? input.name.name : @name.name)
end
def outputparts
sort_parts(output.find_message.parts)
end

View file

@ -37,7 +37,35 @@ class OperationBinding < Info
end
def find_operation
porttype.operations[@name]
porttype.operations[@name] or raise RuntimeError.new("#{@name} not found")
end
def soapoperation_name
if @soapoperation
@soapoperation.input_info.op_name
else
find_operation.name
end
end
def soapoperation_style
style = nil
if @soapoperation
style = @soapoperation.operation_style
elsif parent.soapbinding
style = parent.soapbinding.style
else
raise TypeError.new("operation style definition not found")
end
style || :document
end
def soapaction
if @soapoperation
@soapoperation.soapaction
else
nil
end
end
def parse_element(element)

View file

@ -33,7 +33,7 @@ class Param < Info
end
def find_message
root.message(@message)
root.message(@message) or raise RuntimeError.new("#{@message} not found")
end
def parse_element(element)
@ -61,6 +61,9 @@ class Param < Info
def parse_attr(attr, value)
case attr
when MessageAttrName
if value.namespace.nil?
value = XSD::QName.new(targetnamespace, value.source)
end
@message = value
when NameAttrName
@name = XSD::QName.new(targetnamespace, value.source)

View file

@ -1,5 +1,5 @@
# WSDL4R - WSDL XML Instance parser library.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -53,6 +53,9 @@ public
@parser = XSD::XMLParser.create_parser(self, opt)
@parsestack = nil
@lastnode = nil
@ignored = {}
@location = opt[:location]
@originalroot = opt[:originalroot]
end
def parse(string_or_readable)
@ -96,7 +99,7 @@ public
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 }'.")
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
@ -106,20 +109,31 @@ private
def decode_tag(ns, name, attrs, parent)
o = nil
element = ns.parse(name)
elename = ns.parse(name)
if !parent
if element == DefinitionsName
o = Definitions.parse_element(element)
if elename == DefinitionsName
o = Definitions.parse_element(elename)
o.location = @location
else
raise UnknownElementError.new("Unknown element #{ element }.")
raise UnknownElementError.new("unknown element: #{elename}")
end
o.root = @originalroot if @originalroot # o.root = o otherwise
else
o = parent.parse_element(element)
if elename == XMLSchema::AnnotationName
# only the first annotation element is allowed for each xsd element.
o = XMLSchema::Annotation.new
else
o = parent.parse_element(elename)
end
unless o
STDERR.puts("Unknown element #{ element }.")
unless @ignored.key?(elename)
warn("ignored element: #{elename}")
@ignored[elename] = elename
end
o = Documentation.new # which accepts any element.
end
# node could be a pseudo element. pseudo element has its own parent.
o.root = parent.root
o.parent = parent if o.parent.nil?
end
attrs.each do |key, value|
@ -127,7 +141,10 @@ private
value_ele = ns.parse(value, true)
value_ele.source = value # for recovery; value may not be a QName
unless o.parse_attr(attr_ele, value_ele)
STDERR.puts("Unknown attr #{ attr_ele }.")
unless @ignored.key?(attr_ele)
warn("ignored attr: #{attr_ele}")
@ignored[attr_ele] = attr_ele
end
end
end
o

View file

@ -33,7 +33,7 @@ class Port < Info
end
def find_binding
root.binding(@binding)
root.binding(@binding) or raise RuntimeError.new("#{@binding} not found")
end
def inputoperation_map

View file

@ -28,7 +28,8 @@ class PortType < Info
end
def find_binding
root.bindings.find { |item| item.type == @name }
root.bindings.find { |item| item.type == @name } or
raise RuntimeError.new("#{@name} not found")
end
def locations

View file

@ -1,5 +1,5 @@
# WSDL4R - Creating CGI stub code from WSDL.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -26,9 +26,7 @@ class CGIStubCreator
end
def dump(service_name)
STDERR.puts "!!! IMPORTANT !!!"
STDERR.puts "- CGI stub can only 1 port. Creating stub for the first port... Rests are ignored."
STDERR.puts "!!! IMPORTANT !!!"
warn("CGI stub can have only 1 port. Creating stub for the first port... Rests are ignored.")
port = @definitions.service(service_name).ports[0]
dump_porttype(port.porttype.name)
end
@ -39,28 +37,28 @@ private
class_name = create_class_name(name)
methoddef, types = MethodDefCreator.new(@definitions).dump(name)
mr_creator = MappingRegistryCreator.new(@definitions)
c1 = ::XSD::CodeGen::ClassDef.new(class_name)
c1 = XSD::CodeGen::ClassDef.new(class_name)
c1.def_require("soap/rpc/cgistub")
c1.def_require("soap/mapping/registry")
c1.def_const("MappingRegistry", "::SOAP::Mapping::Registry.new")
c1.def_code(mr_creator.dump(types))
c1.def_code <<-EOD
Methods = [
#{ methoddef.gsub(/^/, " ") }
#{methoddef.gsub(/^/, " ")}
]
EOD
c2 = ::XSD::CodeGen::ClassDef.new(class_name + "App",
c2 = XSD::CodeGen::ClassDef.new(class_name + "App",
"::SOAP::RPC::CGIStub")
c2.def_method("initialize", "*arg") do
<<-EOD
super(*arg)
servant = #{class_name}.new
#{class_name}::Methods.each do |name_as, name, param_def, soapaction, namespace, style|
qname = XSD::QName.new(namespace, name_as)
if style == :document
@router.add_document_method(servant, qname, soapaction, name, param_def)
@router.add_document_operation(servant, soapaction, name, param_def)
else
@router.add_rpc_method(servant, qname, soapaction, name, param_def)
qname = XSD::QName.new(namespace, name_as)
@router.add_rpc_operation(servant, qname, soapaction, name, param_def)
end
end
self.mapping_registry = #{class_name}::MappingRegistry

View file

@ -1,5 +1,5 @@
# WSDL4R - Creating class definition from WSDL
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -22,13 +22,16 @@ class ClassDefCreator
@elements = definitions.collect_elements
@simpletypes = definitions.collect_simpletypes
@complextypes = definitions.collect_complextypes
@faulttypes = definitions.collect_faulttypes if definitions.respond_to?(:collect_faulttypes)
@faulttypes = nil
if definitions.respond_to?(:collect_faulttypes)
@faulttypes = definitions.collect_faulttypes
end
end
def dump(class_name = nil)
result = ''
if class_name
result = dump_classdef(class_name)
def dump(type = nil)
result = "require 'xsd/qname'\n"
if type
result = dump_classdef(type.name, type)
else
str = dump_element
unless str.empty?
@ -53,117 +56,129 @@ private
def dump_element
@elements.collect { |ele|
ele.local_complextype ? dump_classdef(ele) : ''
}.join("\n")
if ele.local_complextype
dump_classdef(ele.name, ele.local_complextype)
elsif ele.local_simpletype
dump_simpletypedef(ele.name, ele.local_simpletype)
else
nil
end
}.compact.join("\n")
end
def dump_simpletype
@simpletypes.collect { |type|
dump_simpletypedef(type)
}.join("\n")
dump_simpletypedef(type.name, type)
}.compact.join("\n")
end
def dump_complextype
@complextypes.collect { |type|
case type.compoundtype
when :TYPE_STRUCT
dump_classdef(type)
when :TYPE_STRUCT, :TYPE_EMPTY
dump_classdef(type.name, type)
when :TYPE_ARRAY
dump_arraydef(type)
when :TYPE_SIMPLE
STDERR.puts("not implemented: ToDo")
dump_simpleclassdef(type)
when :TYPE_MAP
# mapped as a general Hash
nil
else
raise RuntimeError.new(
"Unknown kind of complexContent: #{type.compoundtype}")
"unknown kind of complexContent: #{type.compoundtype}")
end
}.join("\n")
}.compact.join("\n")
end
def dump_simpletypedef(simpletype)
qname = simpletype.name
if simpletype.restriction.enumeration.empty?
STDERR.puts("#{qname}: simpleType which is not enum type not supported.")
return ''
def dump_simpletypedef(qname, simpletype)
if !simpletype.restriction or simpletype.restriction.enumeration.empty?
return nil
end
c = XSD::CodeGen::ModuleDef.new(create_class_name(qname))
c.comment = "#{ qname.namespace }"
c.comment = "#{qname}"
const = {}
simpletype.restriction.enumeration.each do |value|
c.def_const(safeconstname(value), value.dump)
constname = safeconstname(value)
const[constname] ||= 0
if (const[constname] += 1) > 1
constname += "_#{const[constname]}"
end
c.def_const(constname, ndq(value))
end
c.dump
end
def dump_classdef(type_or_element)
def dump_simpleclassdef(type_or_element)
qname = type_or_element.name
base = create_class_name(type_or_element.simplecontent.base)
c = XSD::CodeGen::ClassDef.new(create_class_name(qname), base)
c.comment = "#{qname}"
c.dump
end
def dump_classdef(qname, typedef)
if @faulttypes and @faulttypes.index(qname)
c = XSD::CodeGen::ClassDef.new(create_class_name(qname),
'::StandardError')
else
c = XSD::CodeGen::ClassDef.new(create_class_name(qname))
end
c.comment = "#{ qname.namespace }"
c.def_classvar('schema_type', qname.name.dump)
c.def_classvar('schema_ns', qname.namespace.dump)
schema_attribute = []
c.comment = "#{qname}"
c.def_classvar('schema_type', ndq(qname.name))
c.def_classvar('schema_ns', ndq(qname.namespace))
schema_element = []
init_lines = ''
params = []
type_or_element.each_element do |element|
next unless element.name
name = element.name.name
typedef.each_element do |element|
if element.type == XSD::AnyTypeName
type = nil
elsif basetype = basetype_class(element.type)
type = basetype.name
else
elsif klass = element_basetype(element)
type = klass.name
elsif element.type
type = create_class_name(element.type)
else
type = nil # means anyType.
# do we define a class for local complexType from it's name?
# type = create_class_name(element.name)
# <element>
# <complexType>
# <seq...>
# </complexType>
# </element>
end
name = name_element(element).name
attrname = safemethodname?(name) ? name : safemethodname(name)
varname = safevarname(name)
c.def_attr(attrname, true, varname)
init_lines << "@#{ varname } = #{ varname }\n"
init_lines << "@#{varname} = #{varname}\n"
if element.map_as_array?
params << "#{ varname } = []"
type << '[]'
params << "#{varname} = []"
type << '[]' if type
else
params << "#{ varname } = nil"
params << "#{varname} = nil"
end
schema_element << [name, type]
eleqname = (varname == name) ? nil : element.name
schema_element << [varname, eleqname, type]
end
unless type_or_element.attributes.empty?
type_or_element.attributes.each do |attribute|
name = attribute.name.name
if basetype = basetype_class(attribute.type)
type = basetype_class(attribute.type).name
else
type = nil
unless typedef.attributes.empty?
define_attribute(c, typedef.attributes)
init_lines << "@__xmlattr = {}\n"
end
varname = safevarname('attr_' + name)
c.def_method(varname) do <<-__EOD__
@__soap_attribute[#{name.dump}]
__EOD__
end
c.def_method(varname + '=', 'value') do <<-__EOD__
@__soap_attribute[#{name.dump}] = value
__EOD__
end
schema_attribute << [name, type]
end
init_lines << "@__soap_attribute = {}\n"
end
c.def_classvar('schema_attribute',
'{' +
schema_attribute.collect { |name, type|
name.dump + ' => ' + ndq(type)
}.join(', ') +
'}'
)
c.def_classvar('schema_element',
'{' +
schema_element.collect { |name, type|
name.dump + ' => ' + ndq(type)
'[' +
schema_element.collect { |varname, name, type|
'[' +
(
if name
varname.dump + ', [' + ndq(type) + ', ' + dqname(name) + ']'
else
varname.dump + ', ' + ndq(type)
end
) +
']'
}.join(', ') +
'}'
']'
)
c.def_method('initialize', *params) do
init_lines
@ -171,20 +186,83 @@ private
c.dump
end
def element_basetype(ele)
if klass = basetype_class(ele.type)
klass
elsif ele.local_simpletype
basetype_class(ele.local_simpletype.base)
else
nil
end
end
def attribute_basetype(attr)
if klass = basetype_class(attr.type)
klass
elsif attr.local_simpletype
basetype_class(attr.local_simpletype.base)
else
nil
end
end
def basetype_class(type)
if @simpletypes[type]
basetype_mapped_class(@simpletypes[type].base)
return nil if type.nil?
if simpletype = @simpletypes[type]
basetype_mapped_class(simpletype.base)
else
basetype_mapped_class(type)
end
end
def define_attribute(c, attributes)
schema_attribute = []
attributes.each do |attribute|
name = name_attribute(attribute)
if klass = attribute_basetype(attribute)
type = klass.name
else
type = nil
end
methodname = safemethodname('xmlattr_' + name.name)
c.def_method(methodname) do <<-__EOD__
(@__xmlattr ||= {})[#{dqname(name)}]
__EOD__
end
c.def_method(methodname + '=', 'value') do <<-__EOD__
(@__xmlattr ||= {})[#{dqname(name)}] = value
__EOD__
end
schema_attribute << [name, type]
end
c.def_classvar('schema_attribute',
'{' +
schema_attribute.collect { |name, type|
dqname(name) + ' => ' + ndq(type)
}.join(', ') +
'}'
)
end
def name_element(element)
return element.name if element.name
return element.ref if element.ref
raise RuntimeError.new("cannot define name of #{element}")
end
def name_attribute(attribute)
return attribute.name if attribute.name
return attribute.ref if attribute.ref
raise RuntimeError.new("cannot define name of #{attribute}")
end
def dump_arraydef(complextype)
qname = complextype.name
c = XSD::CodeGen::ClassDef.new(create_class_name(qname), '::Array')
c.comment = "#{ qname.namespace }"
c.def_classvar('schema_type', qname.name.dump)
c.def_classvar('schema_ns', qname.namespace.dump)
c.comment = "#{qname}"
type = complextype.child_type
c.def_classvar('schema_type', ndq(type.name))
c.def_classvar('schema_ns', ndq(type.namespace))
c.dump
end
end

View file

@ -21,7 +21,7 @@ module ClassDefCreatorSupport
def create_class_name(qname)
if klass = basetype_mapped_class(qname)
::SOAP::Mapping::DefaultRegistry.find_mapped_obj_class(klass.name)
::SOAP::Mapping::DefaultRegistry.find_mapped_obj_class(klass).name
else
safeconstname(qname.name)
end
@ -71,6 +71,10 @@ __EOD__
':' + ele
end
def dqname(qname)
qname.dump
end
private
def dump_inout_type(param)

View file

@ -31,42 +31,44 @@ class ComplexType < Info
else
:TYPE_STRUCT
end
elsif complexcontent and complexcontent.base == ::SOAP::ValueArrayName
elsif complexcontent
if complexcontent.base == ::SOAP::ValueArrayName
:TYPE_ARRAY
else
complexcontent.basetype.check_type
end
elsif simplecontent
:TYPE_SIMPLE
elsif !attributes.empty?
:TYPE_STRUCT
else
raise NotImplementedError.new("Unknown kind of complexType.")
else # empty complexType definition (seen in partner.wsdl of salesforce)
:TYPE_EMPTY
end
end
def child_type(name = nil)
type = nil
case compoundtype
when :TYPE_STRUCT
if ele = find_element(name)
type = ele.type
ele.type
elsif ele = find_element_by_name(name.name)
type = ele.type
ele.type
end
when :TYPE_ARRAY
type = @contenttype ||= content_arytype
@contenttype ||= content_arytype
when :TYPE_MAP
item_ele = find_element_by_name("item") or
raise RuntimeError.new("'item' element not found in Map definition.")
content = item_ele.local_complextype or
raise RuntimeError.new("No complexType definition for 'item'.")
if ele = content.find_element(name)
type = ele.type
ele.type
elsif ele = content.find_element_by_name(name.name)
type = ele.type
ele.type
end
else
raise NotImplementedError.new("Unknown kind of complexType.")
end
type
end
def child_defined_complextype(name)
@ -103,16 +105,21 @@ class ComplexType < Info
return attribute.arytype
end
end
elsif content.elements.size == 1 and content.elements[0].maxoccurs != '1'
return content.elements[0].type
else
raise RuntimeError.new("Assert: Unknown array definition.")
if check_array_content(complexcontent.content)
return complexcontent.content.elements[0].type
end
nil
elsif check_array_content(content)
return content.elements[0].type
end
raise RuntimeError.new("Assert: Unknown array definition.")
end
private
def check_array_content(content)
content.elements.size == 1 and content.elements[0].maxoccurs != '1'
end
def content_arytype
if arytype = find_arytype
ns = arytype.namespace

View file

@ -1,5 +1,5 @@
# WSDL4R - WSDL additional definitions for SOAP.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002-2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -77,13 +77,13 @@ class Definitions < Info
def collect_faulttypes
result = []
collect_fault_messages.each do |message|
parts = message(message).parts
if parts.size != 1
raise RuntimeError.new("Expecting fault message to have only 1 part.")
collect_fault_messages.each do |name|
faultparts = message(name).parts
if faultparts.size != 1
raise RuntimeError.new("expecting fault message to have only 1 part")
end
if result.index(parts[0].type).nil?
result << parts[0].type
if result.index(faultparts[0].type).nil?
result << faultparts[0].type
end
end
result
@ -111,13 +111,13 @@ private
if op_bind_rpc?(op_bind)
operation = op_bind.find_operation
if op_bind.input
type = XMLSchema::ComplexType.new(operation_input_name(operation))
type = XMLSchema::ComplexType.new(op_bind.soapoperation_name)
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))
type = XMLSchema::ComplexType.new(operation.outputname)
message = messages[operation.output.message]
type.sequence_elements = elements_from_message(message)
types << type
@ -127,23 +127,20 @@ private
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
op_bind.soapoperation_style == :rpc
end
def elements_from_message(message)
message.parts.collect { |part|
if part.element
collect_elements[part.element]
elsif part.name.nil? or part.type.nil?
raise RuntimeError.new("part of a message must be an element or typed")
else
qname = XSD::QName.new(nil, part.name)
XMLSchema::Element.new(qname, part.type)
end
}
end
end

View file

@ -1,5 +1,5 @@
# WSDL4R - Creating driver code from WSDL.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -46,16 +46,17 @@ private
methoddef, types = MethodDefCreator.new(@definitions).dump(name)
mr_creator = MappingRegistryCreator.new(@definitions)
binding = @definitions.bindings.find { |item| item.type == name }
addresses = @definitions.porttype(name).locations
return '' unless binding.soapbinding # not a SOAP binding
address = @definitions.porttype(name).locations[0]
c = ::XSD::CodeGen::ClassDef.new(class_name, "::SOAP::RPC::Driver")
c = XSD::CodeGen::ClassDef.new(class_name, "::SOAP::RPC::Driver")
c.def_require("soap/rpc/driver")
c.def_const("MappingRegistry", "::SOAP::Mapping::Registry.new")
c.def_const("DefaultEndpointUrl", addresses[0].dump)
c.def_const("DefaultEndpointUrl", ndq(address))
c.def_code(mr_creator.dump(types))
c.def_code <<-EOD
Methods = [
#{ methoddef.gsub(/^/, " ") }
#{methoddef.gsub(/^/, " ")}
]
EOD
c.def_method("initialize", "endpoint_url = nil") do
@ -69,14 +70,19 @@ Methods = [
c.def_privatemethod("init_methods") do
<<-EOD
Methods.each do |name_as, name, params, soapaction, namespace, style|
qname = ::XSD::QName.new(namespace, name_as)
qname = XSD::QName.new(namespace, name_as)
if style == :document
@proxy.add_document_method(qname, soapaction, name, params)
add_document_method_interface(name, name_as)
@proxy.add_document_method(soapaction, name, params)
add_document_method_interface(name, params)
else
@proxy.add_rpc_method(qname, soapaction, name, params)
add_rpc_method_interface(name, params)
end
if name_as != name and name_as.capitalize == name.capitalize
::SOAP::Mapping.define_singleton_method(self, name_as) do |*arg|
__send__(name, *arg)
end
end
end
EOD
end

View file

@ -21,12 +21,6 @@ class Element < Info
def attributes
@local_complextype.attributes
end
def each_element
@local_complextype.each_element do |element|
yield(element)
end
end
end

View file

@ -27,6 +27,10 @@ class Fault < Info
@namespace = nil
end
def targetnamespace
parent.targetnamespace
end
def parse_element(element)
nil
end

View file

@ -32,8 +32,12 @@ class Header < Info
@headerfault = nil
end
def targetnamespace
parent.targetnamespace
end
def find_message
root.message(@message)
root.message(@message) or raise RuntimeError.new("#{@message} not found")
end
def find_part
@ -42,7 +46,7 @@ class Header < Info
return part
end
end
nil
raise RuntimeError.new("#{@part} not found")
end
def parse_element(element)
@ -59,7 +63,10 @@ class Header < Info
def parse_attr(attr, value)
case attr
when MessageAttrName
@message = XSD::QName.new(targetnamespace, value.source)
if value.namespace.nil?
value = XSD::QName.new(targetnamespace, value.source)
end
@message = value
when PartAttrName
@part = value.source
when UseAttrName

View file

@ -1,5 +1,5 @@
# WSDL4R - Creating MappingRegistry code from WSDL.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -51,8 +51,10 @@ private
dump_struct_typemap(definedtype)
when :TYPE_ARRAY
dump_array_typemap(definedtype)
when :TYPE_MAP, :TYPE_EMPTY
nil
else
raise NotImplementedError.new("Must not reach here.")
raise NotImplementedError.new("must not reach here")
end
end
end
@ -61,10 +63,10 @@ private
ele = definedtype.name
return <<__EOD__
MappingRegistry.set(
#{ create_class_name(ele) },
#{create_class_name(ele)},
::SOAP::SOAPStruct,
::SOAP::Mapping::Registry::TypedStructFactory,
{ :type => ::XSD::QName.new("#{ ele.namespace }", "#{ ele.name }") }
{ :type => #{dqname(ele)} }
)
__EOD__
end
@ -76,10 +78,10 @@ __EOD__
@types << type
return <<__EOD__
MappingRegistry.set(
#{ create_class_name(ele) },
#{create_class_name(ele)},
::SOAP::SOAPArray,
::SOAP::Mapping::Registry::TypedArrayFactory,
{ :type => ::XSD::QName.new("#{ type.namespace }", "#{ type.name }") }
{ :type => #{dqname(type)} }
)
__EOD__
end

View file

@ -1,5 +1,5 @@
# WSDL4R - Creating driver code from WSDL.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -8,6 +8,7 @@
require 'wsdl/info'
require 'wsdl/soap/classDefCreatorSupport'
require 'soap/rpc/element'
module WSDL
@ -24,110 +25,122 @@ class MethodDefCreator
@simpletypes = @definitions.collect_simpletypes
@complextypes = @definitions.collect_complextypes
@elements = @definitions.collect_elements
@types = nil
@types = []
end
def dump(porttype)
@types = []
@types.clear
result = ""
operations = @definitions.porttype(porttype).operations
binding = @definitions.porttype_binding(porttype)
operations.each do |operation|
op_bind = binding.operations[operation.name]
next unless op_bind # no binding is defined
next unless op_bind.soapoperation # not a SOAP operation binding
result << ",\n" unless result.empty?
result << dump_method(operation, op_bind).chomp
end
return result, @types
end
def collect_rpcparameter(operation)
result = operation.inputparts.collect { |part|
collect_type(part.type)
param_set(::SOAP::RPC::SOAPMethod::IN, rpcdefinedtype(part), part.name)
}
outparts = operation.outputparts
if outparts.size > 0
retval = outparts[0]
collect_type(retval.type)
result << param_set(::SOAP::RPC::SOAPMethod::RETVAL,
rpcdefinedtype(retval), retval.name)
cdr(outparts).each { |part|
collect_type(part.type)
result << param_set(::SOAP::RPC::SOAPMethod::OUT, rpcdefinedtype(part),
part.name)
}
end
result
end
def collect_documentparameter(operation)
param = []
operation.inputparts.each do |input|
param << param_set(::SOAP::RPC::SOAPMethod::IN,
documentdefinedtype(input), input.name)
end
operation.outputparts.each do |output|
param << param_set(::SOAP::RPC::SOAPMethod::OUT,
documentdefinedtype(output), output.name)
end
param
end
private
def dump_method(operation, binding)
name = safemethodname(operation.name.name)
name_as = operation.name.name
stylestr = binding.soapoperation.operation_style.id2name
if binding.soapoperation.operation_style == :rpc
soapaction = binding.soapoperation.soapaction
style = binding.soapoperation_style
namespace = binding.input.soapbody.namespace
params = collect_rpcparameter(operation)
if style == :rpc
paramstr = param2str(collect_rpcparameter(operation))
else
soapaction = namespace = nil
params = collect_documentparameter(operation)
paramstr = param2str(collect_documentparameter(operation))
end
paramstr = param2str(params)
if paramstr.empty?
paramstr = '[]'
else
paramstr = "[\n" << paramstr.gsub(/^/, ' ') << "\n ]"
end
return <<__EOD__
[#{ dq(name_as) }, #{ dq(name) },
#{ paramstr },
#{ ndq(soapaction) }, #{ ndq(namespace) }, #{ sym(stylestr) }
[#{dq(name_as)}, #{dq(name)},
#{paramstr},
#{ndq(binding.soapaction)}, #{ndq(namespace)}, #{sym(style.id2name)}
]
__EOD__
end
def collect_rpcparameter(operation)
result = operation.inputparts.collect { |part|
collect_type(part.type)
param_set('in', rpcdefinedtype(part), part.name)
}
outparts = operation.outputparts
if outparts.size > 0
retval = outparts[0]
collect_type(retval.type)
result << param_set('retval', rpcdefinedtype(retval), retval.name)
cdr(outparts).each { |part|
collect_type(part.type)
result << param_set('out', rpcdefinedtype(part), part.name)
}
end
result
end
def collect_documentparameter(operation)
input = operation.inputparts[0]
output = operation.outputparts[0]
[
param_set('input', documentdefinedtype(input), input.name),
param_set('output', documentdefinedtype(output), output.name)
]
end
def rpcdefinedtype(part)
if mapped = basetype_mapped_class(part.type)
['::' + mapped.name]
elsif definedtype = @simpletypes[part.type]
['::' + basetype_mapped_class(definedtype.base).name]
elsif definedtype = @elements[part.element]
['::SOAP::SOAPStruct', part.element.namespace, part.element.name]
#['::SOAP::SOAPStruct', part.element.namespace, part.element.name]
['nil', part.element.namespace, part.element.name]
elsif definedtype = @complextypes[part.type]
case definedtype.compoundtype
when :TYPE_STRUCT
['::SOAP::SOAPStruct', part.type.namespace, part.type.name]
when :TYPE_STRUCT, :TYPE_EMPTY # ToDo: empty should be treated as void.
type = create_class_name(part.type)
[type, part.type.namespace, part.type.name]
when :TYPE_MAP
[Hash.name, part.type.namespace, part.type.name]
when :TYPE_ARRAY
arytype = definedtype.find_arytype || XSD::AnyTypeName
ns = arytype.namespace
name = arytype.name.sub(/\[(?:,)*\]$/, '')
['::SOAP::SOAPArray', ns, name]
type = create_class_name(XSD::QName.new(ns, name))
[type + '[]', ns, name]
else
raise NotImplementedError.new("Must not reach here.")
raise NotImplementedError.new("must not reach here")
end
else
raise RuntimeError.new("Part: #{part.name} cannot be resolved.")
raise RuntimeError.new("part: #{part.name} cannot be resolved")
end
end
def documentdefinedtype(part)
if definedtype = @simpletypes[part.type]
if mapped = basetype_mapped_class(part.type)
['::' + mapped.name, nil, part.name]
elsif definedtype = @simpletypes[part.type]
['::' + basetype_mapped_class(definedtype.base).name, nil, part.name]
elsif definedtype = @elements[part.element]
['::SOAP::SOAPElement', part.element.namespace, part.element.name]
elsif definedtype = @complextypes[part.type]
['::SOAP::SOAPElement', part.type.namespace, part.type.name]
else
raise RuntimeError.new("Part: #{part.name} cannot be resolved.")
raise RuntimeError.new("part: #{part.name} cannot be resolved")
end
end
@ -138,6 +151,7 @@ __EOD__
def collect_type(type)
# ignore inline type definition.
return if type.nil?
return if @types.include?(type)
@types << type
return unless @complextypes[type]
@complextypes[type].each_element do |element|
@ -147,15 +161,15 @@ __EOD__
def param2str(params)
params.collect { |param|
"[#{ dq(param[0]) }, #{ dq(param[2]) }, #{ type2str(param[1]) }]"
"[#{dq(param[0])}, #{dq(param[2])}, #{type2str(param[1])}]"
}.join(",\n")
end
def type2str(type)
if type.size == 1
"[#{ type[0] }]"
"[#{dq(type[0])}]"
else
"[#{ type[0] }, #{ ndq(type[1]) }, #{ dq(type[2]) }]"
"[#{dq(type[0])}, #{ndq(type[1])}, #{dq(type[2])}]"
end
end

View file

@ -101,8 +101,7 @@ private
"EncodingStyle '#{ soapbody.encodingstyle }' not supported.")
end
if soapbody.namespace
op_name = op_name.dup
op_name.namespace = soapbody.namespace
op_name = XSD::QName.new(soapbody.namespace, op_name.name)
end
if soapbody.parts
target = soapbody.parts.split(/\s+/)
@ -114,8 +113,7 @@ private
end
faultpart = nil
soapaction = parent.soapoperation.soapaction
OperationInfo.new(operation_style, op_name, optype_name, headerparts, bodyparts, faultpart, soapaction)
OperationInfo.new(operation_style, op_name, optype_name, headerparts, bodyparts, faultpart, parent.soapaction)
end
end

View file

@ -1,5 +1,5 @@
# WSDL4R - Creating servant skelton code from WSDL.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -17,7 +17,7 @@ module SOAP
class ServantSkeltonCreator
include ClassDefCreatorSupport
include ::XSD::CodeGen::GenSupport
include XSD::CodeGen::GenSupport
attr_reader :definitions
@ -42,7 +42,7 @@ private
def dump_porttype(name)
class_name = create_class_name(name)
c = ::XSD::CodeGen::ClassDef.new(class_name)
c = XSD::CodeGen::ClassDef.new(class_name)
operations = @definitions.porttype(name).operations
operations.each do |operation|
name = safemethodname(operation.name.name)
@ -50,7 +50,7 @@ private
params = input.find_message.parts.collect { |part|
safevarname(part.name)
}
m = ::XSD::CodeGen::MethodDef.new(name, params) do <<-EOD
m = XSD::CodeGen::MethodDef.new(name, params) do <<-EOD
p [#{params.join(", ")}]
raise NotImplementedError.new
EOD

View file

@ -1,5 +1,5 @@
# WSDL4R - Creating standalone server stub code from WSDL.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -26,10 +26,8 @@ class StandaloneServerStubCreator
end
def dump(service_name)
STDERR.puts "!!! IMPORTANT !!!"
STDERR.puts "- Standalone stub can have only 1 port for now. So creating stub for the first port and rests are ignored."
STDERR.puts "- Standalone server stub ignores port location defined in WSDL. Location is http://localhost:10080/ by default. Generated client from WSDL must be configured to point this endpoint by hand."
STDERR.puts "!!! IMPORTANT !!!"
warn("- Standalone stub can have only 1 port for now. So creating stub for the first port and rests are ignored.")
warn("- Standalone server stub ignores port location defined in WSDL. Location is http://localhost:10080/ by default. Generated client from WSDL must be configured to point this endpoint manually.")
port = @definitions.service(service_name).ports[0]
dump_porttype(port.porttype.name)
end
@ -41,28 +39,28 @@ private
methoddef, types = MethodDefCreator.new(@definitions).dump(name)
mr_creator = MappingRegistryCreator.new(@definitions)
c1 = ::XSD::CodeGen::ClassDef.new(class_name)
c1 = XSD::CodeGen::ClassDef.new(class_name)
c1.def_require("soap/rpc/standaloneServer")
c1.def_require("soap/mapping/registry")
c1.def_const("MappingRegistry", "::SOAP::Mapping::Registry.new")
c1.def_code(mr_creator.dump(types))
c1.def_code <<-EOD
Methods = [
#{ methoddef.gsub(/^/, " ") }
#{methoddef.gsub(/^/, " ")}
]
EOD
c2 = ::XSD::CodeGen::ClassDef.new(class_name + "App",
c2 = XSD::CodeGen::ClassDef.new(class_name + "App",
"::SOAP::RPC::StandaloneServer")
c2.def_method("initialize", "*arg") do
<<-EOD
super(*arg)
servant = #{class_name}.new
#{class_name}::Methods.each do |name_as, name, param_def, soapaction, namespace, style|
qname = XSD::QName.new(namespace, name_as)
if style == :document
@soaplet.app_scope_router.add_document_method(servant, qname, soapaction, name, param_def)
@router.add_document_operation(servant, soapaction, name, param_def)
else
@soaplet.app_scope_router.add_rpc_method(servant, qname, soapaction, name, param_def)
qname = XSD::QName.new(namespace, name_as)
@router.add_rpc_operation(servant, qname, soapaction, name, param_def)
end
end
self.mapping_registry = #{class_name}::MappingRegistry

View file

@ -1,5 +1,5 @@
# WSDL4R - XMLSchema attribute definition for WSDL.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -14,34 +14,74 @@ 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
class << self
if RUBY_VERSION > "1.7.0"
def attr_reader_ref(symbol)
name = symbol.to_s
self.__send__(:define_method, name, proc {
instance_variable_get("@#{name}") ||
(refelement ? refelement.__send__(name) : nil)
})
end
else
def attr_reader_ref(symbol)
name = symbol.to_s
module_eval <<-EOS
def #{name}
@#{name} || (refelement ? refelement.#{name} : nil)
end
EOS
end
end
end
attr_writer :use
attr_writer :form
attr_writer :name
attr_writer :type
attr_writer :local_simpletype
attr_writer :default
attr_writer :fixed
attr_reader_ref :use
attr_reader_ref :form
attr_reader_ref :name
attr_reader_ref :type
attr_reader_ref :local_simpletype
attr_reader_ref :default
attr_reader_ref :fixed
attr_accessor :ref
attr_accessor :arytype
def initialize
super
@ref = nil
@use = nil
@form = nil
@name = nil
@type = nil
@local_simpletype = nil
@default = nil
@fixed = nil
@ref = nil
@refelement = nil
@arytype = nil
end
def refelement
@refelement ||= root.collect_attributes[@ref]
end
def targetnamespace
parent.targetnamespace
end
def parse_element(element)
nil
case element
when SimpleTypeName
@local_simpletype = SimpleType.new
@local_simpletype
end
end
def parse_attr(attr, value)

View file

@ -26,12 +26,17 @@ class ComplexContent < Info
@derivetype = nil
@content = nil
@attributes = XSD::NamedElements.new
@basetype = nil
end
def targetnamespace
parent.targetnamespace
end
def basetype
@basetype ||= root.collect_complextypes[@base]
end
def parse_element(element)
case element
when RestrictionName, ExtensionName

View file

@ -1,5 +1,5 @@
# WSDL4R - XMLSchema data definitions.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -7,10 +7,13 @@
require 'xsd/datatypes'
require 'wsdl/xmlSchema/annotation'
require 'wsdl/xmlSchema/schema'
require 'wsdl/xmlSchema/import'
require 'wsdl/xmlSchema/include'
require 'wsdl/xmlSchema/simpleType'
require 'wsdl/xmlSchema/simpleRestriction'
require 'wsdl/xmlSchema/simpleExtension'
require 'wsdl/xmlSchema/complexType'
require 'wsdl/xmlSchema/complexContent'
require 'wsdl/xmlSchema/simpleContent'
@ -22,12 +25,15 @@ require 'wsdl/xmlSchema/sequence'
require 'wsdl/xmlSchema/attribute'
require 'wsdl/xmlSchema/unique'
require 'wsdl/xmlSchema/enumeration'
require 'wsdl/xmlSchema/length'
require 'wsdl/xmlSchema/pattern'
module WSDL
module XMLSchema
AllName = XSD::QName.new(XSD::Namespace, 'all')
AnnotationName = XSD::QName.new(XSD::Namespace, 'annotation')
AnyName = XSD::QName.new(XSD::Namespace, 'any')
AttributeName = XSD::QName.new(XSD::Namespace, 'attribute')
ChoiceName = XSD::QName.new(XSD::Namespace, 'choice')
@ -37,6 +43,9 @@ ElementName = XSD::QName.new(XSD::Namespace, 'element')
EnumerationName = XSD::QName.new(XSD::Namespace, 'enumeration')
ExtensionName = XSD::QName.new(XSD::Namespace, 'extension')
ImportName = XSD::QName.new(XSD::Namespace, 'import')
IncludeName = XSD::QName.new(XSD::Namespace, 'include')
LengthName = XSD::QName.new(XSD::Namespace, 'length')
PatternName = XSD::QName.new(XSD::Namespace, 'pattern')
RestrictionName = XSD::QName.new(XSD::Namespace, 'restriction')
SequenceName = XSD::QName.new(XSD::Namespace, 'sequence')
SchemaName = XSD::QName.new(XSD::Namespace, 'schema')

View file

@ -1,5 +1,5 @@
# WSDL4R - XMLSchema element definition for WSDL.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -14,23 +14,62 @@ 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
class << self
if RUBY_VERSION > "1.7.0"
def attr_reader_ref(symbol)
name = symbol.to_s
self.__send__(:define_method, name, proc {
instance_variable_get("@#{name}") ||
(refelement ? refelement.__send__(name) : nil)
})
end
else
def attr_reader_ref(symbol)
name = symbol.to_s
module_eval <<-EOS
def #{name}
@#{name} || (refelement ? refelement.#{name} : nil)
end
EOS
end
end
end
def initialize(name = nil, type = XSD::AnyTypeName)
attr_writer :name # required
attr_writer :type
attr_writer :local_simpletype
attr_writer :local_complextype
attr_writer :constraint
attr_writer :maxoccurs
attr_writer :minoccurs
attr_writer :nillable
attr_reader_ref :name
attr_reader_ref :type
attr_reader_ref :local_simpletype
attr_reader_ref :local_complextype
attr_reader_ref :constraint
attr_reader_ref :maxoccurs
attr_reader_ref :minoccurs
attr_reader_ref :nillable
attr_accessor :ref
def initialize(name = nil, type = nil)
super()
@name = name
@type = type
@local_complextype = nil
@local_simpletype = @local_complextype = nil
@constraint = nil
@maxoccurs = '1'
@minoccurs = '1'
@nillable = nil
@ref = nil
@refelement = nil
end
def refelement
@refelement ||= root.collect_elements[@ref]
end
def targetnamespace
@ -44,6 +83,9 @@ class Element < Info
def parse_element(element)
case element
when SimpleTypeName
@local_simpletype = SimpleType.new
@local_simpletype
when ComplexTypeName
@type = nil
@local_complextype = ComplexType.new
@ -62,19 +104,19 @@ class Element < Info
@name = XSD::QName.new(targetnamespace, value.source)
when TypeAttrName
@type = value
when RefAttrName
@ref = value
when MaxOccursAttrName
if parent.is_a?(All)
if value.source != '1'
raise Parser::AttrConstraintError.new(
"Cannot parse #{ value } for #{ attr }.")
raise Parser::AttrConstraintError.new("cannot parse #{value} for #{attr}")
end
end
@maxoccurs = value.source
when MinOccursAttrName
if parent.is_a?(All)
unless ['0', '1'].include?(value.source)
raise Parser::AttrConstraintError.new(
"Cannot parse #{ value } for #{ attr }.")
raise Parser::AttrConstraintError.new("cannot parse #{value} for #{attr}")
end
end
@minoccurs = value.source

View file

@ -1,5 +1,5 @@
# WSDL4R - XMLSchema import definition.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -7,6 +7,7 @@
require 'wsdl/info'
require 'wsdl/xmlSchema/importer'
module WSDL
@ -16,11 +17,13 @@ module XMLSchema
class Import < Info
attr_reader :namespace
attr_reader :schemalocation
attr_reader :content
def initialize
super
@namespace = nil
@schemalocation = nil
@content = nil
end
def parse_element(element)
@ -32,11 +35,29 @@ class Import < Info
when NamespaceAttrName
@namespace = value.source
when SchemaLocationAttrName
@schemalocation = value.source
@schemalocation = URI.parse(value.source)
if @schemalocation.relative? and !parent.location.nil? and
!parent.location.relative?
@schemalocation = parent.location + @schemalocation
end
if root.importedschema.key?(@schemalocation)
@content = root.importedschema[@schemalocation]
else
root.importedschema[@schemalocation] = nil # placeholder
@content = import(@schemalocation)
root.importedschema[@schemalocation] = @content
end
@schemalocation
else
nil
end
end
private
def import(location)
Importer.import(location, root)
end
end

View file

@ -1,5 +1,5 @@
# WSDL4R - WSDL XML Instance parser library.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -51,6 +51,9 @@ public
@parser = XSD::XMLParser.create_parser(self, opt)
@parsestack = nil
@lastnode = nil
@ignored = {}
@location = opt[:location]
@originalroot = opt[:originalroot]
end
def parse(string_or_readable)
@ -94,7 +97,7 @@ public
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 }'.")
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
@ -104,20 +107,31 @@ private
def decode_tag(ns, name, attrs, parent)
o = nil
element = ns.parse(name)
elename = ns.parse(name)
if !parent
if element == SchemaName
o = Schema.parse_element(element)
if elename == SchemaName
o = Schema.parse_element(elename)
o.location = @location
else
raise UnknownElementError.new("Unknown element #{ element }.")
raise UnknownElementError.new("unknown element: #{elename}")
end
o.root = @originalroot if @originalroot # o.root = o otherwise
else
o = parent.parse_element(element)
if elename == AnnotationName
# only the first annotation element is allowed for each element.
o = Annotation.new
else
o = parent.parse_element(elename)
end
unless o
STDERR.puts("Unknown element #{ element }.")
unless @ignored.key?(elename)
warn("ignored element: #{elename} of #{parent.class}")
@ignored[elename] = elename
end
o = Documentation.new # which accepts any element.
end
# node could be a pseudo element. pseudo element has its own parent.
o.root = parent.root
o.parent = parent if o.parent.nil?
end
attrs.each do |key, value|
@ -128,7 +142,10 @@ private
o.id = value_ele
else
unless o.parse_attr(attr_ele, value_ele)
STDERR.puts("Unknown attr #{ attr_ele }.")
unless @ignored.key?(attr_ele)
warn("ignored attr: #{attr_ele}")
@ignored[attr_ele] = attr_ele
end
end
end
end

View file

@ -24,6 +24,8 @@ class Schema < Info
attr_accessor :attributeformdefault
attr_accessor :elementformdefault
attr_reader :importedschema
def initialize
super
@targetnamespace = nil
@ -33,6 +35,17 @@ class Schema < Info
@attributes = XSD::NamedElements.new
@imports = []
@elementformdefault = "qualified"
@importedschema = {}
@location = nil
@root = self
end
def location
@location || (root.nil? ? nil : root.location)
end
def location=(location)
@location = location
end
def parse_element(element)
@ -41,6 +54,10 @@ class Schema < Info
o = Import.new
@imports << o
o
when IncludeName
o = Include.new
@imports << o
o
when ComplexTypeName
o = ComplexType.new
@complextypes << o
@ -55,6 +72,7 @@ class Schema < Info
o
when AttributeName
o = Attribute.new
@attributes << o
o
else
nil
@ -74,21 +92,39 @@ class Schema < Info
end
end
def collect_attributes
result = XSD::NamedElements.new
result.concat(@attributes)
@imports.each do |import|
result.concat(import.content.collect_attributes) if import.content
end
result
end
def collect_elements
result = XSD::NamedElements.new
result.concat(@elements)
@imports.each do |import|
result.concat(import.content.collect_elements) if import.content
end
result
end
def collect_complextypes
result = XSD::NamedElements.new
result.concat(@complextypes)
@imports.each do |import|
result.concat(import.content.collect_complextypes) if import.content
end
result
end
def collect_simpletypes
result = XSD::NamedElements.new
result.concat(@simpletypes)
@imports.each do |import|
result.concat(import.content.collect_simpletypes) if import.content
end
result
end

View file

@ -1,5 +1,5 @@
# WSDL4R - XMLSchema simpleContent definition for WSDL.
# Copyright (C) 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2004, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -15,17 +15,21 @@ module XMLSchema
class SimpleContent < Info
attr_accessor :base
attr_reader :derivetype
attr_reader :content
attr_reader :attributes
attr_reader :restriction
attr_reader :extension
def check_lexical_format(value)
check(value)
end
def initialize
super
@base = nil
@derivetype = nil
@content = nil
@attributes = XSD::NamedElements.new
@restriction = nil
@extension = nil
end
def base
content.base
end
def targetnamespace
@ -34,28 +38,24 @@ class SimpleContent < Info
def parse_element(element)
case element
when RestrictionName, ExtensionName
@derivetype = element.name
self
when AttributeName
if @derivetype.nil?
raise Parser::ElementConstraintError.new("base attr not found.")
end
o = Attribute.new
@attributes << o
o
when RestrictionName
@restriction = SimpleRestriction.new
@restriction
when ExtensionName
@extension = SimpleExtension.new
@extension
end
end
def parse_attr(attr, value)
if @derivetype.nil?
return nil
private
def content
@restriction || @extension
end
case attr
when BaseAttrName
@base = value
else
nil
def check(value)
unless content.valid?(value)
raise XSD::ValueSpaceError.new("#{@name}: cannot accept '#{value}'")
end
end
end

View file

@ -1,4 +1,4 @@
# WSDL4R - XMLSchema simpleType definition for WSDL.
# WSDL4R - XMLSchema simpleContent restriction definition for WSDL.
# Copyright (C) 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
@ -17,21 +17,32 @@ module XMLSchema
class SimpleRestriction < Info
attr_reader :base
attr_reader :enumeration
attr_accessor :length
attr_accessor :pattern
def initialize
super
@base = nil
@enumeration = [] # NamedElements?
@length = nil
@pattern = nil
end
def valid?(value)
@enumeration.include?(value)
return false unless check_restriction(value)
return false unless check_length(value)
return false unless check_pattern(value)
true
end
def parse_element(element)
case element
when EnumerationName
Enumeration.new # just a parsing handler
when LengthName
Length.new # just a parsing handler
when PatternName
Pattern.new # just a parsing handler
end
end
@ -41,6 +52,20 @@ class SimpleRestriction < Info
@base = value
end
end
private
def check_restriction(value)
@enumeration.empty? or @enumeration.include?(value)
end
def check_length(value)
@length.nil? or value.size == @length
end
def check_pattern(value)
@pattern.nil? or @pattern =~ value
end
end

View file

@ -1,5 +1,5 @@
# WSDL4R - XMLSchema simpleType definition for WSDL.
# Copyright (C) 2004 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2004, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -16,15 +16,11 @@ module XMLSchema
class SimpleType < Info
attr_accessor :name
attr_reader :derivetype
attr_reader :restriction
def check_lexical_format(value)
if @restriction
check_restriction(value)
elsif @extension
raise NotImplementedError
# ToDo
else
raise ArgumentError.new("incomplete simpleType")
end
@ -33,8 +29,6 @@ class SimpleType < Info
def base
if @restriction
@restriction.base
elsif @extension
@extension.base
else
raise ArgumentError.new("incomplete simpleType")
end
@ -43,7 +37,6 @@ class SimpleType < Info
def initialize(name = nil)
super()
@name = name
@derivetype = nil
@restriction = nil
end
@ -55,7 +48,6 @@ class SimpleType < Info
case element
when RestrictionName
@restriction = SimpleRestriction.new
@derivetype = element.name
@restriction
end
end
@ -71,7 +63,7 @@ private
def check_restriction(value)
unless @restriction.valid?(value)
raise ::XSD::ValueSpaceError.new("#{@name}: cannot accept '#{value}'.")
raise XSD::ValueSpaceError.new("#{@name}: cannot accept '#{value}'")
end
end
end

View file

@ -71,7 +71,7 @@ public
end
def Charset.encoding=(encoding)
STDERR.puts("xsd charset is set to #{encoding}") if $DEBUG
warn("xsd charset is set to #{encoding}") if $DEBUG
@encoding = encoding
end

View file

@ -77,7 +77,7 @@ class ClassDef < ModuleDef
end
buf << dump_class_def_end
buf << dump_package_def_end(package) unless package.empty?
buf
buf.gsub(/^\s+$/, '')
end
private

View file

@ -21,10 +21,10 @@ module CommentDef
private
def dump_comment
if /^#/ =~ @comment
if /\A#/ =~ @comment
format(@comment)
else
format(@comment).gsub(/^/, "# ")
format(@comment).gsub(/^/, '# ')
end
end
end

View file

@ -9,6 +9,49 @@
module XSD
module CodeGen
# from the file 'keywords' in 1.9.
KEYWORD = %w(
__LINE__
__FILE__
BEGIN
END
alias
and
begin
break
case
class
def
defined?
do
else
elsif
end
ensure
false
for
if
in
module
next
nil
not
or
redo
rescue
retry
return
self
super
then
true
undef
unless
until
when
while
yield
)
module GenSupport
def capitalize(target)
@ -25,7 +68,7 @@ module GenSupport
safename = name.scan(/[a-zA-Z0-9_]+/).collect { |ele|
GenSupport.capitalize(ele)
}.join
unless /^[A-Z]/ =~ safename
if /^[A-Z]/ !~ safename or keyword?(safename)
safename = "C_#{safename}"
end
safename
@ -33,12 +76,17 @@ module GenSupport
module_function :safeconstname
def safeconstname?(name)
/\A[A-Z][a-zA-Z0-9_]*\z/ =~ name
/\A[A-Z][a-zA-Z0-9_]*\z/ =~ name and !keyword?(name)
end
module_function :safeconstname?
def safemethodname(name)
safevarname(name)
safename = name.scan(/[a-zA-Z0-9_]+/).join('_')
safename = uncapitalize(safename)
if /^[a-z]/ !~ safename
safename = "m_#{safename}"
end
safename
end
module_function :safemethodname
@ -50,18 +98,23 @@ module GenSupport
def safevarname(name)
safename = name.scan(/[a-zA-Z0-9_]+/).join('_')
safename = uncapitalize(safename)
unless /^[a-z]/ =~ safename
safename = "m_#{safename}"
if /^[a-z]/ !~ safename or keyword?(safename)
safename = "v_#{safename}"
end
safename
end
module_function :safevarname
def safevarname?(name)
/\A[a-z_][a-zA-Z0-9_]*\z/ =~ name
/\A[a-z_][a-zA-Z0-9_]*\z/ =~ name and !keyword?(name)
end
module_function :safevarname?
def keyword?(word)
KEYWORD.include?(word)
end
module_function :keyword?
def format(str, indent = nil)
str = trim_eol(str)
str = trim_indent(str)
@ -76,7 +129,7 @@ private
def trim_eol(str)
str.collect { |line|
line.sub(/\r?\n$/, "") + "\n"
line.sub(/\r?\n\z/, "") + "\n"
}.join
end

View file

@ -34,7 +34,7 @@ class MethodDef
buf = ""
buf << dump_comment if @comment
buf << dump_method_def
buf << dump_definition if @definition
buf << dump_definition if @definition and !@definition.empty?
buf << dump_method_def_end
buf
end

View file

@ -89,7 +89,7 @@ class ModuleDef
end
buf << dump_module_def_end
buf << dump_package_def_end(package) unless package.empty?
buf
buf.gsub(/^\s+$/, '')
end
private

View file

@ -495,6 +495,18 @@ require 'date'
module XSDDateTimeImpl
SecInDay = 86400 # 24 * 60 * 60
def to_obj(klass)
if klass == Time
to_time
elsif klass == Date
to_date
elsif klass == DateTime
to_datetime
else
nil
end
end
def to_time
begin
if @data.offset * SecInDay == Time.now.utc_offset
@ -511,6 +523,14 @@ module XSDDateTimeImpl
end
end
def to_date
Date.new0(@data.class.jd_to_ajd(@data.jd, 0, 0), 0, @data.start)
end
def to_datetime
data
end
def tz2of(str)
/^(?:Z|(?:([+\-])(\d\d):(\d\d))?)$/ =~ str
sign = $1
@ -539,9 +559,18 @@ module XSDDateTimeImpl
end
def screen_data(t)
if (t.is_a?(Date))
# convert t to a DateTime as an internal representation.
if t.is_a?(DateTime)
t
elsif (t.is_a?(Time))
elsif t.is_a?(Date)
if t.respond_to?(:to_datetime) # from 1.9
t.to_datetime
else
t = screen_data_str(t)
t <<= 12 if t.year < 0
t
end
elsif t.is_a?(Time)
sec, min, hour, mday, month, year = t.to_a[0..5]
diffday = t.usec.to_r / 1000000 / SecInDay
of = t.utc_offset.to_r / SecInDay

View file

@ -22,7 +22,7 @@ class IconvCharset
out << e.success
ch, str = e.failed.split(//, 2)
out << '?'
STDERR.puts("Failed to convert #{ch}")
warn("Failed to convert #{ch}")
retry
end
return out

View file

@ -1,5 +1,5 @@
# XSD4R - WSDL named element collection.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -23,6 +23,12 @@ class NamedElements
o
end
def freeze
super
@elements.freeze
self
end
def empty?
size == 0
end
@ -43,6 +49,10 @@ class NamedElements
@elements.find { |item| item.name.name == name }
end
def keys
collect { |element| element.name }
end
def each
@elements.each do |element|
yield(element)
@ -69,6 +79,8 @@ class NamedElements
self
end
Empty = NamedElements.new.freeze
protected
def elements=(rhs)

View file

@ -1,5 +1,5 @@
# XSD4R - XML Schema Namespace library
# Copyright (C) 2000, 2001, 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2000-2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -20,7 +20,7 @@ class NS
def assign(ns)
@count += 1
"n#{ @count }"
"n#{@count}"
end
end
@ -54,7 +54,7 @@ public
end
def assigned?(ns)
@ns2tag.key?(ns)
@default_namespace == ns or @ns2tag.key?(ns)
end
def assigned_tag?(tag)
@ -74,7 +74,7 @@ public
elsif @ns2tag.key?(name.namespace)
@ns2tag[name.namespace] + ':' << name.name
else
raise FormatError.new('Namespace: ' << name.namespace << ' not defined yet.')
raise FormatError.new("namespace: #{name.namespace} not defined yet")
end
end
@ -83,7 +83,7 @@ public
return true if (name == rhs)
end
@tag2ns.each do |assigned_tag, assigned_ns|
if assigned_ns == ns && "#{ assigned_tag }:#{ name }" == rhs
if assigned_ns == ns && "#{assigned_tag}:#{name}" == rhs
return true
end
end
@ -103,22 +103,22 @@ public
end
# For local attribute key parsing
# <foo xmlns="urn:" xmlns:n1="urn:" bar="1" n1:baz="2" />
# <foo xmlns="urn:a" xmlns:n1="urn:a" bar="1" n1:baz="2" />
# =>
# {}bar, {urn:}baz
# {}bar, {urn:a}baz
def parse_local(elem)
ParseRegexp =~ elem
if $2
ns = @tag2ns[$1]
name = $2
if !ns
raise FormatError.new('Unknown namespace qualifier: ' << $1)
raise FormatError.new("unknown namespace qualifier: #{$1}")
end
elsif $1
ns = nil
name = $1
else
raise FormatError.new("Illegal element format: #{ elem }")
raise FormatError.new("illegal element format: #{elem}")
end
XSD::QName.new(ns, name)
end

View file

@ -24,6 +24,12 @@ class QName
XSD::QName.new(@namespace, name)
end
def dump
ns = @namespace.nil? ? 'nil' : @namespace.dump
name = @name.nil? ? 'nil' : @name.dump
"XSD::QName.new(#{ns}, #{name})"
end
def match(rhs)
unless self.class === rhs
return false

View file

@ -45,8 +45,8 @@ end
# Try to load XML processor.
loaded = false
[
'xsd/xmlparser/xmlscanner',
'xsd/xmlparser/xmlparser',
'xsd/xmlparser/xmlscanner',
'xsd/xmlparser/rexmlparser',
].each do |lib|
begin

View file

@ -1,5 +1,5 @@
# XSD4R - XMLScan XML parser library.
# Copyright (C) 2002, 2003 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# Copyright (C) 2002, 2003, 2005 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
@ -21,12 +21,12 @@ class XMLScanner < XSD::XMLParser::Parser
@attrs = {}
@curattr = nil
@scanner = XMLScan::XMLScanner.new(self)
@scanner.kcode = ::XSD::Charset.charset_str(charset) if charset
@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
@scanner.kcode = XSD::Charset.charset_str(charset) if charset
self.xmldecl_encoding = charset
end

View file

@ -1,41 +0,0 @@
class Authmgr
def initialize
@users = {
'NaHi' => 'passwd',
'HiNa' => 'wspass'
}
@sessions = {}
end
def login(userid, passwd)
userid and passwd and @users[userid] == passwd
end
# returns userid
def auth(sessionid)
@sessions[sessionid]
end
def create_session(userid)
while true
key = create_sessionkey
break unless @sessions[key]
end
@sessions[key] = userid
key
end
def get_session(userid)
@sessions.index(userid)
end
def destroy_session(sessionkey)
@sessions.delete(sessionkey)
end
private
def create_sessionkey
Time.now.usec.to_s
end
end

View file

@ -1,40 +0,0 @@
require 'soap/rpc/driver'
require 'soap/header/simplehandler'
server = ARGV.shift || 'http://localhost:7000/'
class ClientAuthHeaderHandler < SOAP::Header::SimpleHandler
MyHeaderName = XSD::QName.new("http://tempuri.org/authHeader", "auth")
def initialize(userid, passwd)
super(MyHeaderName)
@sessionid = nil
@userid = userid
@passwd = passwd
@mustunderstand = true
end
def on_simple_outbound
if @sessionid
{ "sessionid" => @sessionid }
else
{ "userid" => @userid, "passwd" => @passwd }
end
end
def on_simple_inbound(my_header, mustunderstand)
@sessionid = my_header["sessionid"]
end
end
ns = 'http://tempuri.org/authHeaderPort'
serv = SOAP::RPC::Driver.new(server, ns)
serv.add_method('deposit', 'amt')
serv.add_method('withdrawal', 'amt')
serv.headerhandler << ClientAuthHeaderHandler.new('NaHi', 'passwd')
serv.wiredump_dev = STDOUT
p serv.deposit(150)
p serv.withdrawal(120)

View file

@ -1,42 +0,0 @@
require 'soap/rpc/driver'
require 'soap/header/simplehandler'
server = ARGV.shift || 'http://localhost:7000/'
class ClientAuthHeaderHandler < SOAP::Header::SimpleHandler
MyHeaderName = XSD::QName.new("http://tempuri.org/authHeader", "auth")
attr_accessor :sessionid
def initialize
super(MyHeaderName)
@sessionid = nil
end
def on_simple_outbound
if @sessionid
{ "sessionid" => @sessionid }
end
end
def on_simple_inbound(my_header, mustunderstand)
@sessionid = my_header["sessionid"]
end
end
ns = 'http://tempuri.org/authHeaderPort'
serv = SOAP::RPC::Driver.new(server, ns)
serv.add_method('login', 'userid', 'passwd')
serv.add_method('deposit', 'amt')
serv.add_method('withdrawal', 'amt')
h = ClientAuthHeaderHandler.new
serv.headerhandler << h
serv.wiredump_dev = STDOUT
sessionid = serv.login('NaHi', 'passwd')
h.sessionid = sessionid
p serv.deposit(150)
p serv.withdrawal(120)

View file

@ -1,73 +0,0 @@
#!/usr/bin/env ruby
require 'soap/rpc/standaloneServer'
require 'soap/header/simplehandler'
require 'authmgr'
class AuthHeaderPortServer < SOAP::RPC::StandaloneServer
class AuthHeaderService
def self.create
new
end
def deposit(amt)
"deposit #{amt} OK"
end
def withdrawal(amt)
"withdrawal #{amt} OK"
end
end
Name = 'http://tempuri.org/authHeaderPort'
def initialize(*arg)
super
add_rpc_servant(AuthHeaderService.new, Name)
# header handler must be a per request handler.
add_rpc_request_headerhandler(ServerAuthHeaderHandler)
end
class ServerAuthHeaderHandler < SOAP::Header::SimpleHandler
MyHeaderName = XSD::QName.new("http://tempuri.org/authHeader", "auth")
@authmgr = Authmgr.new
def self.create
new(@authmgr)
end
def initialize(authmgr)
super(MyHeaderName)
@authmgr = authmgr
@userid = @sessionid = nil
end
def on_simple_outbound
{ "sessionid" => @sessionid }
end
def on_simple_inbound(my_header, mu)
auth = false
userid = my_header["userid"]
passwd = my_header["passwd"]
if @authmgr.login(userid, passwd)
auth = true
elsif sessionid = my_header["sessionid"]
if userid = @authmgr.auth(sessionid)
@authmgr.destroy_session(sessionid)
auth = true
end
end
raise RuntimeError.new("authentication failed") unless auth
@userid = userid
@sessionid = @authmgr.create_session(userid)
end
end
end
if $0 == __FILE__
svr = AuthHeaderPortServer.new('AuthHeaderPortServer', nil, '0.0.0.0', 7000)
trap(:INT) do
svr.shutdown
end
status = svr.start
end

View file

@ -1,83 +0,0 @@
#!/usr/bin/env ruby
require 'soap/rpc/standaloneServer'
require 'soap/header/simplehandler'
require 'authmgr'
class AuthHeaderPortServer < SOAP::RPC::StandaloneServer
class AuthHeaderService
def initialize(authmgr)
@authmgr = authmgr
end
def login(userid, passwd)
if @authmgr.login(userid, passwd)
@authmgr.create_session(userid)
else
raise RuntimeError.new("authentication failed")
end
end
def deposit(amt)
"deposit #{amt} OK"
end
def withdrawal(amt)
"withdrawal #{amt} OK"
end
end
Name = 'http://tempuri.org/authHeaderPort'
def initialize(*arg)
super
authmgr = Authmgr.new
add_rpc_servant(AuthHeaderService.new(authmgr), Name)
ServerAuthHeaderHandler.init(authmgr)
# header handler must be a per request handler.
add_rpc_request_headerhandler(ServerAuthHeaderHandler)
end
class ServerAuthHeaderHandler < SOAP::Header::SimpleHandler
MyHeaderName = XSD::QName.new("http://tempuri.org/authHeader", "auth")
def self.init(authmgr)
@authmgr = authmgr
end
def self.create
new(@authmgr)
end
def initialize(authmgr)
super(MyHeaderName)
@authmgr = authmgr
@sessionid = nil
end
def on_simple_outbound
if @sessionid
{ "sessionid" => @sessionid }
end
end
def on_simple_inbound(my_header, mu)
auth = false
if sessionid = my_header["sessionid"]
if userid = @authmgr.auth(sessionid)
@authmgr.destroy_session(sessionid)
@sessionid = @authmgr.create_session(userid)
auth = true
end
end
raise RuntimeError.new("authentication failed") unless auth
end
end
end
if $0 == __FILE__
svr = AuthHeaderPortServer.new('AuthHeaderPortServer', nil, '0.0.0.0', 7000)
trap(:INT) do
svr.shutdown
end
status = svr.start
end

View file

@ -1,16 +0,0 @@
#!/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)

View file

@ -1,17 +0,0 @@
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

View file

@ -1,29 +0,0 @@
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

@ -1,26 +0,0 @@
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

@ -1,29 +0,0 @@
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

View file

@ -1,20 +0,0 @@
#!/usr/bin/env ruby
require 'webrick'
require 'soap/property'
docroot = "."
port = 8808
if opt = SOAP::Property.loadproperty("samplehttpd.conf")
docroot = opt["docroot"]
port = Integer(opt["port"])
end
s = WEBrick::HTTPServer.new(
:BindAddress => "0.0.0.0",
:Port => port,
:DocumentRoot => docroot,
:CGIPathEnv => ENV['PATH']
)
trap(:INT){ s.shutdown }
s.start

View file

@ -1,2 +0,0 @@
docroot = .
port = 8808

View file

@ -1,15 +0,0 @@
#!/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

@ -1,21 +0,0 @@
#!/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__
server = CalcServer.new('CalcServer', nil, '0.0.0.0', 7000)
trap(:INT) do
server.shutdown
end
server.start
end

View file

@ -1,24 +0,0 @@
#!/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__
server = CalcServer2.new('CalcServer', 'http://tempuri.org/calcService', '0.0.0.0', 7000)
trap(:INT) do
server.shutdown
end
status = server.start
end

View file

@ -1,43 +0,0 @@
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") { |f| f.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

@ -1,19 +0,0 @@
#!/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

@ -1,17 +0,0 @@
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

@ -1,20 +0,0 @@
#!/usr/bin/env ruby
require 'webrick'
require 'soap/property'
docroot = "."
port = 8808
if opt = SOAP::Property.loadproperty("samplehttpd.conf")
docroot = opt["docroot"]
port = Integer(opt["port"])
end
s = WEBrick::HTTPServer.new(
:BindAddress => "0.0.0.0",
:Port => port,
:DocumentRoot => docroot,
:CGIPathEnv => ENV['PATH']
)
trap(:INT){ s.shutdown }
s.start

View file

@ -1,2 +0,0 @@
docroot = .
port = 8808

View file

@ -1,14 +0,0 @@
#!/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

@ -1,16 +0,0 @@
#!/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

@ -1,6 +0,0 @@
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)

View file

@ -1,8 +0,0 @@
require 'soap/rpc/driver'
s = SOAP::RPC::Driver.new('http://localhost:2000/', 'urn:hws')
s.add_method("hello_world", "from")
#s.wiredump_dev = STDOUT # care about binary output.
s.streamhandler.accept_encoding_gzip = true
p s.hello_world(self.to_s)

View file

@ -1,20 +0,0 @@
require 'soap/rpc/standaloneServer'
class HelloWorldServer < SOAP::RPC::StandaloneServer
def on_init
@log.level = Logger::Severity::DEBUG
add_method(self, 'hello_world', 'from')
end
def hello_world(from)
"Hello World, from #{ from }"
end
end
if $0 == __FILE__
server = HelloWorldServer.new('hws', 'urn:hws', '0.0.0.0', 2000)
trap(:INT) do
server.shutdown
end
server.start
end

View file

@ -1,21 +0,0 @@
require 'soap/rpc/standaloneServer'
class HelloWorldServer < SOAP::RPC::StandaloneServer
def on_init
@soaplet.allow_content_encoding_gzip = true
@log.level = Logger::Severity::DEBUG
add_method(self, 'hello_world', 'from')
end
def hello_world(from)
"Hello World, from #{ from }"
end
end
if $0 == __FILE__
server = HelloWorldServer.new('hws', 'urn:hws', '0.0.0.0', 2000)
trap(:INT) do
server.shutdown
end
server.start
end

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