Vendoring soap4r

This commit is contained in:
Eric Allen 2010-01-31 17:04:28 -08:00
parent c433661048
commit 61eb6aeb6a
441 changed files with 64652 additions and 0 deletions

566
vendor/gems/soap4r-1.5.8/.specification vendored Normal file
View file

@ -0,0 +1,566 @@
--- !ruby/object:Gem::Specification
name: soap4r
version: !ruby/object:Gem::Version
version: 1.5.8
platform: ruby
authors:
- NAKAMURA, Hiroshi
autorequire:
bindir: bin
cert_chain:
date: 2007-09-23 00:00:00 -07:00
default_executable:
dependencies:
- !ruby/object:Gem::Dependency
name: httpclient
type: :runtime
version_requirement:
version_requirements: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
version: 2.1.1
version:
description:
email: nahi@ruby-lang.org
executables:
- wsdl2ruby.rb
- xsd2ruby.rb
extensions: []
extra_rdoc_files: []
files:
- bin/wsdl2ruby.rb
- bin/xsd2ruby.rb
- lib/tags
- lib/xsd
- lib/xsd/datatypes.rb
- lib/xsd/namedelements.rb
- lib/xsd/iconvcharset.rb
- lib/xsd/charset.rb
- lib/xsd/qname.rb
- lib/xsd/mapping.rb
- lib/xsd/codegen
- lib/xsd/codegen/methoddef.rb
- lib/xsd/codegen/moduledef.rb
- lib/xsd/codegen/gensupport.rb
- lib/xsd/codegen/commentdef.rb
- lib/xsd/codegen/classdef.rb
- lib/xsd/xmlparser
- lib/xsd/xmlparser/xmlscanner.rb
- lib/xsd/xmlparser/rexmlparser.rb
- lib/xsd/xmlparser/parser.rb
- lib/xsd/xmlparser/xmlparser.rb
- lib/xsd/codegen.rb
- lib/xsd/xmlparser.rb
- lib/xsd/ns.rb
- lib/xsd/datatypes1999.rb
- lib/wsdl
- lib/wsdl/xmlSchema
- lib/wsdl/xmlSchema/fractiondigits.rb
- lib/wsdl/xmlSchema/union.rb
- lib/wsdl/xmlSchema/importHandler.rb
- lib/wsdl/xmlSchema/minexclusive.rb
- lib/wsdl/xmlSchema/complexRestriction.rb
- lib/wsdl/xmlSchema/totaldigits.rb
- lib/wsdl/xmlSchema/group.rb
- lib/wsdl/xmlSchema/include.rb
- lib/wsdl/xmlSchema/annotation.rb
- lib/wsdl/xmlSchema/content.rb
- lib/wsdl/xmlSchema/maxexclusive.rb
- lib/wsdl/xmlSchema/element.rb
- lib/wsdl/xmlSchema/choice.rb
- lib/wsdl/xmlSchema/unique.rb
- lib/wsdl/xmlSchema/sequence.rb
- lib/wsdl/xmlSchema/list.rb
- lib/wsdl/xmlSchema/any.rb
- lib/wsdl/xmlSchema/maxinclusive.rb
- lib/wsdl/xmlSchema/attribute.rb
- lib/wsdl/xmlSchema/complexType.rb
- lib/wsdl/xmlSchema/enumeration.rb
- lib/wsdl/xmlSchema/length.rb
- lib/wsdl/xmlSchema/maxlength.rb
- lib/wsdl/xmlSchema/complexExtension.rb
- lib/wsdl/xmlSchema/simpleType.rb
- lib/wsdl/xmlSchema/parser.rb
- lib/wsdl/xmlSchema/pattern.rb
- lib/wsdl/xmlSchema/whitespace.rb
- lib/wsdl/xmlSchema/all.rb
- lib/wsdl/xmlSchema/schema.rb
- lib/wsdl/xmlSchema/xsd2ruby.rb
- lib/wsdl/xmlSchema/simpleContent.rb
- lib/wsdl/xmlSchema/mininclusive.rb
- lib/wsdl/xmlSchema/complexContent.rb
- lib/wsdl/xmlSchema/anyAttribute.rb
- lib/wsdl/xmlSchema/minlength.rb
- lib/wsdl/xmlSchema/simpleExtension.rb
- lib/wsdl/xmlSchema/simpleRestriction.rb
- lib/wsdl/xmlSchema/attributeGroup.rb
- lib/wsdl/xmlSchema/data.rb
- lib/wsdl/xmlSchema/import.rb
- lib/wsdl/xmlSchema/importer.rb
- lib/wsdl/documentation.rb
- lib/wsdl/param.rb
- lib/wsdl/portType.rb
- lib/wsdl/definitions.rb
- lib/wsdl/wsdl.rb
- lib/wsdl/operation.rb
- lib/wsdl/operationBinding.rb
- lib/wsdl/parser.rb
- lib/wsdl/message.rb
- lib/wsdl/port.rb
- lib/wsdl/types.rb
- lib/wsdl/part.rb
- lib/wsdl/soap
- lib/wsdl/soap/servletStubCreator.rb
- lib/wsdl/soap/body.rb
- lib/wsdl/soap/methodDefCreator.rb
- lib/wsdl/soap/encodedMappingRegistryCreator.rb
- lib/wsdl/soap/driverCreator.rb
- lib/wsdl/soap/literalMappingRegistryCreator.rb
- lib/wsdl/soap/element.rb
- lib/wsdl/soap/definitions.rb
- lib/wsdl/soap/servantSkeltonCreator.rb
- lib/wsdl/soap/standaloneServerStubCreator.rb
- lib/wsdl/soap/mappingRegistryCreatorSupport.rb
- lib/wsdl/soap/fault.rb
- lib/wsdl/soap/complexType.rb
- lib/wsdl/soap/cgiStubCreator.rb
- lib/wsdl/soap/operation.rb
- lib/wsdl/soap/address.rb
- lib/wsdl/soap/wsdl2ruby.rb
- lib/wsdl/soap/clientSkeltonCreator.rb
- lib/wsdl/soap/classDefCreatorSupport.rb
- lib/wsdl/soap/headerfault.rb
- lib/wsdl/soap/classDefCreator.rb
- lib/wsdl/soap/mappingRegistryCreator.rb
- lib/wsdl/soap/classNameCreator.rb
- lib/wsdl/soap/binding.rb
- lib/wsdl/soap/data.rb
- lib/wsdl/soap/header.rb
- lib/wsdl/binding.rb
- lib/wsdl/service.rb
- lib/wsdl/data.rb
- lib/wsdl/import.rb
- lib/wsdl/importer.rb
- lib/wsdl/info.rb
- lib/soap
- lib/soap/mappingRegistry.rb
- lib/soap/filter
- lib/soap/filter/filterchain.rb
- lib/soap/filter/streamhandler.rb
- lib/soap/filter/handler.rb
- lib/soap/encodingstyle
- lib/soap/encodingstyle/literalHandler.rb
- lib/soap/encodingstyle/soapHandler.rb
- lib/soap/encodingstyle/aspDotNetHandler.rb
- lib/soap/encodingstyle/handler.rb
- lib/soap/wsdlDriver.rb
- lib/soap/rpc
- lib/soap/rpc/driver.rb
- lib/soap/rpc/element.rb
- lib/soap/rpc/soaplet.rb
- lib/soap/rpc/cgistub.rb
- lib/soap/rpc/proxy.rb
- lib/soap/rpc/rpc.rb
- lib/soap/rpc/standaloneServer.rb
- lib/soap/rpc/router.rb
- lib/soap/rpc/httpserver.rb
- lib/soap/XMLSchemaDatatypes.rb
- lib/soap/marshal.rb
- lib/soap/driver.rb
- lib/soap/mapping
- lib/soap/mapping/registry.rb
- lib/soap/mapping/typeMap.rb
- lib/soap/mapping/mapping.rb
- lib/soap/mapping/rubytypeFactory.rb
- lib/soap/mapping/encodedregistry.rb
- lib/soap/mapping/wsdlencodedregistry.rb
- lib/soap/mapping/factory.rb
- lib/soap/mapping/wsdlliteralregistry.rb
- lib/soap/mapping/schemadefinition.rb
- lib/soap/mapping/literalregistry.rb
- lib/soap/nestedexception.rb
- lib/soap/element.rb
- lib/soap/charset.rb
- lib/soap/qname.rb
- lib/soap/httpconfigloader.rb
- lib/soap/netHttpClient.rb
- lib/soap/mapping.rb
- lib/soap/cgistub.rb
- lib/soap/XMLSchemaDatatypes1999.rb
- lib/soap/proxy.rb
- lib/soap/filter.rb
- lib/soap/baseData.rb
- lib/soap/streamHandler.rb
- lib/soap/generator.rb
- lib/soap/rpcUtils.rb
- lib/soap/mimemessage.rb
- lib/soap/header
- lib/soap/header/simplehandler.rb
- lib/soap/header/handlerset.rb
- lib/soap/header/mappinghandler.rb
- lib/soap/header/handler.rb
- lib/soap/property.rb
- lib/soap/attachment.rb
- lib/soap/parser.rb
- lib/soap/processor.rb
- lib/soap/standaloneServer.rb
- lib/soap/server.rb
- lib/soap/rpcRouter.rb
- lib/soap/ns.rb
- lib/soap/compat.rb
- lib/soap/soap.rb
- lib/soap/namespace.rb
- test/interopR4
- test/interopR4/client.rb
- test/testutil.rb
- test/sm11
- test/sm11/driver.rb
- test/sm11/servant.rb
- test/sm11/classDef.rb
- test/sm11/server.rb
- test/sm11/client.rb
- test/xsd
- test/xsd/xmlschema.xml
- test/xsd/test_xsd.rb
- test/xsd/xsd2ruby
- test/xsd/xsd2ruby/expected_mysample.rb
- test/xsd/xsd2ruby/section.xsd
- test/xsd/xsd2ruby/expected_mysample_mapper.rb
- test/xsd/xsd2ruby/test_xsd2ruby.rb
- test/xsd/xsd2ruby/expected_mysample_mapping_registry.rb
- test/xsd/test_noencoding.rb
- test/xsd/codegen
- test/xsd/codegen/test_classdef.rb
- test/xsd/noencoding.xml
- test/xsd/test_xmlschemaparser.rb
- test/xsd/test_ns.rb
- test/xsd/xmllang.xml
- test/wsdl
- test/wsdl/simpletype
- test/wsdl/simpletype/rpc
- test/wsdl/simpletype/rpc/expectedEchoVersion.rb
- test/wsdl/simpletype/rpc/test_rpc.rb
- test/wsdl/simpletype/rpc/expectedClient.rb
- test/wsdl/simpletype/rpc/expectedDriver.rb
- test/wsdl/simpletype/rpc/expectedMappingRegistry.rb
- test/wsdl/simpletype/rpc/rpc.wsdl
- test/wsdl/simpletype/rpc/expectedServant.rb
- test/wsdl/simpletype/rpc/expectedService.rb
- test/wsdl/simpletype/simpletype.wsdl
- test/wsdl/simpletype/test_simpletype.rb
- test/wsdl/abstract
- test/wsdl/abstract/test_abstract.rb
- test/wsdl/abstract/abstract.wsdl
- test/wsdl/rpc
- test/wsdl/rpc/test_rpc.rb
- test/wsdl/rpc/test_rpc_lit.rb
- test/wsdl/rpc/test-rpc-lit.wsdl
- test/wsdl/rpc/rpc.wsdl
- test/wsdl/test_multiplefault.rb
- test/wsdl/marshal
- test/wsdl/marshal/person.wsdl
- test/wsdl/marshal/test_wsdlmarshal.rb
- test/wsdl/marshal/person_org.rb
- test/wsdl/choice
- test/wsdl/choice/choice.wsdl
- test/wsdl/choice/test_choice.rb
- test/wsdl/simplecontent
- test/wsdl/simplecontent/test_simplecontent.rb
- test/wsdl/simplecontent/simplecontent.wsdl
- test/wsdl/overload
- test/wsdl/overload/overload.wsdl
- test/wsdl/overload/test_overload.rb
- test/wsdl/complexcontent
- test/wsdl/complexcontent/test_echo.rb
- test/wsdl/complexcontent/complexContent.wsdl
- test/wsdl/multiplefault.wsdl
- test/wsdl/raa
- test/wsdl/raa/README.txt
- test/wsdl/raa/RAAService.rb
- test/wsdl/raa/raa.wsdl
- test/wsdl/raa/test_raa.rb
- test/wsdl/raa/expectedDriver.rb
- test/wsdl/raa/expectedMappingRegistry.rb
- test/wsdl/raa/expectedClassDef.rb
- test/wsdl/document
- test/wsdl/document/test_rpc.rb
- test/wsdl/document/test_number.rb
- test/wsdl/document/ping_nosoapaction.wsdl
- test/wsdl/document/document.wsdl
- test/wsdl/document/number.wsdl
- test/wsdl/document/array
- test/wsdl/document/array/test_array.rb
- test/wsdl/document/array/double.wsdl
- test/wsdl/document/test_nosoapaction.rb
- test/wsdl/any
- test/wsdl/any/expectedDriver.rb
- test/wsdl/any/expectedMappingRegistry.rb
- test/wsdl/any/expectedEcho.rb
- test/wsdl/any/any.wsdl
- test/wsdl/any/test_any.rb
- test/wsdl/any/expectedService.rb
- test/wsdl/datetime
- test/wsdl/datetime/datetimeServant.rb
- test/wsdl/datetime/test_datetime.rb
- test/wsdl/datetime/datetime.wsdl
- test/wsdl/datetime/DatetimeService.rb
- test/wsdl/datetime/datetime.rb
- test/wsdl/list
- test/wsdl/list/test_list.rb
- test/wsdl/list/list.wsdl
- test/wsdl/ref
- test/wsdl/ref/product.wsdl
- test/wsdl/ref/test_ref.rb
- test/wsdl/ref/expectedDriver.rb
- test/wsdl/ref/expectedProduct.rb
- test/wsdl/test_fault.rb
- test/wsdl/emptycomplextype.wsdl
- test/wsdl/test_emptycomplextype.rb
- test/wsdl/map
- test/wsdl/map/map.xml
- test/wsdl/map/map.wsdl
- test/wsdl/map/test_map.rb
- test/wsdl/axisArray
- test/wsdl/axisArray/test_axisarray.rb
- test/wsdl/axisArray/axisArray.wsdl
- test/wsdl/qualified
- test/wsdl/qualified/np.wsdl
- test/wsdl/qualified/lp.xsd
- test/wsdl/qualified/test_qualified.rb
- test/wsdl/qualified/test_unqualified.rb
- test/wsdl/qualified/lp.wsdl
- test/wsdl/soap
- test/wsdl/soap/test_soapbodyparts.rb
- test/wsdl/soap/soapbodyparts.wsdl
- test/wsdl/soap/wsdl2ruby
- test/wsdl/soap/wsdl2ruby/expectedClassdef.rb
- test/wsdl/soap/wsdl2ruby/expectedClient.rb
- test/wsdl/soap/wsdl2ruby/section
- test/wsdl/soap/wsdl2ruby/section/test_section.rb
- test/wsdl/soap/wsdl2ruby/section/expectedClassdef.rb
- test/wsdl/soap/wsdl2ruby/section/section.xsd
- test/wsdl/soap/wsdl2ruby/expectedDriver.rb
- test/wsdl/soap/wsdl2ruby/expectedService.cgi
- test/wsdl/soap/wsdl2ruby/expectedMappingRegistry.rb
- test/wsdl/soap/wsdl2ruby/soapenc
- test/wsdl/soap/wsdl2ruby/soapenc/soapenc.wsdl
- test/wsdl/soap/wsdl2ruby/soapenc/test_soapenc.rb
- test/wsdl/soap/wsdl2ruby/rpc.wsdl
- test/wsdl/soap/wsdl2ruby/expectedServant.rb
- test/wsdl/soap/wsdl2ruby/expectedService.rb
- test/wsdl/soap/wsdl2ruby/test_wsdl2ruby.rb
- test/wsdl/anonymous
- test/wsdl/anonymous/test_anonymous.rb
- test/wsdl/anonymous/expectedDriver.rb
- test/wsdl/anonymous/expectedMappingRegistry.rb
- test/wsdl/anonymous/expectedClassDef.rb
- test/wsdl/anonymous/lp.wsdl
- test/wsdl/oneway
- test/wsdl/oneway/test_oneway.rb
- test/wsdl/oneway/oneway.wsdl
- test/wsdl/group
- test/wsdl/group/expectedClassdef.rb
- test/wsdl/group/test_rpc.rb
- test/wsdl/group/group.wsdl
- test/wsdl/group/expectedDriver.rb
- test/wsdl/group/expectedMappingRegistry.rb
- test/wsdl/soaptype
- test/wsdl/soaptype/soaptype.wsdl
- test/wsdl/soaptype/test_soaptype.rb
- test/wsdl/fault
- test/wsdl/fault/test_multifault.rb
- test/wsdl/fault/test_fault.rb
- test/wsdl/fault/multifault.wsdl
- test/wsdl/fault/fault.wsdl
- test/runner.rb
- test/interopR2
- test/interopR2/clientBEAWebLogic.rb
- test/interopR2/client4S4C2.rb
- test/interopR2/client.log
- test/interopR2/rwikiInteropService.rb
- test/interopR2/InteropTest.wsdl
- test/interopR2/clientJSOAP.rb
- test/interopR2/clientMSSOAPToolkit2.0.rb
- test/interopR2/clientOpenLink.rb
- test/interopR2/clientSilverStream.rb
- test/interopR2/clientSIMACE.rb
- test/interopR2/clientMSSOAPToolkit3.0.rb
- test/interopR2/InteropTestDriver.rb
- test/interopR2/clientApacheAxis.rb
- test/interopR2/SOAPBuildersInterop_R2GrB.wsdl
- test/interopR2/clientWASP.rb
- test/interopR2/InteropTestC.wsdl
- test/interopR2/clientEasySoap.rb
- test/interopR2/README.txt
- test/interopR2/interopService.rb
- test/interopR2/clientGLUE.rb
- test/interopR2/SOAPBuildersInterop_R2.wsdl
- test/interopR2/clientBase.rb
- test/interopR2/clientWASPC.rb
- test/interopR2/clientSpray2001.rb
- test/interopR2/clientASP.NET.rb
- test/interopR2/clientNuSOAP.rb
- test/interopR2/clientCapeConnect.rb
- test/interopR2/clientZSI.rb
- test/interopR2/clientSQLData.rb
- test/interopR2/groupc.wsdl
- test/interopR2/clientJAX-RPC.rb
- test/interopR2/iSimonReg.rb
- test/interopR2/clientWhiteMesa.rb
- test/interopR2/clienteSOAP.rb
- test/interopR2/SOAP4R_SOAPBuildersInteropTest_R2GroupB.wsdl
- test/interopR2/clientOracle.rb
- test/interopR2/clientSun.rb
- test/interopR2/clientHP.rb
- test/interopR2/clientgSOAP.rb
- test/interopR2/simonReg.rb
- test/interopR2/clientDelphi.rb
- test/interopR2/clientXMLRPC-EPI.rb
- test/interopR2/client4S4C.rb
- test/interopR2/clientPhalanx.rb
- test/interopR2/server.cgi
- test/interopR2/clientPEAR.rb
- test/interopR2/clientkSOAP.rb
- test/interopR2/SOAP4R_SOAPBuildersInteropTest_R2.wsdl
- test/interopR2/clientVWOpentalkSoap.rb
- test/interopR2/clientSOAP4R.rb
- test/interopR2/clientNuWave.rb
- test/interopR2/clientKafkaXSLT.rb
- test/interopR2/InteropTest.rb
- test/interopR2/server.rb
- test/interopR2/interopResultBase.rb
- test/interopR2/clientXSOAP.rb
- test/interopR2/clientFrontier.rb
- test/interopR2/client.rb
- test/interopR2/test.sh
- test/interopR2/SOAP4R_SOAPBuildersInteropTest_R2GroupCClient.rb
- test/interopR2/clientWebMethods.rb
- test/interopR2/clientWingfoot.rb
- test/interopR2/SOAPBuildersInterop_R2GrC.wsdl
- test/interopR2/base.rb
- test/interopR2/clientXMLBus.rb
- test/interopR2/client.NetRemoting.rb
- test/interopR2/clientSOAP__Lite.rb
- test/interopR2/clientApacheSOAP.rb
- test/soap
- test/soap/ssl
- test/soap/ssl/client.cert
- test/soap/ssl/server.cert
- test/soap/ssl/README
- test/soap/ssl/test_ssl.rb
- test/soap/ssl/sslsvr.rb
- test/soap/ssl/server.key
- test/soap/ssl/ca.cert
- test/soap/ssl/client.key
- test/soap/ssl/subca.cert
- test/soap/filter
- test/soap/filter/test_filter.rb
- test/soap/marshal
- test/soap/marshal/test_digraph.rb
- test/soap/marshal/test_struct.rb
- test/soap/marshal/test_marshal.rb
- test/soap/marshal/marshaltestlib.rb
- test/soap/test_generator.rb
- test/soap/test_nestedexception.rb
- test/soap/helloworld
- test/soap/helloworld/test_helloworld.rb
- test/soap/helloworld/hw_s.rb
- test/soap/test_basetype.rb
- test/soap/test_custommap.rb
- test/soap/calc
- test/soap/calc/test_calc2.rb
- test/soap/calc/server2.rb
- test/soap/calc/test_calc_cgi.rb
- test/soap/calc/calc.rb
- test/soap/calc/calc2.rb
- test/soap/calc/server.cgi
- test/soap/calc/test_calc.rb
- test/soap/calc/server.rb
- test/soap/test_empty.rb
- test/soap/test_extraattr.rb
- test/soap/test_response_as_xml.rb
- test/soap/wsdlDriver
- test/soap/wsdlDriver/test_document.rb
- test/soap/wsdlDriver/README.txt
- test/soap/wsdlDriver/simpletype.wsdl
- test/soap/wsdlDriver/calc.wsdl
- test/soap/wsdlDriver/echo_version.rb
- test/soap/wsdlDriver/document.wsdl
- test/soap/wsdlDriver/test_calc.rb
- test/soap/wsdlDriver/test_simpletype.rb
- test/soap/test_soapelement.rb
- test/soap/test_httpconfigloader.rb
- test/soap/test_envelopenamespace.rb
- test/soap/struct
- test/soap/struct/test_struct.rb
- test/soap/test_nil.rb
- test/soap/case
- test/soap/case/test_mapping.rb
- test/soap/test_cookie.rb
- test/soap/test_property.rb
- test/soap/test_streamhandler.rb
- test/soap/header
- test/soap/header/test_simplehandler.rb
- test/soap/header/test_authheader.rb
- test/soap/header/server.cgi
- test/soap/header/test_authheader_cgi.rb
- test/soap/asp.net
- test/soap/asp.net/hello.wsdl
- test/soap/asp.net/test_aspdotnet.rb
- test/soap/styleuse
- test/soap/styleuse/server.rb
- test/soap/styleuse/client.rb
- test/soap/test_styleuse.rb
- test/soap/test_no_indent.rb
- test/soap/test_custom_ns.rb
- test/soap/htpasswd
- test/soap/literalArrayMapping
- test/soap/literalArrayMapping/amazonEcDriver.rb
- test/soap/literalArrayMapping/amazonresponse.xml
- test/soap/literalArrayMapping/amazonEc.rb
- test/soap/literalArrayMapping/test_definedarray.rb
- test/soap/auth
- test/soap/auth/htdigest
- test/soap/auth/test_basic.rb
- test/soap/auth/htpasswd
- test/soap/auth/test_digest.rb
- test/soap/swa
- test/soap/swa/test_file.rb
- test/soap/fault
- test/soap/fault/test_soaparray.rb
- test/soap/fault/test_customfault.rb
- test/soap/test_mapping.rb
- test/16runner.rb
has_rdoc: true
homepage: http://dev.ctor.org/soap4r
licenses: []
post_install_message:
rdoc_options: []
require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
requirements:
- - ">"
- !ruby/object:Gem::Version
version: 0.0.0
version:
required_rubygems_version: !ruby/object:Gem::Requirement
requirements:
- - ">="
- !ruby/object:Gem::Version
version: "0"
version:
requirements: []
rubyforge_project:
rubygems_version: 1.3.5
signing_key:
specification_version: 1
summary: An implementation of SOAP 1.1 for Ruby.
test_files:
- test/runner.rb

View file

@ -0,0 +1,137 @@
#!/usr/bin/env ruby
require 'getoptlong'
require 'logger'
require 'wsdl/soap/wsdl2ruby'
class WSDL2RubyApp < Logger::Application
private
OptSet = [
['--wsdl','-w', GetoptLong::REQUIRED_ARGUMENT],
['--module_path','-m', GetoptLong::REQUIRED_ARGUMENT],
['--type','-t', GetoptLong::REQUIRED_ARGUMENT],
['--classdef','-e', GetoptLong::OPTIONAL_ARGUMENT],
['--mapping_registry','-r', GetoptLong::NO_ARGUMENT],
['--client_skelton','-c', GetoptLong::OPTIONAL_ARGUMENT],
['--servant_skelton','-s', GetoptLong::OPTIONAL_ARGUMENT],
['--cgi_stub','-g', GetoptLong::OPTIONAL_ARGUMENT],
['--servlet_stub','-l', GetoptLong::OPTIONAL_ARGUMENT],
['--standalone_server_stub','-a', GetoptLong::OPTIONAL_ARGUMENT],
['--driver','-d', GetoptLong::OPTIONAL_ARGUMENT],
['--drivername_postfix','-n', GetoptLong::REQUIRED_ARGUMENT],
['--force','-f', GetoptLong::NO_ARGUMENT],
['--quiet','-q', GetoptLong::NO_ARGUMENT],
]
def initialize
super('app')
STDERR.sync = true
self.level = Logger::FATAL
end
def run
@worker = WSDL::SOAP::WSDL2Ruby.new
@worker.logger = @log
location, opt = parse_opt(GetoptLong.new(*OptSet))
usage_exit unless location
@worker.location = location
if opt['quiet']
self.level = Logger::FATAL
else
self.level = Logger::INFO
end
@worker.opt.update(opt)
@worker.run
0
end
def usage_exit
puts <<__EOU__
Usage: #{ $0 } --wsdl wsdl_location [options]
wsdl_location: filename or URL
Example:
For server side:
#{ $0 } --wsdl myapp.wsdl --type server
For client side:
#{ $0 } --wsdl myapp.wsdl --type client
Options:
--wsdl wsdl_location
--type server|client
--type server implies;
--classdef --mapping_registry --servant_skelton --standalone_server_stub
--type client implies;
--classdef --mapping_registry --client_skelton --driver
--classdef [filenameprefix]
--mapping_registry
--client_skelton [servicename]
--servant_skelton [porttypename]
--cgi_stub [servicename]
--servlet_stub [servicename]
--standalone_server_stub [servicename]
--driver [porttypename]
--drivername_postfix driver_classname_postfix
--module_path Module::Path::Name
--force
--quiet
Terminology:
Client <-> Driver <-(SOAP)-> Stub <-> Servant
Driver and Stub: Automatically generated
Client and Servant: Skelton generated (you should change)
__EOU__
exit 1
end
def parse_opt(getoptlong)
opt = {}
wsdl = nil
begin
getoptlong.each do |name, arg|
case name
when "--wsdl"
wsdl = arg
when "--module_path"
opt['module_path'] = arg
when "--type"
case arg
when "server"
opt['classdef'] ||= nil
opt['mapping_registry'] ||= nil
opt['servant_skelton'] ||= nil
opt['standalone_server_stub'] ||= nil
when "client"
opt['classdef'] ||= nil
opt['mapping_registry'] ||= nil
opt['driver'] ||= nil
opt['client_skelton'] ||= nil
else
raise ArgumentError.new("Unknown type #{ arg }")
end
when "--classdef", "--mapping_registry",
"--client_skelton", "--servant_skelton",
"--cgi_stub", "--servlet_stub", "--standalone_server_stub",
"--driver"
opt[name.sub(/^--/, '')] = arg.empty? ? nil : arg
when "--drivername_postfix"
opt['drivername_postfix'] = arg
when "--force"
opt['force'] = true
when "--quiet"
opt['quiet'] = true
else
raise ArgumentError.new("Unknown type #{ arg }")
end
end
rescue
usage_exit
end
return wsdl, opt
end
end
WSDL2RubyApp.new.start

View file

@ -0,0 +1,90 @@
#!/usr/bin/env ruby
require 'getoptlong'
require 'logger'
require 'wsdl/xmlSchema/xsd2ruby'
class XSD2RubyApp < Logger::Application
private
OptSet = [
['--xsd','-x', GetoptLong::REQUIRED_ARGUMENT],
['--module_path','-m', GetoptLong::REQUIRED_ARGUMENT],
['--classdef','-e', GetoptLong::OPTIONAL_ARGUMENT],
['--mapping_registry','-r', GetoptLong::NO_ARGUMENT],
['--mapper','-p', GetoptLong::NO_ARGUMENT],
['--force','-f', GetoptLong::NO_ARGUMENT],
['--quiet','-q', GetoptLong::NO_ARGUMENT],
]
def initialize
super('app')
STDERR.sync = true
self.level = Logger::FATAL
end
def run
@worker = WSDL::XMLSchema::XSD2Ruby.new
@worker.logger = @log
location, opt = parse_opt(GetoptLong.new(*OptSet))
usage_exit unless location
@worker.location = location
if opt['quiet']
self.level = Logger::FATAL
else
self.level = Logger::INFO
end
@worker.opt.update(opt)
@worker.run
0
end
def usage_exit
puts <<__EOU__
Usage: #{ $0 } --xsd xsd_location [options]
xsd_location: filename or URL
Example:
#{ $0 } --xsd myapp.xsd --classdef foo
Options:
--xsd xsd_location
--classdef [filenameprefix]
--mapping_registry
--mapper
--module_path [Module::Path::Name]
--force
--quiet
__EOU__
exit 1
end
def parse_opt(getoptlong)
opt = {}
xsd = nil
begin
getoptlong.each do |name, arg|
case name
when "--xsd"
xsd = arg
when "--module_path"
opt['module_path'] = arg
when "--classdef", "--mapping_registry", "--mapper"
opt[name.sub(/^--/, '')] = arg.empty? ? nil : arg
when "--force"
opt['force'] = true
when "--quiet"
opt['quiet'] = true
else
raise ArgumentError.new("Unknown type #{ arg }")
end
end
rescue
usage_exit
end
return xsd, opt
end
end
XSD2RubyApp.new.start

View file

@ -0,0 +1,9 @@
# soap/XMLSchemaDatatypes.rb: SOAP4R - XML Schema Datatype implementation.
# Copyright (C) 2000-2007 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/datatypes'

View file

@ -0,0 +1,10 @@
# soap/XMLSchemaDatatypes1999.rb: SOAP4R - XML Schema Datatype 1999 support
# Copyright (C) 2000-2007 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/datatypes1999'
load 'soap/mapping/typeMap.rb'

View file

@ -0,0 +1,108 @@
# soap/attachment.rb: SOAP4R - SwA implementation.
# Copyright (C) 2000-2007 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 'soap/baseData'
require 'soap/mapping'
module SOAP
class SOAPAttachment < SOAPExternalReference
attr_reader :data
def initialize(value)
super()
@data = value
end
private
def external_contentid
@data.contentid
end
end
class Attachment
attr_reader :io
attr_accessor :contenttype
def initialize(string_or_readable = nil)
@string_or_readable = string_or_readable
@contenttype = "application/octet-stream"
@contentid = nil
@content = nil
end
def contentid
@contentid ||= Attachment.contentid(self)
end
def contentid=(contentid)
@contentid = contentid
end
def mime_contentid
'<' + contentid + '>'
end
def content
if @content == nil and @string_or_readable != nil
@content = @string_or_readable.respond_to?(:read) ?
@string_or_readable.read : @string_or_readable
end
@content
end
def to_s
content
end
def write(out)
out.write(content)
end
def save(filename)
File.open(filename, "wb") do |f|
write(f)
end
end
def self.contentid(obj)
# this needs to be fixed
[obj.__id__.to_s, Process.pid.to_s].join('.')
end
def self.mime_contentid(obj)
'<' + contentid(obj) + '>'
end
end
module Mapping
class AttachmentFactory < SOAP::Mapping::Factory
def obj2soap(soap_class, obj, info, map)
soap_obj = soap_class.new(obj)
mark_marshalled_obj(obj, soap_obj)
soap_obj
end
def soap2obj(obj_class, node, info, map)
obj = node.data
mark_unmarshalled_obj(node, obj)
return true, obj
end
end
DefaultRegistry.add(::SOAP::Attachment, ::SOAP::SOAPAttachment,
AttachmentFactory.new, nil)
end
end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,9 @@
# SOAP4R - CGI stub library
# Copyright (C) 2000-2007 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 'soap/compat'

View file

@ -0,0 +1,9 @@
# SOAP4R - Charset encoding handler.
# Copyright (C) 2000-2007 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 'soap/compat'

View file

@ -0,0 +1,182 @@
# SOAP4R - Compatibility definitions.
# Copyright (C) 2003 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.
STDERR.puts "Loading compatibility library..."
require 'xsd/qname'
require 'xsd/ns'
require 'xsd/charset'
require 'soap/mapping'
require 'soap/rpc/rpc'
require 'soap/rpc/element'
require 'soap/rpc/driver'
require 'soap/rpc/cgistub'
require 'soap/rpc/router'
require 'soap/rpc/standaloneServer'
module SOAP
module RPC
RubyTypeNamespace = Mapping::RubyTypeNamespace
RubyTypeInstanceNamespace = Mapping::RubyTypeInstanceNamespace
RubyCustomTypeNamespace = Mapping::RubyCustomTypeNamespace
ApacheSOAPTypeNamespace = Mapping::ApacheSOAPTypeNamespace
DefaultMappingRegistry = Mapping::DefaultRegistry
def self.obj2soap(*arg); Mapping.obj2soap(*arg); end
def self.soap2obj(*arg); Mapping.soap2obj(*arg); end
def self.ary2soap(*arg); Mapping.ary2soap(*arg); end
def self.ary2md(*arg); Mapping.ary2md(*arg); end
def self.fault2exception(*arg); Mapping.fault2exception(*arg); end
def self.defined_methods(obj)
if obj.is_a?(Module)
obj.methods - Module.methods
else
obj.methods - Kernel.instance_methods(true)
end
end
end
NS = XSD::NS
Charset = XSD::Charset
RPCUtils = RPC
RPCServerException = RPC::ServerException
RPCRouter = RPC::Router
class StandaloneServer < RPC::StandaloneServer
def initialize(*arg)
super
@router = @soaplet.app_scope_router
methodDef if respond_to?('methodDef')
end
alias addServant add_servant
alias addMethod add_method
alias addMethodAs add_method_as
end
class CGIStub < RPC::CGIStub
def initialize(*arg)
super
methodDef if respond_to?('methodDef')
end
alias addServant add_servant
def addMethod(receiver, methodName, *paramArg)
addMethodWithNSAs(@default_namespace, receiver, methodName, methodName, *paramArg)
end
def addMethodAs(receiver, methodName, methodNameAs, *paramArg)
addMethodWithNSAs(@default_namespace, receiver, methodName, methodNameAs, *paramArg)
end
def addMethodWithNS(namespace, receiver, methodName, *paramArg)
addMethodWithNSAs(namespace, receiver, methodName, methodName, *paramArg)
end
def addMethodWithNSAs(namespace, receiver, methodName, methodNameAs, *paramArg)
add_method_with_namespace_as(namespace, receiver, methodName, methodNameAs, *paramArg)
end
end
class Driver < RPC::Driver
include Logger::Severity
attr_accessor :logdev
alias logDev= logdev=
alias logDev logdev
alias setWireDumpDev wiredump_dev=
alias setDefaultEncodingStyle default_encodingstyle=
alias mappingRegistry= mapping_registry=
alias mappingRegistry mapping_registry
def initialize(log, logid, namespace, endpoint_url, httpproxy = nil, soapaction = nil)
super(endpoint_url, namespace, soapaction)
@logdev = log
@logid = logid
@logid_prefix = "<#{ @logid }> "
self.httpproxy = httpproxy if httpproxy
log(INFO) { 'initialize: initializing SOAP driver...' }
end
def invoke(headers, body)
log(INFO) { "invoke: invoking message '#{ body.type }'." }
super
end
def call(name, *params)
log(INFO) { "call: calling method '#{ name }'." }
log(DEBUG) { "call: parameters '#{ params.inspect }'." }
log(DEBUG) {
params = Mapping.obj2soap(params, @mapping_registry).to_a
"call: parameters '#{ params.inspect }'."
}
super
end
def addMethod(name, *params)
addMethodWithSOAPActionAs(name, name, nil, *params)
end
def addMethodAs(name_as, name, *params)
addMethodWithSOAPActionAs(name_as, name, nil, *params)
end
def addMethodWithSOAPAction(name, soapaction, *params)
addMethodWithSOAPActionAs(name, name, soapaction, *params)
end
def addMethodWithSOAPActionAs(name_as, name, soapaction, *params)
add_method_with_soapaction_as(name, name_as, soapaction, *params)
end
def setLogDev(logdev)
self.logdev = logdev
end
private
def log(sev)
@logdev.add(sev, nil, self.class) { @logid_prefix + yield } if @logdev
end
end
module RPC
class MappingRegistry < SOAP::Mapping::Registry
def initialize(*arg)
super
end
def add(obj_class, soap_class, factory, info = nil)
if (info.size > 1)
raise RuntimeError.new("Parameter signature changed. [namespace, name] should be { :type => XSD::QName.new(namespace, name) } from 1.5.0.")
end
@map.add(obj_class, soap_class, factory, { :type => info[0] })
end
alias set add
end
class Router
alias mappingRegistry mapping_registry
alias mappingRegistry= mapping_registry=
end
end
end

View file

@ -0,0 +1,9 @@
# SOAP4R - SOAP driver
# Copyright (C) 2000-2007 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 'soap/compat'

View file

@ -0,0 +1,277 @@
# SOAP4R - SOAP elements library
# Copyright (C) 2000-2007 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 'soap/baseData'
module SOAP
###
## SOAP elements
#
module SOAPEnvelopeElement; end
class SOAPFault < SOAPStruct
include SOAPEnvelopeElement
include SOAPCompoundtype
public
def faultcode
self['faultcode']
end
def faultstring
self['faultstring']
end
def faultactor
self['faultactor']
end
def detail
self['detail']
end
def faultcode=(rhs)
self['faultcode'] = rhs
end
def faultstring=(rhs)
self['faultstring'] = rhs
end
def faultactor=(rhs)
self['faultactor'] = rhs
end
def detail=(rhs)
self['detail'] = rhs
end
def initialize(faultcode = nil, faultstring = nil, faultactor = nil, detail = nil)
super(EleFaultName)
@elename = EleFaultName
@encodingstyle = EncodingNamespace
if faultcode
self.faultcode = faultcode
self.faultstring = faultstring
self.faultactor = faultactor
self.detail = detail
self.faultcode.elename = EleFaultCodeName if self.faultcode
self.faultstring.elename = EleFaultStringName if self.faultstring
self.faultactor.elename = EleFaultActorName if self.faultactor
self.detail.elename = EleFaultDetailName if self.detail
end
faultcode.parent = self if faultcode
faultstring.parent = self if faultstring
faultactor.parent = self if faultactor
detail.parent = self if detail
end
def encode(generator, ns, attrs = {})
Generator.assign_ns(attrs, ns, EnvelopeNamespace)
Generator.assign_ns(attrs, ns, EncodingNamespace)
attrs[ns.name(AttrEncodingStyleName)] = EncodingNamespace
name = ns.name(@elename)
generator.encode_tag(name, attrs)
yield(self.faultcode)
yield(self.faultstring)
yield(self.faultactor)
yield(self.detail) if self.detail
generator.encode_tag_end(name, true)
end
end
class SOAPBody < SOAPStruct
include SOAPEnvelopeElement
attr_reader :is_fault
def initialize(data = nil, is_fault = false)
super(nil)
@elename = EleBodyName
@encodingstyle = nil
if data
if data.respond_to?(:to_xmlpart)
data = SOAP::SOAPRawData.new(data)
elsif defined?(::REXML) and data.is_a?(::REXML::Element)
data = SOAP::SOAPRawData.new(SOAP::SOAPREXMLElementWrap.new(data))
end
if data.respond_to?(:elename)
add(data.elename.name, data)
else
data.to_a.each do |datum|
add(datum.elename.name, datum)
end
end
end
@is_fault = is_fault
end
def encode(generator, ns, attrs = {})
name = ns.name(@elename)
generator.encode_tag(name, attrs)
@data.each do |data|
yield(data)
end
generator.encode_tag_end(name, @data.size > 0)
end
def root_node
@data.each do |node|
if node.root == 1
return node
end
end
# No specified root...
@data.each do |node|
if node.root != 0
return node
end
end
raise Parser::FormatDecodeError.new('no root element')
end
end
class SOAPHeaderItem < XSD::NSDBase
include SOAPEnvelopeElement
include SOAPCompoundtype
public
attr_accessor :element
attr_accessor :mustunderstand
attr_accessor :encodingstyle
attr_accessor :actor
def initialize(element, mustunderstand = true, encodingstyle = nil, actor = nil)
super()
@type = nil
@element = element
@mustunderstand = mustunderstand
@encodingstyle = encodingstyle
@actor = actor
element.parent = self if element
element.qualified = true
end
def encode(generator, ns, attrs = {})
attrs.each do |key, value|
@element.extraattr[key] = value
end
# to remove mustUnderstand attribute, set it to nil
unless @mustunderstand.nil?
@element.extraattr[AttrMustUnderstandName] = (@mustunderstand ? '1' : '0')
end
if @encodingstyle
@element.extraattr[AttrEncodingStyleName] = @encodingstyle
end
unless @element.encodingstyle
@element.encodingstyle = @encodingstyle
end
if @actor
@element.extraattr[AttrActorName] = @actor
end
yield(@element)
end
end
class SOAPHeader < SOAPStruct
include SOAPEnvelopeElement
attr_writer :force_encode
def initialize
super(nil)
@elename = EleHeaderName
@encodingstyle = nil
@force_encode = false
end
def encode(generator, ns, attrs = {})
name = ns.name(@elename)
generator.encode_tag(name, attrs)
@data.each do |data|
yield(data)
end
generator.encode_tag_end(name, @data.size > 0)
end
def add(name, value)
actor = value.extraattr[AttrActorName]
mu = value.extraattr[AttrMustUnderstandName]
encstyle = value.extraattr[AttrEncodingStyleName]
mu_value = mu.nil? ? nil : (mu == '1')
# to remove mustUnderstand attribute, set it to nil
item = SOAPHeaderItem.new(value, mu_value, encstyle, actor)
super(name, item)
end
def length
@data.length
end
alias size length
def encode?
@force_encode or length > 0
end
end
class SOAPEnvelope < XSD::NSDBase
include SOAPEnvelopeElement
include SOAPCompoundtype
attr_reader :header
attr_reader :body
attr_reader :external_content
def initialize(header = nil, body = nil)
super()
@type = nil
@elename = EleEnvelopeName
@encodingstyle = nil
@header = header
@body = body
@external_content = {}
header.parent = self if header
body.parent = self if body
end
def header=(header)
header.parent = self
@header = header
end
def body=(body)
body.parent = self
@body = body
end
def encode(generator, ns, attrs = {})
Generator.assign_ns(attrs, ns, elename.namespace)
name = ns.name(@elename)
generator.encode_tag(name, attrs)
yield(@header) if @header and @header.encode?
yield(@body)
generator.encode_tag_end(name, true)
end
def to_ary
[header, body]
end
end
end

View file

@ -0,0 +1,207 @@
# SOAP4R - ASP.NET EncodingStyle handler library
# Copyright (C) 2000-2007 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 'soap/encodingstyle/handler'
module SOAP
module EncodingStyle
class ASPDotNetHandler < Handler
Namespace = 'http://tempuri.org/ASP.NET'
add_handler
def initialize(charset = nil)
super(charset)
@textbuf = ''
@decode_typemap = nil
end
###
## encode interface.
#
def encode_data(generator, ns, data, parent)
attrs = {}
# ASPDotNetHandler is intended to be used for accessing an ASP.NET doc/lit
# service as an rpc/encoded service. in the situation, local elements
# should be qualified. propagate parent's namespace to children.
if data.elename.namespace.nil?
data.elename =
XSD::QName.new(parent.elename.namespace, data.elename.name)
end
name = generator.encode_name(ns, data, attrs)
case data
when SOAPRawString
generator.encode_tag(name, attrs)
generator.encode_rawstring(data.to_s)
when XSD::XSDString
generator.encode_tag(name, attrs)
generator.encode_string(@charset ?
XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
when XSD::XSDAnySimpleType
generator.encode_tag(name, attrs)
generator.encode_string(data.to_s)
when SOAPStruct
generator.encode_tag(name, attrs)
data.each do |key, value|
generator.encode_child(ns, value, data)
end
when SOAPArray
generator.encode_tag(name, attrs)
data.traverse do |child, *rank|
data.position = nil
generator.encode_child(ns, child, data)
end
else
raise EncodingStyleError.new(
"unknown object:#{data} in this encodingStyle")
end
end
def encode_data_end(generator, ns, data, parent)
name = generator.encode_name_end(ns, data)
cr = (data.is_a?(SOAPCompoundtype) and data.have_member)
generator.encode_tag_end(name, cr)
end
###
## decode interface.
#
class SOAPTemporalObject
attr_accessor :parent
def initialize
@parent = nil
end
end
class SOAPUnknown < SOAPTemporalObject
def initialize(handler, elename)
super()
@handler = handler
@elename = elename
end
def as_struct
o = SOAPStruct.decode(@elename, XSD::AnyTypeName)
o.parent = @parent
o.type.name = @name
@handler.decode_parent(@parent, o)
o
end
def as_string
o = SOAPString.decode(@elename)
o.parent = @parent
@handler.decode_parent(@parent, o)
o
end
end
def decode_tag(ns, elename, attrs, parent)
@textbuf = ''
o = SOAPUnknown.new(self, elename)
o.parent = parent
o
end
def decode_tag_end(ns, node)
o = node.node
if o.is_a?(SOAPUnknown)
newnode = o.as_string
# if /\A\s*\z/ =~ @textbuf
# o.as_struct
# else
# o.as_string
# end
node.replace_node(newnode)
o = node.node
end
decode_textbuf(o)
@textbuf = ''
end
def decode_text(ns, text)
# @textbuf is set at decode_tag_end.
@textbuf << text
end
def decode_prologue
end
def decode_epilogue
end
def decode_parent(parent, node)
case parent.node
when SOAPUnknown
newparent = parent.node.as_struct
node.parent = newparent
parent.replace_node(newparent)
decode_parent(parent, node)
when SOAPStruct
data = parent.node[node.elename.name]
case data
when nil
parent.node.add(node.elename.name, node)
when SOAPArray
name, type_ns = node.elename.name, node.type.namespace
data.add(node)
node.elename, node.type.namespace = name, type_ns
else
parent.node[node.elename.name] = SOAPArray.new
name, type_ns = data.elename.name, data.type.namespace
parent.node[node.elename.name].add(data)
data.elename.name, data.type.namespace = name, type_ns
name, type_ns = node.elename.name, node.type.namespace
parent.node[node.elename.name].add(node)
node.elename.name, node.type.namespace = name, type_ns
end
when SOAPArray
if node.position
parent.node[*(decode_arypos(node.position))] = node
parent.node.sparse = true
else
parent.node.add(node)
end
when SOAPBasetype
raise EncodingStyleError.new("SOAP base type must not have a child")
else
# SOAPUnknown does not have parent.
# raise EncodingStyleError.new("illegal parent: #{parent}")
end
end
private
def decode_textbuf(node)
if node.is_a?(XSD::XSDString)
if @charset
node.set(XSD::Charset.encoding_from_xml(@textbuf, @charset))
else
node.set(@textbuf)
end
else
# Nothing to do...
end
end
end
ASPDotNetHandler.new
end
end

View file

@ -0,0 +1,120 @@
# SOAP4R - EncodingStyle handler library
# Copyright (C) 2000-2007 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 'soap/soap'
require 'soap/baseData'
require 'soap/element'
module SOAP
module EncodingStyle
class Handler
@@handlers = {}
class EncodingStyleError < Error; end
class << self
def uri
self::Namespace
end
def handler(uri)
@@handlers[uri]
end
def each
@@handlers.each do |key, value|
yield(value)
end
end
private
def add_handler
@@handlers[self.uri] = self
end
end
attr_reader :charset
attr_accessor :generate_explicit_type
def decode_typemap=(definedtypes)
@decode_typemap = definedtypes
end
def initialize(charset)
@charset = charset
@generate_explicit_type = true
@decode_typemap = nil
end
###
## encode interface.
#
# Returns a XML instance as a string.
def encode_data(generator, ns, data, parent)
raise NotImplementError
end
def encode_data_end(generator, ns, data, parent)
raise NotImplementError
end
def encode_prologue
end
def encode_epilogue
end
###
## decode interface.
#
# Returns SOAP/OM data.
def decode_tag(ns, name, attrs, parent)
raise NotImplementError
end
def decode_tag_end(ns, name)
raise NotImplementError
end
def decode_text(ns, text)
raise NotImplementError
end
def decode_prologue
end
def decode_epilogue
end
def encode_attr_key(attrs, ns, qname)
if qname.namespace.nil?
qname.name
else
unless ns.assigned_as_tagged?(qname.namespace)
Generator.assign_ns!(attrs, ns, qname.namespace)
end
ns.name_attr(qname)
end
end
def encode_qname(attrs, ns, qname)
if qname.namespace.nil?
qname.name
else
Generator.assign_ns(attrs, ns, qname.namespace)
ns.name(qname)
end
end
end
end
end

View file

@ -0,0 +1,192 @@
# SOAP4R - XML Literal EncodingStyle handler library
# Copyright (C) 2000-2007 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 'soap/encodingstyle/handler'
module SOAP
module EncodingStyle
class LiteralHandler < Handler
Namespace = SOAP::LiteralNamespace
add_handler
def initialize(charset = nil)
super(charset)
@textbuf = []
end
###
## encode interface.
#
def encode_data(generator, ns, data, parent)
attrs = {}
name = generator.encode_name(ns, data, attrs)
data.extraattr.each do |key, value|
next if !@generate_explicit_type and key == XSD::AttrTypeName
keytag = key
if key.is_a?(XSD::QName)
keytag = encode_attr_key(attrs, ns, key)
end
if value.is_a?(XSD::QName)
value = encode_qname(attrs, ns, value)
end
attrs[keytag] = value
end
case data
when SOAPExternalReference
# do not encode SOAPExternalReference in
# literalHandler (which is used for literal service)
data.referred
when SOAPRawString
generator.encode_tag(name, attrs)
generator.encode_rawstring(data.to_s)
when XSD::XSDString
generator.encode_tag(name, attrs)
str = decode_str(data.to_s)
generator.encode_string(str)
when XSD::XSDAnySimpleType
generator.encode_tag(name, attrs)
generator.encode_string(data.to_s)
when SOAPStruct
generator.encode_tag(name, attrs)
data.each do |key, value|
generator.encode_child(ns, value, data)
end
when SOAPArray
generator.encode_tag(name, attrs)
data.traverse do |child, *rank|
data.position = nil
generator.encode_child(ns, child, data)
end
when SOAPElement
unless generator.use_default_namespace
# passes 2 times for simplifying namespace definition
data.each do |key, value|
if value.elename.namespace
Generator.assign_ns(attrs, ns, value.elename.namespace)
end
end
end
if data.text and data.text.is_a?(XSD::QName)
Generator.assign_ns(attrs, ns, data.text.namespace)
end
generator.encode_tag(name, attrs)
if data.text
if data.text.is_a?(XSD::QName)
text = ns.name(data.text)
else
text = data.text
end
generator.encode_string(text)
end
data.each do |key, value|
generator.encode_child(ns, value, data)
end
else
raise EncodingStyleError.new(
"unknown object:#{data} in this encodingStyle")
end
end
def encode_data_end(generator, ns, data, parent)
# do not encode SOAPExternalReference in
# literalHandler (which is used for literal service)
return nil if data.is_a?(SOAPExternalReference)
name = generator.encode_name_end(ns, data)
cr = (data.is_a?(SOAPCompoundtype) and data.have_member)
generator.encode_tag_end(name, cr)
end
###
## decode interface.
#
def decode_tag(ns, elename, attrs, parent)
@textbuf.clear
if attrs[XSD::AttrNilName] == 'true'
o = SOAPNil.decode(elename)
else
o = SOAPElement.decode(elename)
end
if definedtype = attrs[XSD::AttrTypeName]
o.type = ns.parse(definedtype)
end
o.parent = parent
o.extraattr.update(attrs)
decode_parent(parent, o)
o
end
def decode_tag_end(ns, node)
textbufstr = @textbuf.join
@textbuf.clear
o = node.node
decode_textbuf(o, textbufstr)
end
def decode_text(ns, text)
# @textbuf is set at decode_tag_end.
@textbuf << text
end
def decode_prologue
end
def decode_epilogue
end
def decode_parent(parent, node)
return unless parent.node
case parent.node
when SOAPElement
parent.node.add(node)
node.parent = parent.node
when SOAPStruct
parent.node.add(node.elename.name, node)
node.parent = parent.node
when SOAPArray
if node.position
parent.node[*(decode_arypos(node.position))] = node
parent.node.sparse = true
else
parent.node.add(node)
end
node.parent = parent.node
else
raise EncodingStyleError.new("illegal parent: #{parent.node}")
end
end
private
def decode_textbuf(node, textbufstr)
case node
when XSD::XSDString, SOAPElement
if @charset
node.set(decode_str(textbufstr))
else
node.set(textbufstr)
end
else
# Nothing to do...
end
end
def decode_str(str)
@charset ? XSD::Charset.encoding_from_xml(str, @charset) : str
end
end
LiteralHandler.new
end
end

View file

@ -0,0 +1,559 @@
# SOAP4R - SOAP EncodingStyle handler library
# Copyright (C) 2000-2007 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 'soap/encodingstyle/handler'
require 'soap/mapping/registry'
module SOAP
module EncodingStyle
class SOAPHandler < Handler
Namespace = SOAP::EncodingNamespace
add_handler
def initialize(charset = nil)
super(charset)
@refpool = []
@idpool = []
@textbuf = []
@is_first_top_ele = true
end
###
## encode interface.
#
def encode_data(generator, ns, data, parent)
attrs = encode_attrs(generator, ns, data, parent)
if parent && parent.is_a?(SOAPArray) && parent.position
attrs[ns.name(AttrPositionName)] = "[#{parent.position.join(',')}]"
end
name = generator.encode_name(ns, data, attrs)
case data
when SOAPReference
attrs['href'] = data.refidstr
generator.encode_tag(name, attrs)
when SOAPExternalReference
data.referred
attrs['href'] = data.refidstr
generator.encode_tag(name, attrs)
when SOAPRawString
generator.encode_tag(name, attrs)
generator.encode_rawstring(data.to_s)
when XSD::XSDString
generator.encode_tag(name, attrs)
generator.encode_string(@charset ?
XSD::Charset.encoding_to_xml(data.to_s, @charset) : data.to_s)
when XSD::XSDAnySimpleType
generator.encode_tag(name, attrs)
generator.encode_string(data.to_s)
when SOAPStruct
generator.encode_tag(name, attrs)
data.each do |key, value|
generator.encode_child(ns, value, data)
end
when SOAPArray
generator.encode_tag(name, attrs)
data.traverse do |child, *rank|
data.position = data.sparse ? rank : nil
generator.encode_child(ns, child, data)
end
else
raise EncodingStyleError.new(
"unknown object:#{data} in this encodingStyle")
end
end
def encode_data_end(generator, ns, data, parent)
name = generator.encode_name_end(ns, data)
cr = (data.is_a?(SOAPCompoundtype) and data.have_member)
generator.encode_tag_end(name, cr)
end
###
## decode interface.
#
class SOAPTemporalObject
attr_accessor :parent
attr_accessor :position
attr_accessor :id
attr_accessor :root
def initialize
@parent = nil
@position = nil
@id = nil
@root = nil
end
end
class SOAPUnknown < SOAPTemporalObject
attr_reader :type
attr_accessor :definedtype
attr_reader :extraattr
def initialize(handler, elename, type, extraattr)
super()
@handler = handler
@elename = elename
@type = type
@extraattr = extraattr
@definedtype = nil
end
def as_struct
if @extraattr[XSD::AttrNilName] == 'true'
return as_nil
end
o = SOAPStruct.decode(@elename, @type)
o.id = @id
o.root = @root
o.parent = @parent
o.position = @position
o.extraattr.update(@extraattr)
@handler.decode_parent(@parent, o)
o
end
def as_string
if @extraattr[XSD::AttrNilName] == 'true'
return as_nil
end
o = SOAPString.decode(@elename)
o.id = @id
o.root = @root
o.parent = @parent
o.position = @position
o.extraattr.update(@extraattr)
@handler.decode_parent(@parent, o)
o
end
def as_nil
o = SOAPNil.decode(@elename)
o.id = @id
o.root = @root
o.parent = @parent
o.position = @position
o.extraattr.update(@extraattr)
@handler.decode_parent(@parent, o)
o
end
end
def decode_tag(ns, elename, attrs, parent)
@textbuf.clear
is_nil, type, arytype, root, offset, position, href, id =
extract_attrs(ns, attrs)
o = nil
if is_nil
o = SOAPNil.decode(elename)
elsif href
o = SOAPReference.decode(elename, href)
@refpool << o
elsif @decode_typemap
o = decode_tag_by_wsdl(ns, elename, type, parent.node, arytype, attrs)
else
o = decode_tag_by_type(ns, elename, type, parent.node, arytype, attrs)
end
if o.is_a?(SOAPArray)
if offset
o.offset = decode_arypos(offset)
o.sparse = true
else
o.sparse = false
end
end
o.parent = parent
o.id = id
o.root = root
o.position = position
unless o.is_a?(SOAPTemporalObject)
@idpool << o if o.id
decode_parent(parent, o)
end
o
end
def decode_tag_end(ns, node)
textbufstr = @textbuf.join
@textbuf.clear
o = node.node
if o.is_a?(SOAPUnknown)
newnode = if /\A\s*\z/ =~ textbufstr
o.as_struct
else
o.as_string
end
if newnode.id
@idpool << newnode
end
node.replace_node(newnode)
o = node.node
end
decode_textbuf(o, textbufstr)
# unlink definedtype
o.definedtype = nil
end
def decode_text(ns, text)
@textbuf << text
end
def decode_prologue
@refpool.clear
@idpool.clear
@is_first_top_ele = true
end
def decode_epilogue
decode_resolve_id
end
def decode_parent(parent, node)
return unless parent.node
case parent.node
when SOAPUnknown
newparent = parent.node.as_struct
node.parent = newparent
if newparent.id
@idpool << newparent
end
parent.replace_node(newparent)
decode_parent(parent, node)
when SOAPStruct
parent.node.add(node.elename.name, node)
node.parent = parent.node
when SOAPArray
if node.position
parent.node[*(decode_arypos(node.position))] = node
parent.node.sparse = true
else
parent.node.add(node)
end
node.parent = parent.node
else
raise EncodingStyleError.new("illegal parent: #{parent.node}")
end
end
private
def content_ranksize(typename)
typename.scan(/\[[\d,]*\]$/)[0]
end
def content_typename(typename)
typename.sub(/\[,*\]$/, '')
end
def create_arytype(ns, data)
XSD::QName.new(data.arytype.namespace,
content_typename(data.arytype.name) + "[#{data.size.join(',')}]")
end
def encode_attrs(generator, ns, data, parent)
attrs = {}
return attrs if data.is_a?(SOAPReference)
if !parent || parent.encodingstyle != EncodingNamespace
if @generate_explicit_type
Generator.assign_ns(attrs, ns, EnvelopeNamespace)
attrs[ns.name(AttrEncodingStyleName)] = EncodingNamespace
end
data.encodingstyle = EncodingNamespace
end
if data.is_a?(SOAPNil)
attrs[ns.name(XSD::AttrNilName)] = XSD::NilValue
elsif @generate_explicit_type
if data.type.namespace
Generator.assign_ns(attrs, ns, data.type.namespace)
end
if data.is_a?(SOAPArray)
if data.arytype.namespace
Generator.assign_ns(attrs, ns, data.arytype.namespace)
end
Generator.assign_ns(attrs, ns, EncodingNamespace)
attrs[ns.name(AttrArrayTypeName)] = ns.name(create_arytype(ns, data))
if data.type.name
attrs[ns.name(XSD::AttrTypeName)] = ns.name(data.type)
end
elsif parent && parent.is_a?(SOAPArray) && (parent.arytype == data.type)
# No need to add.
elsif !data.type.namespace
# No need to add.
else
attrs[ns.name(XSD::AttrTypeName)] = ns.name(data.type)
end
end
data.extraattr.each do |key, value|
keytag = key
if key.is_a?(XSD::QName)
keytag = encode_attr_key(attrs, ns, key)
end
if value.is_a?(XSD::QName)
value = encode_qname(attrs, ns, value)
else
value = encode_attr_value(generator, ns, key, value)
end
attrs[keytag] = value
end
if data.id
attrs['id'] = data.id
end
attrs
end
def encode_attr_value(generator, ns, qname, value)
case value
when SOAPType
ref = SOAPReference.new(value)
generator.add_reftarget(qname.name, value)
ref.refidstr
else
value.to_s
end
end
def decode_tag_by_wsdl(ns, elename, typestr, parent, arytypestr, attrs)
o = nil
if parent.class == SOAPBody
# root element: should branch by root attribute?
if @is_first_top_ele
# Unqualified name is allowed here.
@is_first_top_ele = false
type = @decode_typemap[elename] ||
@decode_typemap.find_name(elename.name)
if type
o = SOAPStruct.new(elename)
o.elename = elename
o.definedtype = type
return o
end
end
# multi-ref element.
if typestr
typename = ns.parse(typestr)
typedef = @decode_typemap[typename]
if typedef
return decode_definedtype(elename, typename, typedef, arytypestr)
end
end
return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, attrs)
end
if parent.type == XSD::AnyTypeName
return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, attrs)
end
# parent.definedtype == nil means the parent is SOAPUnknown. SOAPUnknown
# is generated by decode_tag_by_type when its type is anyType.
parenttype = parent.definedtype || @decode_typemap[parent.type]
unless parenttype
return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, attrs)
end
definedtype_name = parenttype.child_type(elename)
if definedtype_name and (klass = TypeMap[definedtype_name])
return decode_basetype(klass, elename)
elsif definedtype_name == XSD::AnyTypeName
return decode_tag_by_type(ns, elename, typestr, parent, arytypestr, attrs)
end
if definedtype_name
typedef = @decode_typemap[definedtype_name]
else
typedef = parenttype.child_defined_complextype(elename)
end
decode_definedtype(elename, definedtype_name, typedef, arytypestr)
end
def decode_definedtype(elename, typename, typedef, arytypestr)
unless typedef
raise EncodingStyleError.new("unknown type '#{typename}'")
end
if typedef.is_a?(::WSDL::XMLSchema::SimpleType)
decode_defined_simpletype(elename, typename, typedef, arytypestr)
else
decode_defined_complextype(elename, typename, typedef, arytypestr)
end
end
def decode_basetype(klass, elename)
klass.decode(elename)
end
def decode_defined_simpletype(elename, typename, typedef, arytypestr)
if typedef.base
o = decode_basetype(TypeMap[typedef.base], elename)
o.definedtype = typedef
o
else
raise RuntimeError.new("unsupported simpleType: #{typedef}")
end
end
def decode_defined_complextype(elename, typename, typedef, arytypestr)
case typedef.compoundtype
when :TYPE_STRUCT, :TYPE_MAP
o = SOAPStruct.decode(elename, typename)
o.definedtype = typedef
return o
when :TYPE_ARRAY
expected_arytype = typedef.find_arytype
if arytypestr
actual_arytype = XSD::QName.new(expected_arytype.namespace,
content_typename(expected_arytype.name) <<
content_ranksize(arytypestr))
o = SOAPArray.decode(elename, typename, actual_arytype)
else
o = SOAPArray.new(typename, 1, expected_arytype)
o.elename = elename
end
o.definedtype = typedef
return o
when :TYPE_EMPTY
o = SOAPNil.decode(elename)
o.definedtype = typedef
return o
else
raise RuntimeError.new(
"Unknown kind of complexType: #{typedef.compoundtype}")
end
nil
end
def decode_tag_by_type(ns, elename, typestr, parent, arytypestr, attrs)
if arytypestr
type = typestr ? ns.parse(typestr) : ValueArrayName
node = SOAPArray.decode(elename, type, ns.parse(arytypestr))
node.extraattr.update(attrs)
return node
end
type = nil
if typestr
type = ns.parse(typestr)
elsif parent.is_a?(SOAPArray)
type = parent.arytype
else
# Since it's in dynamic(without any type) encoding process,
# assumes entity as its type itself.
# <SOAP-ENC:Array ...> => type Array in SOAP-ENC.
# <Country xmlns="foo"> => type Country in foo.
type = elename
end
if klass = TypeMap[type]
node = decode_basetype(klass, elename)
node.extraattr.update(attrs)
return node
end
# Unknown type... Struct or String
SOAPUnknown.new(self, elename, type, attrs)
end
def decode_textbuf(node, textbufstr)
case node
when XSD::XSDHexBinary, XSD::XSDBase64Binary
node.set_encoded(textbufstr)
when XSD::XSDString
if @charset
textbufstr = XSD::Charset.encoding_from_xml(textbufstr, @charset)
end
if node.definedtype
node.definedtype.check_lexical_format(textbufstr)
end
node.set(textbufstr)
when SOAPNil
# Nothing to do.
when SOAPBasetype
node.set(textbufstr)
else
# Nothing to do...
end
end
NilLiteralMap = {
'true' => true,
'1' => true,
'false' => false,
'0' => false
}
RootLiteralMap = {
'1' => 1,
'0' => 0
}
def extract_attrs(ns, attrs)
is_nil = NilLiteralMap[attrs[XSD::AttrNilName]]
type = attrs[XSD::AttrTypeName]
arytype = attrs[AttrArrayTypeName]
root = attrs[AttrRootName]
offset = attrs[AttrOffsetName]
position = attrs[AttrPositionName]
href = attrs[AttrHrefName]
id = attrs[AttrIdName]
if attrs.key?(Mapping::RubyIVarName)
attrs[Mapping::RubyIVarName] =
decode_ref_value(ns, attrs[Mapping::RubyIVarName])
end
return is_nil, type, arytype, root, offset, position, href, id
end
def decode_ref_value(ns, value)
if /\A#/ =~ value
o = SOAPReference.decode(nil, value)
@refpool << o
o
else
value
end
end
def decode_arypos(position)
/^\[(.+)\]$/ =~ position
$1.split(',').collect { |s| s.to_i }
end
def decode_resolve_id
count = @refpool.length # To avoid infinite loop
while !@refpool.empty? && count > 0
@refpool = @refpool.find_all { |ref|
o = @idpool.find { |item|
item.id == ref.refid
}
if o.is_a?(SOAPReference)
true # link of link.
elsif o
ref.__setobj__(o)
false
elsif o = ref.rootnode.external_content[ref.refid]
ref.__setobj__(o)
false
else
raise EncodingStyleError.new("unresolved reference: #{ref.refid}")
end
}
count -= 1
end
end
end
SOAPHandler.new
end
end

View file

@ -0,0 +1,13 @@
# SOAP4R - SOAP filter.
# Copyright (C) 2000-2007 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 'soap/filter/filterchain'
# envelope filter
require 'soap/filter/handler'
# steram filter
require 'soap/filter/streamhandler'

View file

@ -0,0 +1,51 @@
# SOAP4R - SOAP filter chain.
# Copyright (C) 2000-2007 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 'soap/filter/handler'
module SOAP
module Filter
class FilterChain
def each
@array.each do |filter|
yield filter
end
end
def reverse_each
@array.reverse_each do |filter|
yield filter
end
end
def initialize
@array = []
end
def add(filter)
@array << filter
end
alias << add
def delete(filter)
@array.delete(filter)
end
def include?(filter)
@array.include?(filter)
end
end
end
end

View file

@ -0,0 +1,31 @@
# SOAP4R - SOAP envelope filter base class.
# Copyright (C) 2000-2007 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.
module SOAP
module Filter
class Handler
# should return envelope. opt can be updated for other filters.
def on_outbound(envelope, opt)
# do something.
envelope
end
# should return xml. opt can be updated for other filters.
def on_inbound(xml, opt)
# do something.
xml
end
end
end
end

View file

@ -0,0 +1,29 @@
# SOAP4R - SOAP stream filter base class.
# Copyright (C) 2000-2007 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.
module SOAP
module Filter
class StreamHandler
# no returning value expected.
def on_http_outbound(req)
# do something.
end
# no returning value expected.
def on_http_inbound(req, res)
# do something.
end
end
end
end

View file

@ -0,0 +1,304 @@
# SOAP4R - SOAP XML Instance Generator library.
# Copyright (C) 2000-2007 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 'soap/soap'
require 'soap/ns'
require 'soap/baseData'
require 'soap/encodingstyle/handler'
require 'xsd/codegen/gensupport'
module SOAP
###
## CAUTION: MT-unsafe
#
class Generator
include SOAP
include XSD::CodeGen::GenSupport
class FormatEncodeError < Error; end
public
attr_accessor :charset
attr_accessor :default_encodingstyle
attr_accessor :generate_explicit_type
attr_accessor :use_numeric_character_reference
attr_accessor :use_default_namespace
def initialize(opt = {})
@reftarget = nil
@handlers = {}
@charset = opt[:charset] || XSD::Charset.xml_encoding_label
@default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace
@generate_explicit_type =
opt.key?(:generate_explicit_type) ? opt[:generate_explicit_type] : true
@use_default_namespace = opt[:use_default_namespace]
@attributeformdefault = opt[:attributeformdefault]
@use_numeric_character_reference = opt[:use_numeric_character_reference]
@indentstr = opt[:no_indent] ? '' : ' '
@buf = @indent = @curr = nil
@default_ns = opt[:default_ns]
@default_ns_tag = opt[:default_ns_tag]
end
def generate(obj, io = nil)
@buf = io || ''
@indent = ''
@encode_char_regexp = get_encode_char_regexp()
prologue
@handlers.each do |uri, handler|
handler.encode_prologue
end
ns = SOAP::NS.new
if @default_ns
@default_ns.each_ns do |default_ns, default_tag|
Generator.assign_ns(obj.extraattr, ns, default_ns, default_tag)
end
end
if @default_ns_tag
@default_ns_tag.each_ns do |default_ns, default_tag|
ns.known_tag[default_ns] = default_tag
end
end
@buf << xmldecl
encode_data(ns, obj, nil)
@handlers.each do |uri, handler|
handler.encode_epilogue
end
epilogue
@buf
end
def encode_data(ns, obj, parent)
if obj.respond_to?(:to_xmlpart)
formatted = trim_eol(obj.to_xmlpart)
formatted = trim_indent(formatted)
formatted = formatted.gsub(/^/, @indent).sub(/\n+\z/, '')
@buf << "\n#{formatted}"
return
elsif obj.is_a?(SOAPEnvelopeElement)
encode_element(ns, obj, parent)
return
end
if @reftarget && !obj.precedents.empty?
add_reftarget(obj.elename.name, obj)
ref = SOAPReference.new(obj)
ref.elename = ref.elename.dup_name(obj.elename.name)
obj.precedents.clear # Avoid cyclic delay.
obj.encodingstyle = parent.encodingstyle
# SOAPReference is encoded here.
obj = ref
end
encodingstyle = obj.encodingstyle
# Children's encodingstyle is derived from its parent.
encodingstyle ||= parent.encodingstyle if parent
obj.encodingstyle = encodingstyle
handler = find_handler(encodingstyle || @default_encodingstyle)
unless handler
raise FormatEncodeError.new("Unknown encodingStyle: #{ encodingstyle }.")
end
if !obj.elename.name
raise FormatEncodeError.new("Element name not defined: #{ obj }.")
end
handler.encode_data(self, ns, obj, parent)
handler.encode_data_end(self, ns, obj, parent)
end
def add_reftarget(name, node)
unless @reftarget
raise FormatEncodeError.new("Reftarget is not defined.")
end
@reftarget.add(name, node)
end
def encode_child(ns, child, parent)
indent_backup, @indent = @indent, @indent + @indentstr
encode_data(ns.clone_ns, child, parent)
@indent = indent_backup
end
def encode_element(ns, obj, parent)
attrs = obj.extraattr
if obj.is_a?(SOAPBody)
@reftarget = obj
obj.encode(self, ns, attrs) do |child|
indent_backup, @indent = @indent, @indent + @indentstr
encode_data(ns.clone_ns, child, obj)
@indent = indent_backup
end
@reftarget = nil
else
if obj.is_a?(SOAPEnvelope)
# xsi:nil="true" can appear even if dumping without explicit type.
Generator.assign_ns(attrs, ns, XSD::InstanceNamespace)
if @generate_explicit_type
Generator.assign_ns(attrs, ns, XSD::Namespace)
end
end
obj.encode(self, ns, attrs) do |child|
indent_backup, @indent = @indent, @indent + @indentstr
encode_data(ns.clone_ns, child, obj)
@indent = indent_backup
end
end
end
def encode_name(ns, data, attrs)
if element_local?(data)
data.elename.name
else
if @use_default_namespace
Generator.assign_ns(attrs, ns, data.elename.namespace, '')
else
Generator.assign_ns(attrs, ns, data.elename.namespace)
end
ns.name(data.elename)
end
end
def encode_name_end(ns, data)
if element_local?(data)
data.elename.name
else
ns.name(data.elename)
end
end
def encode_tag(elename, attrs = nil)
if attrs.nil? or attrs.empty?
@buf << "\n#{ @indent }<#{ elename }>"
return
end
ary = []
attrs.each do |key, value|
ary << %Q[#{ key }="#{ get_encoded(value.to_s) }"]
end
case ary.size
when 0
@buf << "\n#{ @indent }<#{ elename }>"
when 1
@buf << %Q[\n#{ @indent }<#{ elename } #{ ary[0] }>]
else
@buf << "\n#{ @indent }<#{ elename } " <<
ary.join("\n#{ @indent }#{ @indentstr * 2 }") <<
'>'
end
end
def encode_tag_end(elename, cr = nil)
if cr
@buf << "\n#{ @indent }</#{ elename }>"
else
@buf << "</#{ elename }>"
end
end
def encode_rawstring(str)
@buf << str
end
def encode_string(str)
@buf << get_encoded(str)
end
def element_local?(element)
element.elename.namespace.nil?
end
def self.assign_ns(attrs, ns, namespace, tag = nil)
if namespace.nil?
raise FormatEncodeError.new("empty namespace")
end
override_default_ns = (tag == '' and namespace != ns.default_namespace)
if override_default_ns or !ns.assigned?(namespace)
assign_ns!(attrs, ns, namespace, tag)
end
end
def self.assign_ns!(attrs, ns, namespace, tag = nil)
tag = ns.assign(namespace, tag)
if tag == ''
attr = 'xmlns'
else
attr = "xmlns:#{tag}"
end
attrs[attr] = namespace
end
private
def prologue
end
def epilogue
end
ENCODE_CHAR_REGEXP = {}
EncodeMap = {
'&' => '&amp;',
'<' => '&lt;',
'>' => '&gt;',
'"' => '&quot;',
'\'' => '&apos;',
"\r" => '&#xd;'
}
def get_encoded(str)
if @use_numeric_character_reference and !XSD::Charset.is_us_ascii(str)
str.gsub!(@encode_char_regexp) { |c| EncodeMap[c] }
str.unpack("U*").collect { |c|
if c == 0x9 or c == 0xa or c == 0xd or (c >= 0x20 and c <= 0x7f)
c.chr
else
sprintf("&#x%x;", c)
end
}.join
else
str.gsub(@encode_char_regexp) { |c| EncodeMap[c] }
end
end
def get_encode_char_regexp
ENCODE_CHAR_REGEXP[XSD::Charset.encoding] ||=
Regexp.new("[#{EncodeMap.keys.join}]", nil, XSD::Charset.encoding)
end
def find_handler(encodingstyle)
unless @handlers.key?(encodingstyle)
factory = SOAP::EncodingStyle::Handler.handler(encodingstyle)
if factory
handler = factory.new(@charset)
handler.generate_explicit_type = @generate_explicit_type
handler.encode_prologue
@handlers[encodingstyle] = handler
end
end
@handlers[encodingstyle]
end
def xmldecl
if @charset
%Q[<?xml version="1.0" encoding="#{ @charset }" ?>]
else
%Q[<?xml version="1.0" ?>]
end
end
end
SOAPGenerator = Generator # for backward compatibility
end

View file

@ -0,0 +1,61 @@
# SOAP4R - SOAP Header handler item
# Copyright (C) 2000-2007 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 'soap/element'
module SOAP
module Header
class Handler
attr_reader :elename
attr_accessor :mustunderstand
attr_reader :encodingstyle
attr_reader :target_actor
def initialize(elename)
@elename = elename
@mustunderstand = false
@encodingstyle = nil
@target_actor = nil
end
# Should return a SOAP/OM, a SOAPHeaderItem or nil.
def on_outbound
nil
end
# Given header is a SOAPHeaderItem or nil.
def on_inbound(header, mustunderstand = false)
# do something.
end
def on_outbound_headeritem(header)
arity = self.method(:on_outbound).arity
item = (arity == 0) ? on_outbound : on_outbound(header)
if item.nil?
nil
elsif item.is_a?(::SOAP::SOAPHeaderItem)
item.elename = @elename
item
else
item.elename = @elename
::SOAP::SOAPHeaderItem.new(item, @mustunderstand, @encodingstyle,
@target_actor)
end
end
def on_inbound_headeritem(header, item)
on_inbound(item.element, item.mustunderstand)
end
end
end
end

View file

@ -0,0 +1,70 @@
# SOAP4R - SOAP Header handler set
# Copyright (C) 2000-2007 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/namedelements'
module SOAP
module Header
class HandlerSet
def initialize
@store = XSD::NamedElements.new
end
def dup
obj = HandlerSet.new
obj.store = @store.dup
obj
end
def add(handler)
@store << handler
end
alias << add
def delete(handler)
@store.delete(handler)
end
def include?(handler)
@store.include?(handler)
end
# returns: Array of SOAPHeaderItem
def on_outbound(header)
@store.collect { |handler|
handler.on_outbound_headeritem(header)
}.compact
end
# header: SOAPHeaderItem enumerable object
def on_inbound(header)
header.each do |name, item|
handler = @store.find { |handler|
handler.elename == item.element.elename
}
if handler
handler.on_inbound_headeritem(header, item)
elsif item.mustunderstand
raise UnhandledMustUnderstandHeaderError.new(item.element.elename.to_s)
end
end
end
protected
def store=(store)
@store = store
end
end
end
end

View file

@ -0,0 +1,47 @@
# SOAP4R - SOAP Mapping header item handler
# Copyright (C) 2000-2007 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 'soap/header/handler'
require 'soap/mapping/mapping'
module SOAP
module Header
class MappingHandler < SOAP::Header::Handler
attr_accessor :registry
def initialize(elename, registry = nil)
super(elename)
@registry = registry
end
# Should return an Object for mapping
def on_mapping_outbound
nil
end
# Given header is a mapped Object
def on_mapping_inbound(obj, mustunderstand)
end
def on_outbound
obj = on_mapping_outbound
obj ? SOAP::Mapping.obj2soap(obj, @registry, @elename) : nil
end
def on_inbound(header, mustunderstand)
obj = SOAP::Mapping.soap2obj(header, @registry)
on_mapping_inbound(obj, mustunderstand)
end
end
end
end

View file

@ -0,0 +1,44 @@
# SOAP4R - SOAP Simple header item handler
# Copyright (C) 2000-2007 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 'soap/header/handler'
require 'soap/baseData'
module SOAP
module Header
class SimpleHandler < SOAP::Header::Handler
def initialize(elename)
super(elename)
end
# Should return a Hash, String or nil.
def on_simple_outbound
nil
end
# Given header is a Hash, String or nil.
def on_simple_inbound(header, mustunderstand)
end
def on_outbound
h = on_simple_outbound
h ? SOAPElement.from_obj(h, elename.namespace) : nil
end
def on_inbound(header, mustunderstand)
h = header.respond_to?(:to_obj) ? header.to_obj : header.data
on_simple_inbound(h, mustunderstand)
end
end
end
end

View file

@ -0,0 +1,139 @@
# SOAP4R - HTTP config loader.
# Copyright (C) 2000-2007 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 'soap/property'
module SOAP
module HTTPConfigLoader
module_function
def set_options(client, options)
client.proxy = options["proxy"]
options.add_hook("proxy") do |key, value|
client.proxy = value
end
client.no_proxy = options["no_proxy"]
options.add_hook("no_proxy") do |key, value|
client.no_proxy = value
end
if client.respond_to?(:protocol_version=)
client.protocol_version = options["protocol_version"]
options.add_hook("protocol_version") do |key, value|
client.protocol_version = value
end
end
ssl_config = options["ssl_config"] ||= ::SOAP::Property.new
set_ssl_config(client, ssl_config)
ssl_config.add_hook(true) do |key, value|
set_ssl_config(client, ssl_config)
end
basic_auth = options["basic_auth"] ||= ::SOAP::Property.new
set_basic_auth(client, basic_auth)
basic_auth.add_hook do |key, value|
set_basic_auth(client, basic_auth)
end
auth = options["auth"] ||= ::SOAP::Property.new
set_auth(client, auth)
auth.add_hook do |key, value|
set_auth(client, auth)
end
options.add_hook("connect_timeout") do |key, value|
client.connect_timeout = value
end
options.add_hook("send_timeout") do |key, value|
client.send_timeout = value
end
options.add_hook("receive_timeout") do |key, value|
client.receive_timeout = value
end
end
def set_basic_auth(client, basic_auth)
basic_auth.values.each do |ele|
client.set_basic_auth(*authele_to_triplets(ele))
end
end
def set_auth(client, auth)
auth.values.each do |ele|
client.set_auth(*authele_to_triplets(ele))
end
end
def authele_to_triplets(ele)
if ele.is_a?(::Array)
url, userid, passwd = ele
else
url, userid, passwd = ele[:url], ele[:userid], ele[:password]
end
return url, userid, passwd
end
def set_ssl_config(client, ssl_config)
ssl_config.each do |key, value|
cfg = client.ssl_config
if cfg.nil?
raise NotImplementedError.new("SSL not supported")
end
case key
when 'client_cert'
cfg.client_cert = cert_from_file(value)
when 'client_key'
cfg.client_key = key_from_file(value)
when 'client_ca'
cfg.client_ca = value
when 'ca_path'
cfg.set_trust_ca(value)
when 'ca_file'
cfg.set_trust_ca(value)
when 'crl'
cfg.set_crl(value)
when 'verify_mode'
cfg.verify_mode = ssl_config_int(value)
when 'verify_depth'
cfg.verify_depth = ssl_config_int(value)
when 'options'
cfg.options = value
when 'ciphers'
cfg.ciphers = value
when 'verify_callback'
cfg.verify_callback = value
when 'cert_store'
cfg.cert_store = value
else
raise ArgumentError.new("unknown ssl_config property #{key}")
end
end
end
def ssl_config_int(value)
if value.nil? or value.to_s.empty?
nil
else
begin
Integer(value)
rescue ArgumentError
::SOAP::Property::Util.const_from_name(value.to_s)
end
end
end
def cert_from_file(filename)
OpenSSL::X509::Certificate.new(File.open(filename) { |f| f.read })
end
def key_from_file(filename)
OpenSSL::PKey::RSA.new(File.open(filename) { |f| f.read })
end
end
end

View file

@ -0,0 +1,12 @@
# SOAP4R - Ruby type mapping utility.
# Copyright (C) 2000-2007 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 'soap/mapping/mapping'
require 'soap/mapping/registry'
require 'soap/mapping/encodedregistry'
require 'soap/mapping/literalregistry'

View file

@ -0,0 +1,548 @@
# SOAP4R - encoded mapping registry.
# Copyright (C) 2000-2007 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 'soap/baseData'
require 'soap/mapping/mapping'
require 'soap/mapping/typeMap'
require 'soap/mapping/factory'
require 'soap/mapping/rubytypeFactory'
module SOAP
module Mapping
# Inner class to pass an exception.
class SOAPException
attr_reader :excn_type_name, :cause
def initialize(e)
@excn_type_name = Mapping.name2elename(e.class.to_s)
@cause = e
end
def to_e
if @cause.is_a?(::Exception)
@cause.extend(::SOAP::Mapping::MappedException)
return @cause
elsif @cause.respond_to?(:message) and @cause.respond_to?(:backtrace)
e = RuntimeError.new(@cause.message)
e.set_backtrace(@cause.backtrace)
return e
end
klass = Mapping.class_from_name(Mapping.elename2name(@excn_type_name.to_s))
if klass.nil? or not klass <= ::Exception
return RuntimeError.new(@cause.inspect)
end
obj = klass.new(@cause.message)
obj.extend(::SOAP::Mapping::MappedException)
obj
end
end
class EncodedRegistry
include TraverseSupport
include RegistrySupport
class Map
def initialize(registry)
@obj2soap = {}
@soap2obj = {}
@registry = registry
end
def obj2soap(obj)
klass = obj.class
if map = @obj2soap[klass]
map.each do |soap_class, factory, info|
ret = factory.obj2soap(soap_class, obj, info, @registry)
return ret if ret
end
end
klass.ancestors.each do |baseclass|
next if baseclass == klass
if map = @obj2soap[baseclass]
map.each do |soap_class, factory, info|
if info[:derived_class]
ret = factory.obj2soap(soap_class, obj, info, @registry)
return ret if ret
end
end
end
end
nil
end
def soap2obj(node, klass = nil)
if map = @soap2obj[node.class]
map.each do |obj_class, factory, info|
next if klass and obj_class != klass
conv, obj = factory.soap2obj(obj_class, node, info, @registry)
return true, obj if conv
end
end
return false, nil
end
# Give priority to former entry.
def init(init_map = [])
clear
init_map.reverse_each do |obj_class, soap_class, factory, info|
add(obj_class, soap_class, factory, info)
end
end
# Give priority to latter entry.
def add(obj_class, soap_class, factory, info)
info ||= {}
(@obj2soap[obj_class] ||= []).unshift([soap_class, factory, info])
(@soap2obj[soap_class] ||= []).unshift([obj_class, factory, info])
end
def clear
@obj2soap.clear
@soap2obj.clear
end
def find_mapped_soap_class(target_obj_class)
map = @obj2soap[target_obj_class]
map.empty? ? nil : map[0][1]
end
def find_mapped_obj_class(target_soap_class)
map = @soap2obj[target_soap_class]
map.empty? ? nil : map[0][0]
end
end
StringFactory = StringFactory_.new
BasetypeFactory = BasetypeFactory_.new
FixnumFactory = FixnumFactory_.new
DateTimeFactory = DateTimeFactory_.new
ArrayFactory = ArrayFactory_.new
Base64Factory = Base64Factory_.new
URIFactory = URIFactory_.new
TypedArrayFactory = TypedArrayFactory_.new
TypedStructFactory = TypedStructFactory_.new
HashFactory = HashFactory_.new
SOAPBaseMap = [
[::NilClass, ::SOAP::SOAPNil, BasetypeFactory],
[::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory],
[::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
[::String, ::SOAP::SOAPString, StringFactory,
{:derived_class => true}],
[::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Date, ::SOAP::SOAPDate, DateTimeFactory],
[::Time, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Time, ::SOAP::SOAPTime, DateTimeFactory],
[::Float, ::SOAP::SOAPDouble, BasetypeFactory,
{:derived_class => true}],
[::Float, ::SOAP::SOAPFloat, BasetypeFactory,
{:derived_class => true}],
[::Fixnum, ::SOAP::SOAPInt, FixnumFactory],
[::Integer, ::SOAP::SOAPInt, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPLong, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPInteger, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPShort, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPByte, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPNonPositiveInteger, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPNegativeInteger, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPNonNegativeInteger, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPPositiveInteger, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPUnsignedLong, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPUnsignedInt, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPUnsignedShort, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPUnsignedByte, BasetypeFactory,
{:derived_class => true}],
[::URI::Generic, ::SOAP::SOAPAnyURI, URIFactory,
{:derived_class => true}],
[::String, ::SOAP::SOAPBase64, Base64Factory],
[::String, ::SOAP::SOAPHexBinary, Base64Factory],
[::String, ::SOAP::SOAPDecimal, BasetypeFactory],
[::String, ::SOAP::SOAPDuration, BasetypeFactory],
[::String, ::SOAP::SOAPGYearMonth, BasetypeFactory],
[::String, ::SOAP::SOAPGYear, BasetypeFactory],
[::String, ::SOAP::SOAPGMonthDay, BasetypeFactory],
[::String, ::SOAP::SOAPGDay, BasetypeFactory],
[::String, ::SOAP::SOAPGMonth, BasetypeFactory],
[::String, ::SOAP::SOAPQName, BasetypeFactory],
[::Hash, ::SOAP::SOAPArray, HashFactory,
{:derived_class => true}],
[::Hash, ::SOAP::SOAPStruct, HashFactory,
{:derived_class => true}],
[::Array, ::SOAP::SOAPArray, ArrayFactory,
{:derived_class => true}],
[::SOAP::Mapping::SOAPException,
::SOAP::SOAPStruct, TypedStructFactory,
{:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}],
]
RubyOriginalMap = [
[::NilClass, ::SOAP::SOAPNil, BasetypeFactory],
[::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory],
[::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
[::String, ::SOAP::SOAPString, StringFactory],
[::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Date, ::SOAP::SOAPDate, DateTimeFactory],
[::Time, ::SOAP::SOAPDateTime, DateTimeFactory],
[::Time, ::SOAP::SOAPTime, DateTimeFactory],
[::Float, ::SOAP::SOAPDouble, BasetypeFactory,
{:derived_class => true}],
[::Float, ::SOAP::SOAPFloat, BasetypeFactory,
{:derived_class => true}],
[::Fixnum, ::SOAP::SOAPInt, FixnumFactory],
[::Integer, ::SOAP::SOAPInt, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPLong, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPInteger, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPShort, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPByte, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPNonPositiveInteger, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPNegativeInteger, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPNonNegativeInteger, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPPositiveInteger, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPUnsignedLong, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPUnsignedInt, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPUnsignedShort, BasetypeFactory,
{:derived_class => true}],
[::Integer, ::SOAP::SOAPUnsignedByte, BasetypeFactory,
{:derived_class => true}],
[::URI::Generic, ::SOAP::SOAPAnyURI, URIFactory,
{:derived_class => true}],
[::String, ::SOAP::SOAPBase64, Base64Factory],
[::String, ::SOAP::SOAPHexBinary, Base64Factory],
[::String, ::SOAP::SOAPDecimal, BasetypeFactory],
[::String, ::SOAP::SOAPDuration, BasetypeFactory],
[::String, ::SOAP::SOAPGYearMonth, BasetypeFactory],
[::String, ::SOAP::SOAPGYear, BasetypeFactory],
[::String, ::SOAP::SOAPGMonthDay, BasetypeFactory],
[::String, ::SOAP::SOAPGDay, BasetypeFactory],
[::String, ::SOAP::SOAPGMonth, BasetypeFactory],
[::String, ::SOAP::SOAPQName, BasetypeFactory],
[::Hash, ::SOAP::SOAPArray, HashFactory],
[::Hash, ::SOAP::SOAPStruct, HashFactory],
# Does not allow Array's subclass here.
[::Array, ::SOAP::SOAPArray, ArrayFactory],
[::SOAP::Mapping::SOAPException,
::SOAP::SOAPStruct, TypedStructFactory,
{:type => XSD::QName.new(RubyCustomTypeNamespace, "SOAPException")}],
]
attr_accessor :default_factory
attr_accessor :excn_handler_obj2soap
attr_accessor :excn_handler_soap2obj
def initialize(config = {})
super()
@config = config
@map = Map.new(self)
if @config[:allow_original_mapping]
@allow_original_mapping = true
@map.init(RubyOriginalMap)
else
@allow_original_mapping = false
@map.init(SOAPBaseMap)
end
@allow_untyped_struct = @config.key?(:allow_untyped_struct) ?
@config[:allow_untyped_struct] : true
@rubytype_factory = RubytypeFactory.new(
:allow_untyped_struct => @allow_untyped_struct,
:allow_original_mapping => @allow_original_mapping
)
@default_factory = @rubytype_factory
@excn_handler_obj2soap = nil
@excn_handler_soap2obj = nil
end
# initial mapping interface
# new interface Registry#register is defined in RegisterSupport
def add(obj_class, soap_class, factory, info = nil)
@map.add(obj_class, soap_class, factory, info)
end
alias set add
def obj2soap(obj, type_qname = nil)
soap = _obj2soap(obj, type_qname)
if @allow_original_mapping
addextend2soap(soap, obj)
end
soap
end
def soap2obj(node, klass = nil)
obj = _soap2obj(node, klass)
if @allow_original_mapping
addextend2obj(obj, node.extraattr[RubyExtendName])
addiv2obj(obj, node.extraattr[RubyIVarName])
end
obj
end
def find_mapped_soap_class(obj_class)
@map.find_mapped_soap_class(obj_class)
end
def find_mapped_obj_class(soap_class)
@map.find_mapped_obj_class(soap_class)
end
private
def _obj2soap(obj, type_qname = nil)
ret = nil
if obj.is_a?(SOAPCompoundtype)
obj.replace do |ele|
Mapping._obj2soap(ele, self)
end
return obj
elsif obj.is_a?(SOAPBasetype)
return obj
elsif type_qname && type = TypeMap[type_qname]
return base2soap(obj, type)
end
cause = nil
begin
if definition = schema_definition_from_class(obj.class)
return stubobj2soap(obj, definition)
end
ret = @map.obj2soap(obj) ||
@default_factory.obj2soap(nil, obj, nil, self)
return ret if ret
rescue MappingError
cause = $!
end
if @excn_handler_obj2soap
ret = @excn_handler_obj2soap.call(obj) { |yield_obj|
Mapping._obj2soap(yield_obj, self)
}
return ret if ret
end
raise MappingError.new("Cannot map #{ obj.class.name } to SOAP/OM.", cause)
end
# Might return nil as a mapping result.
def _soap2obj(node, klass = nil)
definition = find_node_definition(node)
if klass
klass_definition = schema_definition_from_class(klass)
if definition and (definition.class_for < klass)
klass = definition.class_for
else
definition = klass_definition
end
else
klass = definition.class_for if definition
end
if definition and node.is_a?(::SOAP::SOAPNameAccessible)
return elesoap2stubobj(node, klass, definition)
end
if node.extraattr.key?(RubyTypeName)
conv, obj = @rubytype_factory.soap2obj(nil, node, nil, self)
return obj if conv
end
conv, obj = @map.soap2obj(node)
return obj if conv
conv, obj = @default_factory.soap2obj(nil, node, nil, self)
return obj if conv
cause = nil
if @excn_handler_soap2obj
begin
return @excn_handler_soap2obj.call(node) { |yield_node|
Mapping._soap2obj(yield_node, self)
}
rescue Exception
cause = $!
end
end
raise MappingError.new("Cannot map #{ node.type.name } to Ruby object.", cause)
end
def addiv2obj(obj, attr)
return unless attr
vars = {}
attr.__getobj__.each do |name, value|
vars[name] = Mapping._soap2obj(value, self)
end
Mapping.set_attributes(obj, vars)
end
if RUBY_VERSION >= '1.8.0'
def addextend2obj(obj, attr)
return unless attr
attr.split(/ /).reverse_each do |mstr|
obj.extend(Mapping.module_from_name(mstr))
end
end
else
# (class < false; self; end).ancestors includes "TrueClass" under 1.6...
def addextend2obj(obj, attr)
return unless attr
attr.split(/ /).reverse_each do |mstr|
m = Mapping.module_from_name(mstr)
obj.extend(m)
end
end
end
def addextend2soap(node, obj)
return if obj.is_a?(Symbol) or obj.is_a?(Fixnum)
list = (class << obj; self; end).ancestors - obj.class.ancestors
unless list.empty?
node.extraattr[RubyExtendName] = list.collect { |c|
name = c.name
if name.nil? or name.empty?
raise TypeError.new("singleton can't be dumped #{ obj }")
end
name
}.join(" ")
end
end
def stubobj2soap(obj, definition)
case obj
when ::Array
array2soap(obj, definition)
else
unknownstubobj2soap(obj, definition)
end
end
def array2soap(obj, definition)
return SOAPNil.new if obj.nil? # ToDo: check nillable.
eledef = definition.elements[0]
soap_obj = SOAPArray.new(ValueArrayName, 1, eledef.elename)
mark_marshalled_obj(obj, soap_obj)
obj.each do |item|
soap_obj.add(typedobj2soap(item, eledef.mapped_class))
end
soap_obj
end
def unknownstubobj2soap(obj, definition)
return SOAPNil.new if obj.nil?
if definition.elements.size == 0
ele = Mapping.obj2soap(obj)
ele.elename = definition.elename if definition.elename
ele.extraattr[XSD::AttrTypeName] = definition.type if definition.type
return ele
else
ele = SOAPStruct.new(definition.type)
mark_marshalled_obj(obj, ele)
end
definition.elements.each do |eledef|
name = eledef.elename.name
if obj.respond_to?(:each) and eledef.as_array?
obj.each do |item|
ele.add(name, typedobj2soap(item, eledef.mapped_class))
end
else
child = Mapping.get_attribute(obj, eledef.varname)
if child.respond_to?(:each) and eledef.as_array?
child.each do |item|
ele.add(name, typedobj2soap(item, eledef.mapped_class))
end
else
ele.add(name, typedobj2soap(child, eledef.mapped_class))
end
end
end
ele
end
def typedobj2soap(value, klass)
if klass and klass.include?(::SOAP::SOAPBasetype)
base2soap(value, klass)
else
Mapping._obj2soap(value, self)
end
end
def elesoap2stubobj(node, obj_class, definition)
obj = Mapping.create_empty_object(obj_class)
add_elesoap2stubobj(node, obj, definition)
obj
end
# XXX consider to merge with the method in LiteralRegistry
def add_elesoap2stubobj(node, obj, definition)
vars = {}
node.each do |name, value|
item = definition.elements.find_element(value.elename)
if item
child = soap2typedobj(value, item.mapped_class)
else
# unknown element is treated as anyType.
child = Mapping._soap2obj(value, self)
end
if item and item.as_array?
(vars[name] ||= []) << child
elsif vars.key?(name)
vars[name] = [vars[name], child].flatten
else
vars[name] = child
end
end
if obj.is_a?(::Array) and is_stubobj_elements_for_array(vars)
Array.instance_method(:replace).bind(obj).call(vars.values[0])
else
Mapping.set_attributes(obj, vars)
end
end
def soap2typedobj(value, klass)
unless klass
raise MappingError.new("unknown class: #{klass}")
end
if klass.include?(::SOAP::SOAPBasetype)
obj = base2obj(value, klass)
else
obj = Mapping._soap2obj(value, self, klass)
end
obj
end
end
Registry = EncodedRegistry
DefaultRegistry = EncodedRegistry.new
RubyOriginalRegistry = EncodedRegistry.new(:allow_original_mapping => true)
end
end

View file

@ -0,0 +1,388 @@
# SOAP4R - Mapping factory.
# Copyright (C) 2000-2007 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.
module SOAP
module Mapping
class Factory
include TraverseSupport
def initialize
# nothing to do
end
def obj2soap(soap_class, obj, info, map)
raise NotImplementError.new
# return soap_obj
end
def soap2obj(obj_class, node, info, map)
raise NotImplementError.new
# return convert_succeeded_or_not, obj
end
def setiv2obj(obj, node, map)
return if node.nil?
if obj.is_a?(Array)
setiv2ary(obj, node, map)
else
setiv2struct(obj, node, map)
end
end
def setiv2soap(node, obj, map)
if obj.class.class_variables.include?('@@schema_element')
setdefinediv2soap(node, obj, map)
else
# should we sort instance_variables? how?
obj.instance_variables.each do |var|
name = var.sub(/^@/, '')
elename = Mapping.name2elename(name)
node.add(elename,
Mapping._obj2soap(obj.instance_variable_get(var), map))
end
end
end
private
def setdefinediv2soap(ele, obj, map)
definition = Mapping.schema_definition_classdef(obj.class)
definition.elements.each do |eledef|
child = Mapping.get_attribute(obj, eledef.varname)
# extract method
if child.nil?
value = SOAPNil.new
elsif child.is_a?(XSD::NSDBase)
value = child
else
klass = Mapping.class_from_name(eledef.type)
if klass && klass.include?(::SOAP::SOAPBasetype)
value = klass.new(child)
else
# should check klass matches an actual object?
value = Mapping._obj2soap(child, map)
end
end
ele.add(eledef.elename.name, value)
end
end
def setiv2ary(obj, node, map)
node.each do |name, value|
Array.instance_method(:<<).bind(obj).call(Mapping._soap2obj(value, map))
end
end
def setiv2struct(obj, node, map)
vars = {}
node.each do |name, value|
vars[Mapping.elename2name(name)] = Mapping._soap2obj(value, map)
end
Mapping.set_attributes(obj, vars)
end
def anonymous_class?(obj)
name = obj.class.name
name.nil? or name.empty? # 1.8 returns ""
end
end
class StringFactory_ < Factory
def initialize(allow_original_mapping = false)
super()
@allow_original_mapping = allow_original_mapping
end
def obj2soap(soap_class, obj, info, map)
if !@allow_original_mapping and !obj.instance_variables.empty?
return nil
end
begin
encoded = XSD::Charset.encoding_conv(obj, Mapping.external_ces,
XSD::Charset.encoding)
soap_obj = soap_class.new(encoded)
rescue XSD::ValueSpaceError
return nil
end
mark_marshalled_obj(obj, soap_obj)
soap_obj
end
def soap2obj(obj_class, node, info, map)
obj = Mapping.create_empty_object(obj_class)
decoded = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding,
Mapping.external_ces)
obj.replace(decoded)
mark_unmarshalled_obj(node, obj)
return true, obj
end
end
class FixnumFactory_ < Factory
def obj2soap(soap_class, obj, info, map)
soap_obj = nil
begin
soap_obj = soap_class.new(obj)
rescue XSD::ValueSpaceError
return nil
end
soap_obj
end
def soap2obj(obj_class, node, info, map)
obj = node.data
return true, obj
end
end
class BasetypeFactory_ < Factory
def initialize(allow_original_mapping = false)
super()
@allow_original_mapping = allow_original_mapping
end
def obj2soap(soap_class, obj, info, map)
if !@allow_original_mapping and !obj.instance_variables.empty?
return nil
end
soap_obj = nil
begin
soap_obj = soap_class.new(obj)
rescue XSD::ValueSpaceError
return nil
end
if @allow_original_mapping
# Basetype except String should not be multiref-ed in SOAP/1.1.
mark_marshalled_obj(obj, soap_obj)
end
soap_obj
end
def soap2obj(obj_class, node, info, map)
obj = node.data
mark_unmarshalled_obj(node, obj)
return true, obj
end
end
class DateTimeFactory_ < Factory
def initialize(allow_original_mapping = false)
super()
@allow_original_mapping = allow_original_mapping
end
def obj2soap(soap_class, obj, info, map)
if !@allow_original_mapping and
Time === obj and !obj.instance_variables.empty?
return nil
end
soap_obj = nil
begin
soap_obj = soap_class.new(obj)
rescue XSD::ValueSpaceError
return nil
end
mark_marshalled_obj(obj, soap_obj)
soap_obj
end
def soap2obj(obj_class, node, info, map)
if node.respond_to?(:to_obj)
obj = node.to_obj(obj_class)
return false if obj.nil?
mark_unmarshalled_obj(node, obj)
return true, obj
else
return false
end
end
end
class Base64Factory_ < Factory
def obj2soap(soap_class, obj, info, map)
return nil unless obj.instance_variables.empty?
soap_obj = soap_class.new(obj)
mark_marshalled_obj(obj, soap_obj) if soap_obj
soap_obj
end
def soap2obj(obj_class, node, info, map)
obj = node.string
mark_unmarshalled_obj(node, obj)
return true, obj
end
end
class URIFactory_ < Factory
def obj2soap(soap_class, obj, info, map)
soap_obj = soap_class.new(obj)
mark_marshalled_obj(obj, soap_obj) if soap_obj
soap_obj
end
def soap2obj(obj_class, node, info, map)
obj = node.data
mark_unmarshalled_obj(node, obj)
return true, obj
end
end
class ArrayFactory_ < Factory
def initialize(allow_original_mapping = false)
super()
@allow_original_mapping = allow_original_mapping
end
# [[1], [2]] is converted to Array of Array, not 2-D Array.
# To create M-D Array, you must call Mapping.ary2md.
def obj2soap(soap_class, obj, info, map)
if !@allow_original_mapping and !obj.instance_variables.empty?
return nil
end
arytype = Mapping.obj2element(obj)
if arytype.name
arytype.namespace ||= RubyTypeNamespace
else
arytype = XSD::AnyTypeName
end
soap_obj = SOAPArray.new(ValueArrayName, 1, arytype)
mark_marshalled_obj(obj, soap_obj)
obj.each do |item|
soap_obj.add(Mapping._obj2soap(item, map))
end
soap_obj
end
def soap2obj(obj_class, node, info, map)
obj = Mapping.create_empty_object(obj_class)
mark_unmarshalled_obj(node, obj)
node.soap2array(obj) do |elem|
elem ? Mapping._soap2obj(elem, map) : nil
end
return true, obj
end
end
class TypedArrayFactory_ < Factory
def initialize(allow_original_mapping = false)
super()
@allow_original_mapping = allow_original_mapping
end
def obj2soap(soap_class, obj, info, map)
if !@allow_original_mapping and !obj.instance_variables.empty?
return nil
end
arytype = info[:type] || info[0]
soap_obj = SOAPArray.new(ValueArrayName, 1, arytype)
mark_marshalled_obj(obj, soap_obj)
obj.each do |var|
soap_obj.add(Mapping._obj2soap(var, map))
end
soap_obj
end
def soap2obj(obj_class, node, info, map)
if node.rank > 1
return false
end
arytype = info[:type] || info[0]
unless node.arytype == arytype
return false
end
obj = Mapping.create_empty_object(obj_class)
mark_unmarshalled_obj(node, obj)
node.soap2array(obj) do |elem|
elem ? Mapping._soap2obj(elem, map) : nil
end
return true, obj
end
end
class TypedStructFactory_ < Factory
def obj2soap(soap_class, obj, info, map)
type = info[:type] || info[0]
soap_obj = soap_class.new(type)
mark_marshalled_obj(obj, soap_obj)
if obj.class <= SOAP::Marshallable
setiv2soap(soap_obj, obj, map)
else
# allow to serialize an instance of unmarked class
setiv2soap(soap_obj, obj, map)
end
soap_obj
end
def soap2obj(obj_class, node, info, map)
type = info[:type] || info[0]
unless node.type == type
return false
end
obj = Mapping.create_empty_object(obj_class)
mark_unmarshalled_obj(node, obj)
setiv2obj(obj, node, map)
return true, obj
end
end
MapQName = XSD::QName.new(ApacheSOAPTypeNamespace, 'Map')
class HashFactory_ < Factory
def initialize(allow_original_mapping = false)
super()
@allow_original_mapping = allow_original_mapping
end
def obj2soap(soap_class, obj, info, map)
if !@allow_original_mapping and !obj.instance_variables.empty?
return nil
end
if !obj.default.nil? or
(obj.respond_to?(:default_proc) and obj.default_proc)
return nil
end
soap_obj = SOAPStruct.new(MapQName)
mark_marshalled_obj(obj, soap_obj)
obj.each do |key, value|
elem = SOAPStruct.new
elem.add("key", Mapping._obj2soap(key, map))
elem.add("value", Mapping._obj2soap(value, map))
# ApacheAxis allows only 'item' here.
soap_obj.add("item", elem)
end
soap_obj
end
def soap2obj(obj_class, node, info, map)
unless node.type == MapQName
return false
end
if node.class == SOAPStruct and node.key?('default')
return false
end
obj = Mapping.create_empty_object(obj_class)
mark_unmarshalled_obj(node, obj)
if node.class == SOAPStruct
node.each do |key, value|
obj[Mapping._soap2obj(value['key'], map)] =
Mapping._soap2obj(value['value'], map)
end
else
node.each do |value|
obj[Mapping._soap2obj(value['key'], map)] =
Mapping._soap2obj(value['value'], map)
end
end
return true, obj
end
end
end
end

View file

@ -0,0 +1,388 @@
# SOAP4R - literal mapping registry.
# Copyright (C) 2000-2007 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 'soap/baseData'
require 'soap/mapping/mapping'
require 'soap/mapping/typeMap'
require 'xsd/codegen/gensupport'
require 'xsd/namedelements'
module SOAP
module Mapping
class LiteralRegistry
include RegistrySupport
attr_accessor :excn_handler_obj2soap
attr_accessor :excn_handler_soap2obj
def initialize
super()
@excn_handler_obj2soap = nil
@excn_handler_soap2obj = nil
end
def obj2soap(obj, qname, obj_class = nil)
soap_obj = nil
if obj.is_a?(SOAPElement)
soap_obj = obj
else
soap_obj = any2soap(obj, qname, obj_class)
end
return soap_obj if soap_obj
if @excn_handler_obj2soap
soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj|
Mapping.obj2soap(yield_obj, nil, nil, MAPPING_OPT)
}
return soap_obj if soap_obj
end
raise MappingError.new("cannot map #{obj.class.name} as #{qname}")
end
# node should be a SOAPElement
def soap2obj(node, obj_class = nil)
cause = nil
begin
return any2obj(node, obj_class)
rescue MappingError
cause = $!
end
if @excn_handler_soap2obj
begin
return @excn_handler_soap2obj.call(node) { |yield_node|
Mapping.soap2obj(yield_node, nil, nil, MAPPING_OPT)
}
rescue Exception
end
end
raise MappingError.new("cannot map #{node.elename.name}/#{node.type.name} to Ruby object", cause)
end
private
MAPPING_OPT = { :no_reference => true }
def definedobj2soap(obj, definition)
obj2soap(obj, definition.elename, definition.mapped_class)
end
def any2soap(obj, qname, obj_class)
ele = nil
if obj.is_a?(SOAP::Mapping::Object)
return mappingobj2soap(obj, qname)
end
class_definition = schema_definition_from_class(obj.class)
if class_definition.nil? and obj_class
class_definition = schema_definition_from_class(obj_class)
end
elename_definition = schema_definition_from_elename(qname)
if !class_definition and !elename_definition
# no definition found
return anyobj2soap(obj, qname)
end
if !class_definition or !elename_definition
# use found one
return stubobj2soap(obj, qname, class_definition || elename_definition)
end
# found both:
if class_definition.class_for == elename_definition.class_for
# if two definitions are for the same class, give qname a priority.
return stubobj2soap(obj, qname, elename_definition)
end
# it should be a derived class
return stubobj2soap(obj, qname, class_definition)
end
def anyobj2soap(obj, qname)
ele = nil
case obj
when Hash
ele = SOAPElement.from_obj(obj, nil)
ele.elename = qname
when Array
# treat as a list of simpletype
ele = SOAPElement.new(qname, obj.join(" "))
when XSD::QName
ele = SOAPElement.new(qname)
ele.text = obj
else
# expected to be a basetype or an anyType.
# SOAPStruct, etc. is used instead of SOAPElement.
begin
ele = Mapping.obj2soap(obj, nil, nil, MAPPING_OPT)
ele.elename = qname
rescue MappingError
ele = SOAPElement.new(qname, obj.to_s)
end
end
add_attributes2soap(obj, ele)
ele
end
def stubobj2soap(obj, qname, definition)
if obj.nil?
ele = SOAPNil.new
ele.elename = qname
elsif obj.is_a?(::String)
ele = SOAPElement.new(qname, obj)
else
ele = SOAPElement.new(qname)
end
ele.qualified = definition.qualified
if definition.type and (definition.basetype or Mapping.root_type_hint)
Mapping.reset_root_type_hint
ele.extraattr[XSD::AttrTypeName] = definition.type
end
if qname.nil? and definition.elename
ele.elename = definition.elename
end
return ele if obj.nil?
stubobj2soap_elements(obj, ele, definition.elements)
add_definedattributes2soap(obj, ele, definition)
ele
end
def stubobj2soap_elements(obj, ele, definition, is_choice = false)
added = false
case definition
when SchemaSequenceDefinition, SchemaEmptyDefinition
definition.each do |eledef|
ele_added = stubobj2soap_elements(obj, ele, eledef, is_choice)
added = true if ele_added
end
when SchemaChoiceDefinition
definition.each do |eledef|
added = stubobj2soap_elements(obj, ele, eledef, true)
break if added
end
else
added = true
if definition.as_any?
any = Mapping.get_attributes_for_any(obj)
SOAPElement.from_objs(any).each do |child|
ele.add(child)
end
elsif obj.respond_to?(:each) and definition.as_array?
obj.each do |item|
ele.add(definedobj2soap(item, definition))
end
else
child = Mapping.get_attribute(obj, definition.varname)
if child.nil? and (is_choice or definition.minoccurs == 0)
added = false
else
if child.respond_to?(:each) and definition.as_array?
if child.empty?
added = false
else
child.each do |item|
ele.add(definedobj2soap(item, definition))
end
end
else
ele.add(definedobj2soap(child, definition))
end
end
end
end
added
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 any2obj(node, obj_class = nil)
is_compound = node.is_a?(::SOAP::SOAPCompoundtype)
# trust xsi:type first
if is_compound and node.type
definition = schema_definition_from_type(node.type)
end
# element name next
definition ||= schema_definition_from_elename(node.elename)
# class defined in parent type last
if obj_class
definition ||= schema_definition_from_class(obj_class)
end
if definition
obj_class = definition.class_for
end
if is_compound
if definition
return elesoap2stubobj(node, obj_class, definition)
elsif node.is_a?(::SOAP::SOAPNameAccessible)
return elesoap2plainobj(node)
end
end
obj = Mapping.soap2obj(node, nil, obj_class, MAPPING_OPT)
add_attributes2obj(node, obj)
obj
end
def elesoap2stubobj(node, obj_class, definition)
obj = nil
if obj_class == ::String
obj = node.text
elsif obj_class < ::String
obj = obj_class.new(node.text)
else
obj = Mapping.create_empty_object(obj_class)
add_elesoap2stubobj(node, obj, definition)
end
add_attributes2stubobj(node, obj, definition)
obj
end
def elesoap2plainobj(node)
obj = nil
if !node.have_member
obj = base2obj(node, ::SOAP::SOAPString)
else
obj = anytype2obj(node)
add_elesoap2plainobj(node, obj)
end
add_attributes2obj(node, obj)
obj
end
def anytype2obj(node)
if node.is_a?(::SOAP::SOAPBasetype)
return node.data
end
::SOAP::Mapping::Object.new
end
def add_elesoap2stubobj(node, obj, definition)
vars = {}
node.each do |name, value|
item = definition.elements.find_element(value.elename)
if item
child = elesoapchild2obj(value, item)
else
# unknown element is treated as anyType.
child = any2obj(value)
end
if item and item.as_array?
(vars[name] ||= []) << child
elsif vars.key?(name)
vars[name] = [vars[name], child].flatten
else
vars[name] = child
end
end
if obj.is_a?(::Array) and is_stubobj_elements_for_array(vars)
Array.instance_method(:replace).bind(obj).call(vars.values[0])
else
Mapping.set_attributes(obj, vars)
end
end
def elesoapchild2obj(value, eledef)
if eledef.mapped_class
if eledef.mapped_class.include?(::SOAP::SOAPBasetype)
base2obj(value, eledef.mapped_class)
else
any2obj(value, eledef.mapped_class)
end
else
child_definition = schema_definition_from_elename(eledef.elename)
if child_definition
any2obj(value, child_definition.class_for)
else
# untyped element is treated as anyType.
any2obj(value)
end
end
end
def add_attributes2stubobj(node, obj, definition)
return if obj.nil? or node.extraattr.empty?
if attributes = definition.attributes
define_xmlattr(obj)
attributes.each do |qname, class_name|
child = node.extraattr[qname]
next if child.nil?
if class_name
klass = Mapping.class_from_name(class_name)
if klass.include?(::SOAP::SOAPBasetype)
child = klass.to_data(child)
end
end
obj.__xmlattr[qname] = child
define_xmlattr_accessor(obj, qname)
end
end
end
def add_elesoap2plainobj(node, obj)
node.each do |name, value|
obj.__add_xmlele_value(value.elename, any2obj(value))
end
end
def add_attributes2obj(node, obj)
return if obj.nil? or node.extraattr.empty?
define_xmlattr(obj)
node.extraattr.each do |qname, value|
obj.__xmlattr[qname] = value
define_xmlattr_accessor(obj, qname)
end
end
# Mapping.define_attr_accessor calls define_method with proc and it exhausts
# much memory for each singleton Object. just instance_eval instead of it.
def define_xmlattr_accessor(obj, qname)
# untaint depends GenSupport.safemethodname
name = Mapping.safemethodname('xmlattr_' + qname.name).untaint
unless obj.respond_to?(name)
# untaint depends QName#dump
qnamedump = qname.dump.untaint
obj.instance_eval <<-EOS
def #{name}
@__xmlattr[#{qnamedump}]
end
def #{name}=(value)
@__xmlattr[#{qnamedump}] = value
end
EOS
end
end
# Mapping.define_attr_accessor calls define_method with proc and it exhausts
# much memory for each singleton Object. just instance_eval instead of it.
def define_xmlattr(obj)
obj.instance_variable_set('@__xmlattr', {})
unless obj.respond_to?(:__xmlattr)
obj.instance_eval <<-EOS
def __xmlattr
@__xmlattr
end
EOS
end
end
end
end
end

View file

@ -0,0 +1,609 @@
# SOAP4R - Ruby type mapping utility.
# Copyright (C) 2000-2007 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/codegen/gensupport'
require 'soap/mapping/schemadefinition'
module SOAP
module Mapping
RubyTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/1.6'
RubyTypeInstanceNamespace =
'http://www.ruby-lang.org/xmlns/ruby/type-instance'
RubyCustomTypeNamespace = 'http://www.ruby-lang.org/xmlns/ruby/type/custom'
ApacheSOAPTypeNamespace = 'http://xml.apache.org/xml-soap'
module TraverseSupport
def mark_marshalled_obj(obj, soap_obj)
raise if obj.nil?
Thread.current[:SOAPMapping][:MarshalKey][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[:SOAPMapping][:MarshalKey][node.id] = obj
end
end
EMPTY_OPT = {}.freeze
def self.obj2soap(obj, registry = nil, type = nil, opt = EMPTY_OPT)
registry ||= Mapping::DefaultRegistry
soap_obj = nil
protect_mapping(opt) do
soap_obj = _obj2soap(obj, registry, type)
end
soap_obj
end
def self.objs2soap(objs, registry = nil, types = nil, opt = EMPTY_OPT)
registry ||= Mapping::DefaultRegistry
ary = []
protect_mapping(opt) do
0.upto(objs.length - 1) do |idx|
type = types ? types[idx] : nil
soap = _obj2soap(objs[idx], registry, type)
ary << soap
end
end
ary
end
def self.soap2obj(node, registry = nil, klass = nil, opt = EMPTY_OPT)
registry ||= Mapping::DefaultRegistry
obj = nil
protect_mapping(opt) do
obj = _soap2obj(node, registry, klass)
end
obj
end
def self.ary2soap(ary, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil, opt = EMPTY_OPT)
registry ||= Mapping::DefaultRegistry
type = XSD::QName.new(type_ns, typename)
soap_ary = SOAPArray.new(ValueArrayName, 1, type)
protect_mapping(opt) do
ary.each do |ele|
soap_ary.add(_obj2soap(ele, registry, type))
end
end
soap_ary
end
def self.ary2md(ary, rank, type_ns = XSD::Namespace, typename = XSD::AnyTypeLiteral, registry = nil, opt = EMPTY_OPT)
registry ||= Mapping::DefaultRegistry
type = XSD::QName.new(type_ns, typename)
md_ary = SOAPArray.new(ValueArrayName, rank, type)
protect_mapping(opt) do
add_md_ary(md_ary, ary, [], registry)
end
md_ary
end
def self.fault2exception(fault, registry = nil)
registry ||= Mapping::DefaultRegistry
detail = if fault.detail
soap2obj(fault.detail, registry) || ""
else
""
end
if detail.is_a?(Mapping::SOAPException)
begin
e = detail.to_e
remote_backtrace = e.backtrace
e.set_backtrace(nil)
raise e # ruby sets current caller as local backtrace of e => e2.
rescue Exception => e
e.set_backtrace(remote_backtrace + e.backtrace[1..-1])
raise
end
else
fault.detail = detail
fault.set_backtrace(
if detail.is_a?(Array)
detail
else
[detail.to_s]
end
)
raise
end
end
def self._obj2soap(obj, registry, type = nil)
if obj.respond_to?(:to_xmlpart)
SOAPRawData.new(obj)
elsif defined?(::REXML) and obj.is_a?(::REXML::Element)
SOAPRawData.new(SOAPREXMLElementWrap.new(obj))
elsif referent = Thread.current[:SOAPMapping][:MarshalKey][obj.__id__] and
!Thread.current[:SOAPMapping][:NoReference]
SOAPReference.new(referent)
elsif registry
registry.obj2soap(obj, type)
else
raise MappingError.new("no mapping registry given")
end
end
def self._soap2obj(node, registry, klass = nil)
if node.nil?
return nil
elsif node.is_a?(SOAPReference)
target = node.__getobj__
# target.id is not Object#id but SOAPReference#id
if referent = Thread.current[:SOAPMapping][:MarshalKey][target.id] and
!Thread.current[:SOAPMapping][:NoReference]
return referent
else
return _soap2obj(target, registry, klass)
end
end
return registry.soap2obj(node, klass)
end
if Object.respond_to?(:allocate)
# ruby/1.7 or later.
def self.create_empty_object(klass)
klass.allocate
end
else
MARSHAL_TAG = {
String => ['"', 1],
Regexp => ['/', 2],
Array => ['[', 1],
Hash => ['{', 1]
}
def self.create_empty_object(klass)
if klass <= Struct
name = klass.name
return ::Marshal.load(sprintf("\004\006S:%c%s\000", name.length + 5, name))
end
if MARSHAL_TAG.has_key?(klass)
tag, terminate = MARSHAL_TAG[klass]
return ::Marshal.load(sprintf("\004\006%s%s", tag, "\000" * terminate))
end
MARSHAL_TAG.each do |k, v|
if klass < k
name = klass.name
tag, terminate = v
return ::Marshal.load(sprintf("\004\006C:%c%s%s%s", name.length + 5, name, tag, "\000" * terminate))
end
end
name = klass.name
::Marshal.load(sprintf("\004\006o:%c%s\000", name.length + 5, name))
end
end
# Allow only (Letter | '_') (Letter | Digit | '-' | '_')* here.
# Caution: '.' is not allowed here.
# To follow XML spec., it should be NCName.
# (denied chars) => .[0-F][0-F]
# ex. a.b => a.2eb
#
def self.name2elename(name)
name.gsub(/([^a-zA-Z0-9:_\-]+)/n) {
'.' << $1.unpack('H2' * $1.size).join('.')
}.gsub(/::/n, '..')
end
def self.elename2name(name)
name.gsub(/\.\./n, '::').gsub(/((?:\.[0-9a-fA-F]{2})+)/n) {
[$1.delete('.')].pack('H*')
}
end
def self.const_from_name(name, lenient = false)
const = ::Object
name.sub(/\A::/, '').split('::').each do |const_str|
if /\A[A-Z]/ =~ const_str
begin
if const.const_defined?(const_str)
const = const.const_get(const_str)
next
end
rescue NameError
end
end
if lenient
const_str = Mapping.safeconstname(const_str)
if const.const_defined?(const_str)
const = const.const_get(const_str)
next
end
end
return nil
end
const
end
def self.class_from_name(name, lenient = false)
unless lenient
const = const_from_name_nonlenient(name)
else
const = const_from_name(name, true)
end
if const.is_a?(::Class)
const
else
nil
end
end
def self.module_from_name(name, lenient = false)
unless lenient
const = const_from_name_nonlenient(name)
else
const = const_from_name(name, true)
end
if const.is_a?(::Module)
const
else
nil
end
end
def self.const_from_name_nonlenient(name)
if Thread.current[:SOAPMapping]
Thread.current[:SOAPMapping][:ConstFromName][name] ||=
const_from_name(name)
else
const_from_name(name)
end
end
def self.class2qname(klass)
name = schema_type_definition(klass)
namespace = schema_ns_definition(klass)
XSD::QName.new(namespace, name)
end
def self.class2element(klass)
name = schema_type_definition(klass) ||
Mapping.name2elename(klass.name)
namespace = schema_ns_definition(klass) || RubyCustomTypeNamespace
XSD::QName.new(namespace, name)
end
def self.obj2element(obj)
name = namespace = nil
ivars = obj.instance_variables
if ivars.include?('@schema_type')
name = obj.instance_variable_get('@schema_type')
end
if ivars.include?('@schema_ns')
namespace = obj.instance_variable_get('@schema_ns')
end
if !name or !namespace
class2qname(obj.class)
else
XSD::QName.new(namespace, name)
end
end
def self.to_qname(obj, ns = nil)
if obj.is_a?(XSD::QName)
obj
else
XSD::QName.new(ns, obj)
end
end
def self.define_singleton_method(obj, name, &block)
sclass = (class << obj; self; end)
sclass.class_eval {
define_method(name, &block)
}
end
def self.get_attributes(obj)
if obj.is_a?(::Hash)
obj
else
rs = {}
obj.instance_variables.each do |ele|
rs[ele.sub(/^@/, '')] = obj.instance_variable_get(ele)
end
rs
end
end
EMPTY_ATTRIBUTES = {}.freeze
def self.get_attributes_for_any(obj)
if obj.respond_to?(:__xmlele_any)
obj.__xmlele_any || EMPTY_ATTRIBUTES
else
get_attributes(obj)
end
end
def self.get_attribute(obj, attr_name)
case obj
when ::SOAP::Mapping::Object
return obj[attr_name]
when ::Hash
return obj[attr_name] || obj[attr_name.intern]
else
if obj.respond_to?(attr_name)
return obj.__send__(attr_name)
end
iv = obj.instance_variables
name = Mapping.safevarname(attr_name)
if iv.include?("@#{name}")
return obj.instance_variable_get("@#{name}")
elsif iv.include?("@#{attr_name}")
return obj.instance_variable_get("@#{attr_name}")
end
if obj.respond_to?(name)
return obj.__send__(name)
end
nil
end
end
def self.set_attributes(obj, values)
case obj
when ::SOAP::Mapping::Object
values.each do |attr_name, value|
obj.__add_xmlele_value(attr_name, value)
end
else
values.each do |attr_name, value|
# untaint depends GenSupport.safevarname
name = Mapping.safevarname(attr_name).untaint
setter = name + "="
if obj.respond_to?(setter)
obj.__send__(setter, value)
else
obj.instance_variable_set('@' + name, value)
begin
unless obj.respond_to?(name)
obj.instance_eval <<-EOS
def #{name}
@#{name}
end
EOS
end
unless self.respond_to?(name + "=")
obj.instance_eval <<-EOS
def #{name}=(value)
@#{name} = value
end
EOS
end
rescue TypeError
# singleton class may not exist (e.g. Float)
end
end
end
end
end
def self.safeconstname(name)
Thread.current[:SOAPMapping][:SafeConstName][name] ||=
XSD::CodeGen::GenSupport.safeconstname(name)
end
def self.safemethodname(name)
Thread.current[:SOAPMapping][:SafeMethodName][name] ||=
XSD::CodeGen::GenSupport.safemethodname(name)
end
def self.safevarname(name)
Thread.current[:SOAPMapping][:SafeVarName][name] ||=
XSD::CodeGen::GenSupport.safevarname(name)
end
def self.root_type_hint
Thread.current[:SOAPMapping][:RootTypeHint]
end
def self.reset_root_type_hint
Thread.current[:SOAPMapping][:RootTypeHint] = false
end
def self.external_ces
Thread.current[:SOAPMapping][:ExternalCES]
end
def self.schema_ns_definition(klass)
class_schema_variable(:schema_ns, klass)
end
def self.schema_name_definition(klass)
class_schema_variable(:schema_name, klass)
end
def self.schema_type_definition(klass)
class_schema_variable(:schema_type, klass)
end
def self.schema_qualified_definition(klass)
class_schema_variable(:schema_qualified, klass)
end
def self.schema_element_definition(klass)
class_schema_variable(:schema_element, klass)
end
def self.schema_attribute_definition(klass)
class_schema_variable(:schema_attribute, klass)
end
def self.schema_definition_classdef(klass)
if Thread.current[:SOAPMapping][:SchemaDefinition].key?(klass)
return Thread.current[:SOAPMapping][:SchemaDefinition][klass]
end
schema_ns = schema_ns_definition(klass)
schema_name = schema_name_definition(klass)
schema_type = schema_type_definition(klass)
qualified = schema_qualified_definition(klass)
elements = schema_element_definition(klass)
attributes = schema_attribute_definition(klass)
return nil if schema_name.nil? and schema_type.nil?
schema_name = Mapping.to_qname(schema_name, schema_ns) if schema_name
schema_type = Mapping.to_qname(schema_type, schema_ns) if schema_type
definition = create_schema_definition(klass,
:schema_name => schema_name,
:schema_type => schema_type,
:is_anonymous => false,
:schema_qualified => qualified,
:schema_element => elements,
:schema_attribute => attributes
)
Thread.current[:SOAPMapping][:SchemaDefinition][klass] = definition
definition
end
def self.create_schema_definition(klass, definition)
schema_ns = definition[:schema_ns]
schema_name = definition[:schema_name]
schema_type = definition[:schema_type]
is_anonymous = definition[:is_anonymous]
schema_basetype = definition[:schema_basetype]
# wrap if needed for backward compatibility
if schema_ns
schema_name = Mapping.to_qname(schema_name, schema_ns) if schema_name
schema_type = Mapping.to_qname(schema_type, schema_ns) if schema_type
# no need for schema_basetype bacause it's introduced later
end
schema_qualified = definition[:schema_qualified]
schema_element = definition[:schema_element]
schema_attributes = definition[:schema_attribute]
definition = SchemaDefinition.new(klass, schema_name, schema_type, is_anonymous, schema_qualified)
definition.basetype = schema_basetype
definition.attributes = schema_attributes
if schema_element
if schema_element.respond_to?(:is_concrete_definition) and
schema_element.is_concrete_definition
definition.elements = schema_element
else
default_ns = schema_name.namespace if schema_name
default_ns ||= schema_type.namespace if schema_type
definition.elements = parse_schema_definition(schema_element, default_ns)
if klass < ::Array
definition.elements.set_array
end
end
end
definition
end
# for backward compatibility
# returns SchemaComplexTypeDefinition
def self.parse_schema_definition(schema_element, default_ns)
definition = nil
if schema_element[0] == :choice
schema_element.shift
definition = SchemaChoiceDefinition.new
else
definition = SchemaSequenceDefinition.new
end
schema_element.each do |ele|
element_definition = parse_schema_element_definition(ele, default_ns)
definition << element_definition
end
definition
end
# returns SchemaElementDefinition
def self.parse_schema_element_definition(schema_element, default_ns)
if schema_element[0] == :choice
parse_schema_definition(schema_element, default_ns)
elsif schema_element[0].is_a?(Array)
parse_schema_definition(schema_element, default_ns)
else
varname, info, occurrence = schema_element
mapped_class_str, elename = info
if occurrence
minoccurs, maxoccurs = occurrence
else
# for backward compatibility
minoccurs, maxoccurs = 1, 1
end
as_any = as_array = false
if /\[\]$/ =~ mapped_class_str
mapped_class_str = mapped_class_str.sub(/\[\]$/, '')
if mapped_class_str.empty?
mapped_class_str = nil
end
as_array = true
end
if mapped_class_str
mapped_class = Mapping.class_from_name(mapped_class_str)
if mapped_class.nil?
warn("cannot find mapped class: #{mapped_class_str}")
end
end
if elename == XSD::AnyTypeName
as_any = true
elsif elename.nil?
elename = XSD::QName.new(default_ns, varname)
end
SchemaElementDefinition.new(
varname, mapped_class, elename, minoccurs, maxoccurs, as_any, as_array)
end
end
class << Mapping
public
def protect_threadvars(*symbols)
backup = {}
begin
symbols.each do |sym|
backup[sym] = Thread.current[sym]
end
yield
ensure
symbols.each do |sym|
Thread.current[sym] = backup[sym]
end
end
end
private
def class_schema_variable(sym, klass)
var = "@@#{sym}"
klass.class_variables.include?(var) ? klass.class_eval(var) : nil
end
def protect_mapping(opt)
protect_threadvars(:SOAPMapping) do
data = Thread.current[:SOAPMapping] = {}
data[:MarshalKey] = {}
data[:ExternalCES] = opt[:external_ces] || XSD::Charset.encoding
data[:NoReference] = opt[:no_reference]
data[:RootTypeHint] = opt[:root_type_hint]
data[:SchemaDefinition] = {}
data[:SafeConstName] = {}
data[:SafeMethodName] = {}
data[:SafeVarName] = {}
data[:ConstFromName] = {}
yield
end
end
def add_md_ary(md_ary, ary, indices, registry)
for idx in 0..(ary.size - 1)
if ary[idx].is_a?(Array)
add_md_ary(md_ary, ary[idx], indices + [idx], registry)
else
md_ary[*(indices + [idx])] = _obj2soap(ary[idx], registry)
end
end
end
end
end
end

View file

@ -0,0 +1,295 @@
# SOAP4R - Mapping registry.
# Copyright (C) 2000-2007 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 'soap/baseData'
require 'soap/mapping/mapping'
module SOAP
module Marshallable
# @@type_ns = Mapping::RubyCustomTypeNamespace
end
module Mapping
module MappedException; end
RubyTypeName = XSD::QName.new(RubyTypeInstanceNamespace, 'rubyType')
RubyExtendName = XSD::QName.new(RubyTypeInstanceNamespace, 'extends')
RubyIVarName = XSD::QName.new(RubyTypeInstanceNamespace, 'ivars')
# For anyType object: SOAP::Mapping::Object not ::Object
class Object
def initialize
@__xmlele_type = {}
@__xmlele = []
@__xmlattr = {}
end
def inspect
sprintf("#<%s:0x%x%s>", self.class.name, __id__,
@__xmlele.collect { |name, value| " #{name}=#{value.inspect}" }.join)
end
def __xmlattr
@__xmlattr
end
def __xmlele
@__xmlele
end
def [](qname)
qname = Mapping.to_qname(qname)
@__xmlele.each do |k, v|
return v if k == qname
end
# fallback
@__xmlele.each do |k, v|
return v if k.name == qname.name
end
nil
end
def []=(qname, value)
qname = Mapping.to_qname(qname)
found = false
@__xmlele.each do |pair|
if pair[0] == qname
found = true
pair[1] = value
end
end
unless found
__define_attr_accessor(qname)
@__xmlele << [qname, value]
end
@__xmlele_type[qname] = :single
end
def __add_xmlele_value(qname, value)
found = false
@__xmlele.map! do |k, v|
if k == qname
found = true
[k, __set_xmlele_value(k, v, value)]
else
[k, v]
end
end
unless found
__define_attr_accessor(qname)
@__xmlele << [qname, value]
@__xmlele_type[qname] = :single
end
value
end
def marshal_load(dumpobj)
__import(dumpobj)
end
private
# Mapping.define_attr_accessor calls define_method with proc and it exhausts
# much memory for each singleton Object. just instance_eval instead of it.
def __define_attr_accessor(qname)
# untaint depends GenSupport.safemethodname
name = Mapping.safemethodname(qname.name).untaint
# untaint depends on QName#dump
qnamedump = qname.dump.untaint
singleton = false
unless self.respond_to?(name)
singleton = true
instance_eval <<-EOS
def #{name}
self[#{qnamedump}]
end
EOS
end
unless self.respond_to?(name + "=")
singleton = true
instance_eval <<-EOS
def #{name}=(value)
self[#{qnamedump}] = value
end
EOS
end
if singleton && !self.respond_to?(:marshal_dump)
instance_eval <<-EOS
def marshal_dump
__export
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
def __export
dumpobj = ::SOAP::Mapping::Object.new
dumpobj.__xmlele.replace(@__xmlele)
dumpobj.__xmlattr.replace(@__xmlattr)
dumpobj
end
def __import(dumpobj)
@__xmlele_type = {}
@__xmlele = []
@__xmlattr = {}
dumpobj.__xmlele.each do |qname, value|
__add_xmlele_value(qname, value)
end
@__xmlattr.replace(dumpobj.__xmlattr)
end
end
class MappingError < Error; end
module RegistrySupport
def initialize
super()
@class_schema_definition = {}
@class_elename_schema_definition = {}
@elename_schema_definition = {}
@type_schema_definition = {}
end
def register(definition)
obj_class = definition[:class]
definition = Mapping.create_schema_definition(obj_class, definition)
# give complexType definition a priority explicitly
if !@class_schema_definition[obj_class] or definition.type
@class_schema_definition[obj_class] = definition
end
if definition.elename and !definition.is_anonymous?
@class_elename_schema_definition[obj_class] = definition
@elename_schema_definition[definition.elename] = definition
end
if definition.type
@type_schema_definition[definition.type] = definition
end
end
def schema_definition_from_class(klass)
@class_schema_definition[klass] || Mapping.schema_definition_classdef(klass)
end
def elename_schema_definition_from_class(klass)
@class_elename_schema_definition[klass]
end
def schema_definition_from_elename(qname)
@elename_schema_definition[qname]
end
def schema_definition_from_type(type)
@type_schema_definition[type]
end
def find_node_definition(node)
schema_definition_from_type(node.type) ||
schema_definition_from_elename(node.elename) ||
find_schema_definition(node.elename.name) ||
find_schema_definition(node.type.name)
end
def find_schema_definition(name)
return nil unless name
typestr = Mapping.safeconstname(name)
obj_class = Mapping.class_from_name(typestr)
if obj_class
schema_definition_from_class(obj_class)
end
end
def add_attributes2soap(obj, ele)
if definition = Mapping.schema_definition_classdef(obj.class)
add_definedattributes2soap(obj, ele, definition)
elsif obj.respond_to?(:__xmlattr)
obj.__xmlattr.each do |key, value|
ele.extraattr[key] = value
end
end
end
def add_definedattributes2soap(obj, ele, typedef)
if typedef.attributes
typedef.attributes.each do |qname, param|
value = get_xmlattr_value(obj, qname)
ele.extraattr[qname] = value unless value.nil?
end
end
end
def get_xmlattr_value(obj, qname)
attrname = 'xmlattr_' + qname.name
value = Mapping.get_attribute(obj, attrname)
if value.nil?
attrname = Mapping.safemethodname('xmlattr_' + qname.name)
value = Mapping.get_attribute(obj, attrname)
end
value
end
def base2soap(obj, type, qualified = nil)
return SOAPNil.new if obj.nil?
soap_obj = nil
if type <= XSD::XSDString
str = XSD::Charset.encoding_conv(obj.to_s, Mapping.external_ces,
XSD::Charset.encoding)
soap_obj = type.new(str)
else
soap_obj = type.new(obj)
end
soap_obj.qualified = qualified
soap_obj
end
def base2obj(value, klass)
v = if value.respond_to?(:data)
value.data
elsif value.respond_to?(:text)
value.text
else
nil
end
if value.is_a?(klass)
v
else
klass.to_data(v)
end
end
def is_stubobj_elements_for_array(vars)
vars.keys.size == 1 and vars.values[0].is_a?(::Array)
end
end
end
end

View file

@ -0,0 +1,478 @@
# SOAP4R - Ruby type mapping factory.
# Copyright (C) 2000-2007 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.
module SOAP
module Mapping
class RubytypeFactory < Factory
TYPE_STRING = XSD::QName.new(RubyTypeNamespace, 'String')
TYPE_TIME = XSD::QName.new(RubyTypeNamespace, 'Time')
TYPE_ARRAY = XSD::QName.new(RubyTypeNamespace, 'Array')
TYPE_REGEXP = XSD::QName.new(RubyTypeNamespace, 'Regexp')
TYPE_RANGE = XSD::QName.new(RubyTypeNamespace, 'Range')
TYPE_CLASS = XSD::QName.new(RubyTypeNamespace, 'Class')
TYPE_MODULE = XSD::QName.new(RubyTypeNamespace, 'Module')
TYPE_SYMBOL = XSD::QName.new(RubyTypeNamespace, 'Symbol')
TYPE_STRUCT = XSD::QName.new(RubyTypeNamespace, 'Struct')
TYPE_HASH = XSD::QName.new(RubyTypeNamespace, 'Map')
def initialize(config = {})
@config = config
@allow_untyped_struct = @config.key?(:allow_untyped_struct) ?
@config[:allow_untyped_struct] : true
@allow_original_mapping = @config.key?(:allow_original_mapping) ?
@config[:allow_original_mapping] : false
@string_factory = StringFactory_.new(true)
@basetype_factory = BasetypeFactory_.new(true)
@datetime_factory = DateTimeFactory_.new(true)
@array_factory = ArrayFactory_.new(true)
@hash_factory = HashFactory_.new(true)
end
def obj2soap(soap_class, obj, info, map)
param = nil
case obj
when ::String
unless @allow_original_mapping
return nil
end
param = @string_factory.obj2soap(SOAPString, obj, info, map)
if obj.class != String
param.extraattr[RubyTypeName] = obj.class.name
end
addiv2soapattr(param, obj, map)
when ::Time
unless @allow_original_mapping
return nil
end
param = @datetime_factory.obj2soap(SOAPDateTime, obj, info, map)
if obj.class != Time
param.extraattr[RubyTypeName] = obj.class.name
end
addiv2soapattr(param, obj, map)
when ::Array
unless @allow_original_mapping
return nil
end
param = @array_factory.obj2soap(nil, obj, info, map)
if obj.class != Array
param.extraattr[RubyTypeName] = obj.class.name
end
addiv2soapattr(param, obj, map)
when ::NilClass
unless @allow_original_mapping
return nil
end
param = @basetype_factory.obj2soap(SOAPNil, obj, info, map)
addiv2soapattr(param, obj, map)
when ::FalseClass, ::TrueClass
unless @allow_original_mapping
return nil
end
param = @basetype_factory.obj2soap(SOAPBoolean, obj, info, map)
addiv2soapattr(param, obj, map)
when ::Integer
unless @allow_original_mapping
return nil
end
param = @basetype_factory.obj2soap(SOAPInt, obj, info, map)
param ||= @basetype_factory.obj2soap(SOAPInteger, obj, info, map)
param ||= @basetype_factory.obj2soap(SOAPDecimal, obj, info, map)
addiv2soapattr(param, obj, map)
when ::Float
unless @allow_original_mapping
return nil
end
param = @basetype_factory.obj2soap(SOAPDouble, obj, info, map)
if obj.class != Float
param.extraattr[RubyTypeName] = obj.class.name
end
addiv2soapattr(param, obj, map)
when ::Hash
unless @allow_original_mapping
return nil
end
if obj.respond_to?(:default_proc) && obj.default_proc
raise TypeError.new("cannot dump hash with default proc")
end
param = SOAPStruct.new(TYPE_HASH)
mark_marshalled_obj(obj, param)
if obj.class != Hash
param.extraattr[RubyTypeName] = obj.class.name
end
obj.each do |key, value|
elem = SOAPStruct.new # Undefined type.
elem.add("key", Mapping._obj2soap(key, map))
elem.add("value", Mapping._obj2soap(value, map))
param.add("item", elem)
end
param.add('default', Mapping._obj2soap(obj.default, map))
addiv2soapattr(param, obj, map)
when ::Regexp
unless @allow_original_mapping
return nil
end
param = SOAPStruct.new(TYPE_REGEXP)
mark_marshalled_obj(obj, param)
if obj.class != Regexp
param.extraattr[RubyTypeName] = obj.class.name
end
param.add('source', SOAPBase64.new(obj.source))
if obj.respond_to?('options')
# Regexp#options is from Ruby/1.7
options = obj.options
else
options = 0
obj.inspect.sub(/^.*\//, '').each_byte do |c|
options += case c
when ?i
1
when ?x
2
when ?m
4
when ?n
16
when ?e
32
when ?s
48
when ?u
64
end
end
end
param.add('options', SOAPInt.new(options))
addiv2soapattr(param, obj, map)
when ::Range
unless @allow_original_mapping
return nil
end
param = SOAPStruct.new(TYPE_RANGE)
mark_marshalled_obj(obj, param)
if obj.class != Range
param.extraattr[RubyTypeName] = obj.class.name
end
param.add('begin', Mapping._obj2soap(obj.begin, map))
param.add('end', Mapping._obj2soap(obj.end, map))
param.add('exclude_end', SOAP::SOAPBoolean.new(obj.exclude_end?))
addiv2soapattr(param, obj, map)
when ::Class
unless @allow_original_mapping
return nil
end
if obj.to_s[0] == ?#
raise TypeError.new("can't dump anonymous class #{obj}")
end
param = SOAPStruct.new(TYPE_CLASS)
mark_marshalled_obj(obj, param)
param.add('name', SOAPString.new(obj.name))
addiv2soapattr(param, obj, map)
when ::Module
unless @allow_original_mapping
return nil
end
if obj.to_s[0] == ?#
raise TypeError.new("can't dump anonymous module #{obj}")
end
param = SOAPStruct.new(TYPE_MODULE)
mark_marshalled_obj(obj, param)
param.add('name', SOAPString.new(obj.name))
addiv2soapattr(param, obj, map)
when ::Symbol
unless @allow_original_mapping
return nil
end
param = SOAPStruct.new(TYPE_SYMBOL)
mark_marshalled_obj(obj, param)
param.add('id', SOAPString.new(obj.id2name))
addiv2soapattr(param, obj, map)
when ::Struct
unless @allow_original_mapping
# treat it as an user defined class. [ruby-talk:104980]
#param = unknownobj2soap(soap_class, obj, info, map)
param = SOAPStruct.new(XSD::AnyTypeName)
mark_marshalled_obj(obj, param)
obj.members.each do |member|
param.add(Mapping.name2elename(member),
Mapping._obj2soap(obj[member], map))
end
else
param = SOAPStruct.new(TYPE_STRUCT)
mark_marshalled_obj(obj, param)
param.add('type', ele_type = SOAPString.new(obj.class.to_s))
ele_member = SOAPStruct.new
obj.members.each do |member|
ele_member.add(Mapping.name2elename(member),
Mapping._obj2soap(obj[member], map))
end
param.add('member', ele_member)
addiv2soapattr(param, obj, map)
end
when ::IO, ::Binding, ::Continuation, ::Data, ::Dir, ::File::Stat,
::MatchData, Method, ::Proc, ::Thread, ::ThreadGroup
# from 1.8: Process::Status, UnboundMethod
return nil
when ::SOAP::Mapping::Object
param = SOAPStruct.new(XSD::AnyTypeName)
mark_marshalled_obj(obj, param)
obj.__xmlele.each do |key, value|
param.add(key.name, Mapping._obj2soap(value, map))
end
obj.__xmlattr.each do |key, value|
param.extraattr[key] = value
end
when ::Exception
typestr = Mapping.name2elename(obj.class.to_s)
param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, typestr))
mark_marshalled_obj(obj, param)
param.add('message', Mapping._obj2soap(obj.message, map))
param.add('backtrace', Mapping._obj2soap(obj.backtrace, map))
addiv2soapattr(param, obj, map)
else
param = unknownobj2soap(soap_class, obj, info, map)
end
param
end
def soap2obj(obj_class, node, info, map)
rubytype = node.extraattr[RubyTypeName]
if rubytype or node.type.namespace == RubyTypeNamespace
rubytype2obj(node, info, map, rubytype)
elsif node.type == XSD::AnyTypeName or node.type == XSD::AnySimpleTypeName
anytype2obj(node, info, map)
else
unknowntype2obj(node, info, map)
end
end
private
def addiv2soapattr(node, obj, map)
return if obj.instance_variables.empty?
ivars = SOAPStruct.new # Undefined type.
setiv2soap(ivars, obj, map)
node.extraattr[RubyIVarName] = ivars
end
def unknownobj2soap(soap_class, obj, info, map)
if 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}")
end
if !(singleton_class.ancestors - obj.class.ancestors).empty?
typestr = Mapping.name2elename(obj.class.to_s)
type = XSD::QName.new(RubyTypeNamespace, typestr)
else
type = Mapping.class2element(obj.class)
end
param = SOAPStruct.new(type)
mark_marshalled_obj(obj, param)
setiv2soap(param, obj, map)
param
end
if RUBY_VERSION >= '1.8.0'
def singleton_methods_true(obj)
obj.singleton_methods(true)
end
else
def singleton_methods_true(obj)
obj.singleton_methods
end
end
def rubytype2obj(node, info, map, rubytype)
klass = rubytype ? Mapping.class_from_name(rubytype) : nil
obj = nil
case node
when SOAPString
return @string_factory.soap2obj(klass || String, node, info, map)
when SOAPDateTime
#return @datetime_factory.soap2obj(klass || Time, node, info, map)
klass ||= Time
t = node.to_time
arg = [t.year, t.month, t.mday, t.hour, t.min, t.sec, t.usec]
obj = t.gmt? ? klass.gm(*arg) : klass.local(*arg)
mark_unmarshalled_obj(node, obj)
return true, obj
when SOAPArray
return @array_factory.soap2obj(klass || Array, node, info, map)
when SOAPNil, SOAPBoolean, SOAPInt, SOAPInteger, SOAPDecimal, SOAPDouble
return @basetype_factory.soap2obj(nil, node, info, map)
when SOAPStruct
return rubytypestruct2obj(node, info, map, rubytype)
else
raise
end
end
def rubytypestruct2obj(node, info, map, rubytype)
klass = rubytype ? Mapping.class_from_name(rubytype) : nil
obj = nil
case node.type
when TYPE_HASH
klass = rubytype ? Mapping.class_from_name(rubytype) : Hash
obj = Mapping.create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
node.each do |key, value|
next unless key == 'item'
obj[Mapping._soap2obj(value['key'], map)] =
Mapping._soap2obj(value['value'], map)
end
if node.key?('default')
obj.default = Mapping._soap2obj(node['default'], map)
end
when TYPE_REGEXP
klass = rubytype ? Mapping.class_from_name(rubytype) : Regexp
obj = Mapping.create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
source = node['source'].string
options = node['options'].data || 0
Regexp.instance_method(:initialize).bind(obj).call(source, options)
when TYPE_RANGE
klass = rubytype ? Mapping.class_from_name(rubytype) : Range
obj = Mapping.create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
first = Mapping._soap2obj(node['begin'], map)
last = Mapping._soap2obj(node['end'], map)
exclude_end = node['exclude_end'].data
Range.instance_method(:initialize).bind(obj).call(first, last, exclude_end)
when TYPE_CLASS
obj = Mapping.class_from_name(node['name'].data)
when TYPE_MODULE
obj = Mapping.class_from_name(node['name'].data)
when TYPE_SYMBOL
obj = node['id'].data.intern
when TYPE_STRUCT
typestr = Mapping.elename2name(node['type'].data)
klass = Mapping.class_from_name(typestr)
if klass.nil?
return false
end
unless klass <= ::Struct
return false
end
obj = Mapping.create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
node['member'].each do |name, value|
obj[Mapping.elename2name(name)] = Mapping._soap2obj(value, map)
end
else
return unknowntype2obj(node, info, map)
end
return true, obj
end
def anytype2obj(node, info, map)
case node
when SOAPBasetype
return true, node.data
when SOAPStruct
klass = ::SOAP::Mapping::Object
obj = klass.new
mark_unmarshalled_obj(node, obj)
node.each do |name, value|
obj.__add_xmlele_value(XSD::QName.new(nil, name),
Mapping._soap2obj(value, map))
end
unless node.extraattr.empty?
obj.instance_variable_set('@__xmlattr', node.extraattr)
end
return true, obj
else
return false
end
end
def unknowntype2obj(node, info, map)
case node
when SOAPBasetype
return true, node.data
when SOAPArray
return @array_factory.soap2obj(Array, node, info, map)
when SOAPStruct
obj = unknownstruct2obj(node, info, map)
return true, obj if obj
if !@allow_untyped_struct
return false
end
return anytype2obj(node, info, map)
else
# Basetype which is not defined...
return false
end
end
def unknownstruct2obj(node, info, map)
unless node.type.name
return nil
end
typestr = Mapping.elename2name(node.type.name)
klass = Mapping.class_from_name(typestr)
if klass.respond_to?(:soap_marshallable) and !klass.soap_marshallable
return nil
end
if klass.nil? and @allow_untyped_struct
klass = Mapping.class_from_name(typestr, true) # lenient
end
if klass.nil?
return nil
end
if klass <= ::Exception
return exception2obj(klass, node, map)
end
klass_type = Mapping.class2qname(klass)
return nil unless node.type.match(klass_type)
obj = nil
begin
obj = Mapping.create_empty_object(klass)
rescue
# type name "data" tries Data.new which raises TypeError
nil
end
mark_unmarshalled_obj(node, obj)
setiv2obj(obj, node, map)
obj
end
def exception2obj(klass, node, map)
message = Mapping._soap2obj(node['message'], map)
backtrace = Mapping._soap2obj(node['backtrace'], map)
obj = Mapping.create_empty_object(klass)
obj = obj.exception(message)
mark_unmarshalled_obj(node, obj)
obj.set_backtrace(backtrace)
obj
end
# Only creates empty array. Do String#replace it with real string.
def array2obj(node, map, rubytype)
klass = rubytype ? Mapping.class_from_name(rubytype) : Array
obj = Mapping.create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
obj
end
# Only creates empty string. Do String#replace it with real string.
def string2obj(node, map, rubytype)
klass = rubytype ? Mapping.class_from_name(rubytype) : String
obj = Mapping.create_empty_object(klass)
mark_unmarshalled_obj(node, obj)
obj
end
end
end
end

View file

@ -0,0 +1,170 @@
# SOAP4R - Ruby type mapping schema definition utility.
# Copyright (C) 2000-2007 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/codegen/gensupport'
module SOAP
module Mapping
class SchemaElementDefinition
attr_reader :varname, :mapped_class, :elename, :minoccurs, :maxoccurs
def initialize(varname, mapped_class, elename, minoccurs, maxoccurs,
as_any, as_array)
@varname = varname
@mapped_class = mapped_class
@elename = elename
@minoccurs = minoccurs
@maxoccurs = maxoccurs
@as_any = as_any
@as_array = as_array
end
def as_any?
@as_any
end
def as_array?
@as_array
end
end
module SchemaComplexTypeDefinition
include Enumerable
def initialize
@content = []
@element_cache = {}
end
def is_concrete_definition
true
end
def <<(ele)
@content << ele
end
def each
@content.each do |ele|
yield ele
end
end
def size
@content.size
end
def as_any?
false
end
def as_array?
false
end
def find_element(qname)
@element_cache[qname] ||= search_element(qname)
end
private
def search_element(qname)
each do |ele|
if ele.respond_to?(:find_element)
found = ele.find_element(qname)
return found if found
else
# relaxed match
if ele.elename == qname or
(qname.namespace.nil? and ele.elename.name == qname.name)
return ele
end
end
end
nil
end
end
class SchemaEmptyDefinition
include SchemaComplexTypeDefinition
def initialize
super()
@content.freeze
end
end
class SchemaSequenceDefinition
include SchemaComplexTypeDefinition
def initialize
super()
end
def choice?
false
end
# override
def as_array?
@as_array ||= false
end
def set_array
@as_array = true
end
end
class SchemaChoiceDefinition
include SchemaComplexTypeDefinition
def initialize
super()
end
def choice?
true
end
end
class SchemaDefinition
EMPTY = SchemaEmptyDefinition.new
attr_reader :class_for
attr_reader :elename, :type
attr_reader :qualified
attr_accessor :basetype
attr_accessor :attributes
attr_accessor :elements
def initialize(class_for, elename, type, anonymous, qualified)
@class_for = class_for
@elename = elename
@type = type
@anonymous = anonymous
@qualified = qualified
@basetype = nil
@elements = EMPTY
@attributes = nil
end
def is_anonymous?
@anonymous
end
def choice?
@elements.choice?
end
end
end
end

View file

@ -0,0 +1,106 @@
# SOAP4R - Base type mapping definition
# Copyright (C) 2000-2007 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.
module SOAP
TypeMap = {
XSD::XSDAnySimpleType::Type => SOAPAnySimpleType,
XSD::XSDString::Type => SOAPString,
XSD::XSDNormalizedString::Type => SOAPNormalizedString,
XSD::XSDToken::Type => SOAPToken,
XSD::XSDLanguage::Type => SOAPLanguage,
XSD::XSDNMTOKEN::Type => SOAPNMTOKEN,
XSD::XSDNMTOKENS::Type => SOAPNMTOKENS,
XSD::XSDName::Type => SOAPName,
XSD::XSDNCName::Type => SOAPNCName,
XSD::XSDID::Type => SOAPID,
XSD::XSDIDREF::Type => SOAPIDREF,
XSD::XSDIDREFS::Type => SOAPIDREFS,
XSD::XSDENTITY::Type => SOAPENTITY,
XSD::XSDENTITIES::Type => SOAPENTITIES,
XSD::XSDBoolean::Type => SOAPBoolean,
XSD::XSDDecimal::Type => SOAPDecimal,
XSD::XSDFloat::Type => SOAPFloat,
XSD::XSDDouble::Type => SOAPDouble,
XSD::XSDDuration::Type => SOAPDuration,
XSD::XSDDateTime::Type => SOAPDateTime,
XSD::XSDTime::Type => SOAPTime,
XSD::XSDDate::Type => SOAPDate,
XSD::XSDGYearMonth::Type => SOAPGYearMonth,
XSD::XSDGYear::Type => SOAPGYear,
XSD::XSDGMonthDay::Type => SOAPGMonthDay,
XSD::XSDGDay::Type => SOAPGDay,
XSD::XSDGMonth::Type => SOAPGMonth,
XSD::XSDHexBinary::Type => SOAPHexBinary,
XSD::XSDBase64Binary::Type => SOAPBase64,
XSD::XSDAnyURI::Type => SOAPAnyURI,
XSD::XSDQName::Type => SOAPQName,
XSD::XSDInteger::Type => SOAPInteger,
XSD::XSDNonPositiveInteger::Type => SOAPNonPositiveInteger,
XSD::XSDNegativeInteger::Type => SOAPNegativeInteger,
XSD::XSDLong::Type => SOAPLong,
XSD::XSDInt::Type => SOAPInt,
XSD::XSDShort::Type => SOAPShort,
XSD::XSDByte::Type => SOAPByte,
XSD::XSDNonNegativeInteger::Type => SOAPNonNegativeInteger,
XSD::XSDUnsignedLong::Type => SOAPUnsignedLong,
XSD::XSDUnsignedInt::Type => SOAPUnsignedInt,
XSD::XSDUnsignedShort::Type => SOAPUnsignedShort,
XSD::XSDUnsignedByte::Type => SOAPUnsignedByte,
XSD::XSDPositiveInteger::Type => SOAPPositiveInteger,
# soap4r does not use soapenc types actively but it should be accepted.
SOAP::SOAPString::SOAPENCType => SOAPString,
SOAP::SOAPNormalizedString::Type => SOAPNormalizedString,
SOAP::SOAPToken::Type => SOAPToken,
SOAP::SOAPLanguage::Type => SOAPLanguage,
SOAP::SOAPNMTOKEN::Type => SOAPNMTOKEN,
SOAP::SOAPNMTOKENS::Type => SOAPNMTOKENS,
SOAP::SOAPName::Type => SOAPName,
SOAP::SOAPNCName::Type => SOAPNCName,
SOAP::SOAPID::Type => SOAPID,
SOAP::SOAPIDREF::Type => SOAPIDREF,
SOAP::SOAPIDREFS::Type => SOAPIDREFS,
SOAP::SOAPENTITY::Type => SOAPENTITY,
SOAP::SOAPENTITIES::Type => SOAPENTITIES,
SOAP::SOAPBoolean::SOAPENCType => SOAPBoolean,
SOAP::SOAPDecimal::SOAPENCType => SOAPDecimal,
SOAP::SOAPFloat::SOAPENCType => SOAPFloat,
SOAP::SOAPDouble::SOAPENCType => SOAPDouble,
SOAP::SOAPDuration::SOAPENCType => SOAPDuration,
SOAP::SOAPDateTime::SOAPENCType => SOAPDateTime,
SOAP::SOAPTime::SOAPENCType => SOAPTime,
SOAP::SOAPDate::SOAPENCType => SOAPDate,
SOAP::SOAPGYearMonth::SOAPENCType => SOAPGYearMonth,
SOAP::SOAPGYear::SOAPENCType => SOAPGYear,
SOAP::SOAPGMonthDay::SOAPENCType => SOAPGMonthDay,
SOAP::SOAPGDay::SOAPENCType => SOAPGDay,
SOAP::SOAPGMonth::SOAPENCType => SOAPGMonth,
SOAP::SOAPHexBinary::SOAPENCType => SOAPHexBinary,
SOAP::SOAPBase64::SOAPENCType => SOAPBase64,
SOAP::SOAPAnyURI::SOAPENCType => SOAPAnyURI,
SOAP::SOAPQName::SOAPENCType => SOAPQName,
SOAP::SOAPInteger::SOAPENCType => SOAPInteger,
SOAP::SOAPNonPositiveInteger::SOAPENCType => SOAPNonPositiveInteger,
SOAP::SOAPNegativeInteger::SOAPENCType => SOAPNegativeInteger,
SOAP::SOAPLong::SOAPENCType => SOAPLong,
SOAP::SOAPInt::SOAPENCType => SOAPInt,
SOAP::SOAPShort::SOAPENCType => SOAPShort,
SOAP::SOAPByte::SOAPENCType => SOAPByte,
SOAP::SOAPNonNegativeInteger::SOAPENCType => SOAPNonNegativeInteger,
SOAP::SOAPUnsignedLong::SOAPENCType => SOAPUnsignedLong,
SOAP::SOAPUnsignedInt::SOAPENCType => SOAPUnsignedInt,
SOAP::SOAPUnsignedShort::SOAPENCType => SOAPUnsignedShort,
SOAP::SOAPUnsignedByte::SOAPENCType => SOAPUnsignedByte,
SOAP::SOAPPositiveInteger::SOAPENCType => SOAPPositiveInteger,
}
end

View file

@ -0,0 +1,211 @@
# SOAP4R - WSDL encoded mapping registry.
# Copyright (C) 2000-2007 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'
module SOAP
module Mapping
class WSDLEncodedRegistry < EncodedRegistry
attr_reader :definedelements
attr_reader :definedtypes
def initialize(definedtypes = XSD::NamedElements::Empty)
super()
@definedtypes = definedtypes
# @definedelements = definedelements needed?
# For mapping AnyType element.
@rubytype_factory = RubytypeFactory.new(
:allow_untyped_struct => true,
:allow_original_mapping => true
)
end
def obj2soap(obj, qname = nil)
soap_obj = nil
if type = @definedtypes[qname]
soap_obj = obj2typesoap(obj, type)
else
soap_obj = any2soap(obj, qname)
end
return soap_obj if soap_obj
if @excn_handler_obj2soap
soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj|
Mapping._obj2soap(yield_obj, self)
}
return soap_obj if soap_obj
end
if qname
raise MappingError.new("cannot map #{obj.class.name} as #{qname}")
else
raise MappingError.new("cannot map #{obj.class.name} to SOAP/OM")
end
end
# map anything for now: must refer WSDL while mapping. [ToDo]
def soap2obj(node, obj_class = nil)
cause = nil
begin
unless obj_class
typestr = Mapping.safeconstname(node.elename.name)
obj_class = Mapping.class_from_name(typestr)
end
return Mapping._soap2obj(node, Mapping::DefaultRegistry, obj_class)
rescue MappingError
cause = $!
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", cause)
end
private
def any2soap(obj, qname)
ele = nil
if obj.nil?
ele = SOAPNil.new
elsif qname.nil? or qname == XSD::AnyTypeName
ele = @rubytype_factory.obj2soap(nil, obj, nil, self)
elsif obj.is_a?(XSD::NSDBase)
ele = soap2soap(obj, qname)
elsif type = TypeMap[qname]
ele = base2soap(obj, type)
end
add_attributes2soap(obj, ele) unless ele.nil?
ele
end
def soap2soap(obj, type_qname)
if obj.is_a?(SOAPBasetype)
obj
elsif obj.is_a?(SOAPStruct) && (type = @definedtypes[type_qname])
soap_obj = obj
mark_marshalled_obj(obj, soap_obj)
elements2soap(obj, soap_obj, type.elements)
soap_obj
elsif obj.is_a?(SOAPArray) && (type = @definedtypes[type_qname])
soap_obj = obj
contenttype = type.child_type
mark_marshalled_obj(obj, soap_obj)
obj.replace do |ele|
Mapping._obj2soap(ele, self, contenttype)
end
soap_obj
else
nil
end
end
def obj2typesoap(obj, type)
if type.is_a?(::WSDL::XMLSchema::SimpleType)
simpleobj2soap(obj, type)
else
complexobj2soap(obj, type)
end
end
def simpleobj2soap(obj, type)
type.check_lexical_format(obj)
return SOAPNil.new if obj.nil? # TODO: check nillable.
if type.base
ele = base2soap(obj, TypeMap[type.base])
ele.type = type.name
elsif type.list
value = obj.is_a?(Array) ? obj.join(" ") : obj.to_s
ele = base2soap(value, SOAP::SOAPString)
else
raise MappingError.new("unsupported simpleType: #{type}")
end
ele
end
def complexobj2soap(obj, type)
case type.compoundtype
when :TYPE_STRUCT
struct2soap(obj, type.name, type)
when :TYPE_ARRAY
array2soap(obj, type.name, type)
when :TYPE_MAP
map2soap(obj, type.name, type)
when :TYPE_SIMPLE
simpleobj2soap(obj, type.simplecontent)
when :TYPE_EMPTY
raise MappingError.new("should be empty") unless obj.nil?
SOAPNil.new
else
raise MappingError.new("unknown compound type: #{type.compoundtype}")
end
end
def struct2soap(obj, type_qname, type)
return SOAPNil.new if obj.nil? # ToDo: check nillable.
soap_obj = SOAPStruct.new(type_qname)
mark_marshalled_obj(obj, soap_obj)
elements2soap(obj, soap_obj, type.elements)
soap_obj
end
def array2soap(obj, type_qname, type)
return SOAPNil.new if obj.nil? # ToDo: check nillable.
arytype = type.child_type
soap_obj = SOAPArray.new(ValueArrayName, 1, arytype)
unless obj.nil?
mark_marshalled_obj(obj, soap_obj)
obj.each do |item|
soap_obj.add(Mapping._obj2soap(item, self, arytype))
end
end
soap_obj
end
MapKeyName = XSD::QName.new(nil, "key")
MapValueName = XSD::QName.new(nil, "value")
def map2soap(obj, type_qname, type)
return SOAPNil.new if obj.nil? # ToDo: check nillable.
keytype = type.child_type(MapKeyName) || XSD::AnyTypeName
valuetype = type.child_type(MapValueName) || XSD::AnyTypeName
soap_obj = SOAPStruct.new(MapQName)
unless obj.nil?
mark_marshalled_obj(obj, soap_obj)
obj.each do |key, value|
elem = SOAPStruct.new
elem.add("key", Mapping._obj2soap(key, self, keytype))
elem.add("value", Mapping._obj2soap(value, self, valuetype))
# ApacheAxis allows only 'item' here.
soap_obj.add("item", elem)
end
end
soap_obj
end
def elements2soap(obj, soap_obj, elements)
elements.each do |element|
name = element.name.name
child_obj = Mapping.get_attribute(obj, name)
soap_obj.add(name,
Mapping._obj2soap(child_obj, self, element.type || element.name))
end
end
end
end
end

View file

@ -0,0 +1,243 @@
# SOAP4R - WSDL literal mapping registry.
# Copyright (C) 2000-2007 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 'soap/baseData'
require 'soap/mapping/mapping'
require 'soap/mapping/literalregistry'
require 'soap/mapping/typeMap'
require 'xsd/codegen/gensupport'
require 'xsd/namedelements'
module SOAP
module Mapping
class WSDLLiteralRegistry < LiteralRegistry
attr_reader :definedelements
attr_reader :definedtypes
def initialize(definedtypes = XSD::NamedElements::Empty,
definedelements = XSD::NamedElements::Empty)
super()
@definedtypes = definedtypes
@definedelements = definedelements
end
def obj2soap(obj, qname, obj_class = nil)
soap_obj = nil
if obj.is_a?(SOAPElement)
soap_obj = obj
elsif eledef = @definedelements[qname]
soap_obj = obj2elesoap(obj, eledef)
elsif type = @definedtypes[qname]
soap_obj = obj2typesoap(obj, type)
else
soap_obj = any2soap(obj, qname, obj_class)
end
return soap_obj if soap_obj
if @excn_handler_obj2soap
soap_obj = @excn_handler_obj2soap.call(obj) { |yield_obj|
Mapping.obj2soap(yield_obj, nil, nil, MAPPING_OPT)
}
return soap_obj if soap_obj
end
raise MappingError.new("cannot map #{obj.class.name} as #{qname}")
end
# node should be a SOAPElement
def soap2obj(node, obj_class = nil)
cause = nil
begin
return any2obj(node, obj_class)
rescue MappingError
cause = $!
end
if @excn_handler_soap2obj
begin
return @excn_handler_soap2obj.call(node) { |yield_node|
Mapping.soap2obj(yield_node, nil, nil, MAPPING_OPT)
}
rescue Exception
end
end
if node.respond_to?(:type)
raise MappingError.new("cannot map #{node.type.name} to Ruby object", cause)
else
raise MappingError.new("cannot map #{node.elename.name} to Ruby object", cause)
end
end
private
def obj2elesoap(obj, eledef)
ele = nil
qualified = (eledef.elementform == 'qualified')
if obj.is_a?(SOAPNil)
ele = obj
elsif eledef.type
if type = @definedtypes[eledef.type]
ele = obj2typesoap(obj, type)
elsif type = TypeMap[eledef.type]
ele = base2soap(obj, type)
else
raise MappingError.new("cannot find type #{eledef.type}")
end
elsif eledef.local_complextype
ele = obj2typesoap(obj, eledef.local_complextype)
elsif eledef.local_simpletype
ele = obj2typesoap(obj, eledef.local_simpletype)
else
raise MappingError.new('illegal schema?')
end
ele.elename = eledef.name
ele.qualified = qualified
ele
end
def obj2typesoap(obj, type)
ele = nil
if type.is_a?(::WSDL::XMLSchema::SimpleType)
ele = simpleobj2soap(obj, type)
else # complexType
if type.simplecontent
ele = simpleobj2soap(obj, type.simplecontent)
else
ele = complexobj2soap(obj, type)
end
add_definedattributes2soap(obj, ele, type)
end
ele
end
def simpleobj2soap(obj, type)
type.check_lexical_format(obj)
return SOAPNil.new if obj.nil?
if type.base
ele = base2soap(obj, TypeMap[type.base])
elsif type.list
value = obj.is_a?(Array) ? obj.join(" ") : obj.to_s
ele = base2soap(value, SOAP::SOAPString)
else
raise MappingError.new("unsupported simpleType: #{type}")
end
ele
end
def complexobj2soap(obj, type)
ele = SOAPElement.new(type.name)
complexobj2sequencesoap(obj, ele, type, type.choice?, type.choice?)
ele
end
def complexobj2sequencesoap(obj, soap, type, nillable, is_choice)
added = false
type.elements.each do |child_ele|
case child_ele
when WSDL::XMLSchema::Any
any = Mapping.get_attributes_for_any(obj)
SOAPElement.from_objs(any).each do |child|
soap.add(child)
end
ele_added = true
when WSDL::XMLSchema::Element
ele_added = complexobj2soapchildren(obj, soap, child_ele, nillable)
when WSDL::XMLSchema::Sequence
ele_added = complexobj2sequencesoap(obj, soap, child_ele, nillable, false)
when WSDL::XMLSchema::Choice
ele_added = complexobj2sequencesoap(obj, soap, child_ele, true, true)
else
raise MappingError.new("unknown type: #{child_ele}")
end
added = true if ele_added
break if is_choice and ele_added
end
added
end
def complexobj2soapchildren(obj, soap, child_ele, nillable = false)
if child_ele.map_as_array?
complexobj2soapchildren_array(obj, soap, child_ele, nillable)
else
complexobj2soapchildren_single(obj, soap, child_ele, nillable)
end
end
def complexobj2soapchildren_array(obj, soap, child_ele, nillable)
child = Mapping.get_attribute(obj, child_ele.name.name)
if child.nil? and obj.is_a?(::Array)
child = obj
end
if child.nil?
return false if nillable
if child_soap = nil2soap(child_ele)
soap.add(child_soap)
return true
else
return false
end
end
unless child.respond_to?(:each)
return false
end
child.each do |item|
if item.is_a?(SOAPElement)
soap.add(item)
else
child_soap = obj2elesoap(item, child_ele)
soap.add(child_soap)
end
end
true
end
def complexobj2soapchildren_single(obj, soap, child_ele, nillable)
child = Mapping.get_attribute(obj, child_ele.name.name)
case child
when NilClass
return false if nillable
if child_soap = nil2soap(child_ele)
soap.add(child_soap)
true
else
false
end
when SOAPElement
soap.add(child)
true
else
child_soap = obj2elesoap(child, child_ele)
soap.add(child_soap)
true
end
end
def nil2soap(ele)
if ele.nillable
obj2elesoap(nil, ele) # add an empty element
elsif ele.minoccurs == 0
nil # intends no element
else
warn("nil not allowed: #{ele.name.name}")
nil
end
end
def add_definedattributes2soap(obj, ele, typedef)
if typedef.attributes
typedef.attributes.each do |at|
value = get_xmlattr_value(obj, at.name)
ele.extraattr[at.name] = value unless value.nil?
end
end
end
end
end
end

View file

@ -0,0 +1,9 @@
# SOAP4R - RPC utility -- Mapping registry.
# Copyright (C) 2000-2007 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 'soap/compat'

View file

@ -0,0 +1,59 @@
# SOAP4R - Marshalling/Unmarshalling Ruby's object using SOAP Encoding.
# Copyright (C) 2000-2007 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 "soap/mapping"
require "soap/processor"
module SOAP
module Marshal
# Trying xsd:dateTime data to be recovered as aTime.
MarshalMappingRegistry = Mapping::EncodedRegistry.new(
:allow_original_mapping => true)
MarshalMappingRegistry.add(
Time,
::SOAP::SOAPDateTime,
::SOAP::Mapping::EncodedRegistry::DateTimeFactory
)
class << self
public
def dump(obj, io = nil)
marshal(obj, MarshalMappingRegistry, io)
end
def load(stream)
unmarshal(stream, MarshalMappingRegistry)
end
def marshal(obj, mapping_registry = MarshalMappingRegistry, io = nil)
elename = Mapping.name2elename(obj.class.to_s)
soap_obj = Mapping.obj2soap(obj, mapping_registry)
body = SOAPBody.new
body.add(elename, soap_obj)
env = SOAPEnvelope.new(nil, body)
SOAP::Processor.marshal(env, {}, io)
end
def unmarshal(stream, mapping_registry = MarshalMappingRegistry)
env = SOAP::Processor.unmarshal(stream)
if env.nil?
raise ArgumentError.new("Illegal SOAP marshal format.")
end
Mapping.soap2obj(env.body.root_node, mapping_registry)
end
end
end
end
SOAPMarshal = SOAP::Marshal

View file

@ -0,0 +1,241 @@
# SOAP4R - MIME Message implementation.
# Copyright (C) 2002 Jamie Herre.
# This program is copyrighted free software by NAKAMURA, Hiroshi. You can
# redistribute it and/or modify it under the same terms of Ruby's license;
# either the dual license version in 2003, or any later version.
require 'soap/attachment'
module SOAP
# Classes for MIME message handling. Should be put somewhere else!
# Tried using the 'tmail' module but found that I needed something
# lighter in weight.
class MIMEMessage
class MIMEMessageError < StandardError; end
MultipartContentType = 'multipart/\w+'
class Header
attr_accessor :str, :key, :root
def initialize
@attrs = {}
end
def [](key)
@attrs[key]
end
def []=(key, value)
@attrs[key] = value
end
def to_s
@key + ": " + @str
end
end
class Headers < Hash
def self.parse(str)
new.parse(str)
end
def parse(str)
header_cache = nil
str.each do |line|
case line
when /^\A[^\: \t]+:\s*.+$/
parse_line(header_cache) if header_cache
header_cache = line.sub(/\r?\n\z/, '')
when /^\A\s+(.*)$/
# a continuous line at the beginning line crashes here.
header_cache << line
else
raise RuntimeError.new("unexpected header: #{line.inspect}")
end
end
parse_line(header_cache) if header_cache
self
end
def parse_line(line)
if /^\A([^\: \t]+):\s*(.+)\z/ =~ line
header = parse_rhs($2.strip)
header.key = $1.strip
self[header.key.downcase] = header
else
raise RuntimeError.new("unexpected header line: #{line.inspect}")
end
end
def parse_rhs(str)
a = str.split(/;+\s+/)
header = Header.new
header.str = str
header.root = a.shift
a.each do |pair|
if pair =~ /(\w+)\s*=\s*"?([^"]+)"?/
header[$1.downcase] = $2
else
raise RuntimeError.new("unexpected header component: #{pair.inspect}")
end
end
header
end
def add(key, value)
if key != nil and value != nil
header = parse_rhs(value)
header.key = key
self[key.downcase] = header
end
end
def to_s
self.values.collect { |hdr|
hdr.to_s
}.join("\r\n")
end
end
class Part
attr_accessor :headers, :body
def initialize
@headers = Headers.new
@headers.add("Content-Transfer-Encoding", "8bit")
@body = nil
@contentid = nil
end
def self.parse(str)
new.parse(str)
end
def parse(str)
headers, body = str.split(/\r\n\r\n/s, 2)
if headers != nil and body != nil
@headers = Headers.parse(headers)
@body = body.sub(/\r\n\z/, '')
else
raise RuntimeError.new("unexpected part: #{str.inspect}")
end
self
end
def contentid
if @contentid == nil and @headers.key?('content-id')
@contentid = @headers['content-id'].str
@contentid = $1 if @contentid =~ /^<(.+)>$/
end
@contentid
end
alias content body
def to_s
@headers.to_s + "\r\n\r\n" + @body
end
end
def initialize
@parts = []
@headers = Headers.new
@root = nil
@boundary = nil
end
def self.parse(head, str)
new.parse(head, str)
end
attr_reader :parts, :headers
def close
@headers.add(
"Content-Type",
"multipart/related; type=\"text/xml\"; boundary=\"#{boundary}\"; start=\"#{@parts[0].contentid}\""
)
end
def parse(head, str)
@headers = Headers.parse(head + "\r\n" + "From: jfh\r\n")
boundary = @headers['content-type']['boundary']
if boundary != nil
parts = str.split(/--#{Regexp.quote(boundary)}\s*(?:\r\n|--\r\n)/)
part = parts.shift # preamble must be ignored.
@parts = parts.collect { |part| Part.parse(part) }
else
@parts = [Part.parse(str)]
end
if @parts.length < 1
raise MIMEMessageError.new("This message contains no valid parts!")
end
self
end
def root
if @root == nil
start = @headers['content-type']['start']
@root = (start && @parts.find { |prt| prt.contentid == start }) ||
@parts[0]
end
@root
end
def boundary
if @boundary == nil
@boundary = "----=Part_" + __id__.to_s + rand.to_s
end
@boundary
end
def add_part(content)
part = Part.new
part.headers.add("Content-Type",
"text/xml; charset=" + XSD::Charset.xml_encoding_label)
part.headers.add("Content-ID", Attachment.contentid(part))
part.body = content
@parts.unshift(part)
end
def add_attachment(attach)
part = Part.new
part.headers.add("Content-Type", attach.contenttype)
part.headers.add("Content-ID", attach.mime_contentid)
part.body = attach.content
@parts.unshift(part)
end
def has_parts?
(@parts.length > 0)
end
def headers_str
@headers.to_s
end
def content_str
str = ''
@parts.each do |prt|
str << "--" + boundary + "\r\n"
str << prt.to_s + "\r\n"
end
str << '--' + boundary + "--\r\n"
str
end
def to_s
str = headers_str + "\r\n\r\n" + conent_str
end
end
end

View file

@ -0,0 +1,9 @@
# SOAP4R - Namespace library
# Copyright (C) 2000-2007 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 'soap/compat'

View file

@ -0,0 +1,42 @@
# SOAP4R - Nested exception implementation
# Copyright (C) 2000-2007 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.
module SOAP
module NestedException
attr_reader :cause
attr_reader :original_backtraace
def initialize(msg = nil, cause = nil)
super(msg)
@cause = cause
@original_backtrace = nil
end
def set_backtrace(backtrace)
if @cause and @cause.respond_to?(:backtrace)
@original_backtrace = backtrace
=begin
# for agressive backtrace abstraction: 'here' only should not be good
here = @original_backtrace[0]
backtrace = Array[*@cause.backtrace]
backtrace[0] = "#{backtrace[0]}: #{@cause} (#{@cause.class})"
backtrace.unshift(here)
=end
# just join the nested backtrace at the tail of backtrace
caused = Array[*@cause.backtrace]
caused[0] = "#{caused[0]}: #{@cause} (#{@cause.class}) [NESTED]"
backtrace += caused
end
super(backtrace)
end
end
end

View file

@ -0,0 +1,241 @@
# SOAP4R - net/http wrapper
# Copyright (C) 2000-2007 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 'net/http'
require 'soap/filter/filterchain'
module SOAP
class NetHttpClient
SSLEnabled = begin
require 'net/https'
true
rescue LoadError
false
end
attr_reader :proxy
attr_accessor :no_proxy
attr_accessor :debug_dev
attr_accessor :ssl_config # ignored for now.
attr_accessor :protocol_version # ignored for now.
attr_accessor :connect_timeout
attr_accessor :send_timeout # ignored for now.
attr_accessor :receive_timeout
attr_reader :test_loopback_response
attr_reader :request_filter # ignored for now.
def initialize(proxy = nil, agent = nil)
@proxy = proxy ? URI.parse(proxy) : nil
@agent = agent
@debug_dev = nil
@test_loopback_response = []
@request_filter = Filter::FilterChain.new
@session_manager = SessionManager.new
@no_proxy = @ssl_config = @protocol_version = nil
@connect_timeout = @send_timeout = @receive_timeout = nil
end
def proxy=(proxy)
if proxy.nil?
@proxy = nil
else
if proxy.is_a?(URI)
@proxy = proxy
else
@proxy = URI.parse(proxy)
end
if @proxy.scheme == nil or @proxy.scheme.downcase != 'http' or
@proxy.host == nil or @proxy.port == nil
raise ArgumentError.new("unsupported proxy `#{proxy}'")
end
end
reset_all
@proxy
end
def set_auth(uri, user_id, passwd)
raise NotImplementedError.new("auth is not supported under soap4r + net/http.")
end
def set_basic_auth(uri, user_id, passwd)
# net/http does not handle url.
@basic_auth = [user_id, passwd]
raise NotImplementedError.new("basic_auth is not supported under soap4r + net/http.")
end
def set_cookie_store(filename)
raise NotImplementedError.new
end
def save_cookie_store(filename)
raise NotImplementedError.new
end
def reset(url)
# no persistent connection. ignored.
end
def reset_all
# no persistent connection. ignored.
end
def post(url, req_body, header = {})
post_redirect(url, req_body, header, 10)
end
def get_content(url, header = {})
if str = @test_loopback_response.shift
return str
end
unless url.is_a?(URI)
url = URI.parse(url)
end
extra = header.dup
extra['User-Agent'] = @agent if @agent
res = start(url) { |http|
http.get(url.request_uri, extra)
}
res.body
end
private
def post_redirect(url, req_body, header, redirect_count)
if str = @test_loopback_response.shift
if @debug_dev
@debug_dev << "= Request\n\n"
@debug_dev << req_body
@debug_dev << "\n\n= Response\n\n"
@debug_dev << str
end
status = 200
reason = nil
contenttype = 'text/xml'
content = str
return Response.new(status, reason, contenttype, content)
return str
end
unless url.is_a?(URI)
url = URI.parse(url)
end
extra = header.dup
extra['User-Agent'] = @agent if @agent
res = start(url) { |http|
if @debug_dev
@debug_dev << "= Request\n\n"
@debug_dev << req_body << "\n"
end
http.post(url.request_uri, req_body, extra)
}
case res
when Net::HTTPRedirection
if redirect_count > 0
post_redirect(res['location'], req_body, header,
redirect_count - 1)
else
raise ArgumentError.new("Too many redirects")
end
else
Response.from_httpresponse(res)
end
end
def start(url)
http = create_connection(url)
response = nil
http.start { |worker|
response = yield(worker)
worker.finish
}
if @debug_dev
@debug_dev << "\n\n= Response\n\n"
@debug_dev << response.body << "\n"
end
response
end
def create_connection(url)
proxy_host = proxy_port = nil
unless no_proxy?(url)
proxy_host = @proxy.host
proxy_port = @proxy.port
end
http = Net::HTTP::Proxy(proxy_host, proxy_port).new(url.host, url.port)
if http.respond_to?(:set_debug_output)
http.set_debug_output(@debug_dev)
end
http.open_timeout = @connect_timeout if @connect_timeout
http.read_timeout = @receive_timeout if @receive_timeout
case url
when URI::HTTPS
if SSLEnabled
http.use_ssl = true
else
raise RuntimeError.new("Cannot connect to #{url} (OpenSSL is not installed.)")
end
when URI::HTTP
# OK
else
raise RuntimeError.new("Cannot connect to #{url} (Not HTTP.)")
end
http
end
NO_PROXY_HOSTS = ['localhost']
def no_proxy?(uri)
if !@proxy or NO_PROXY_HOSTS.include?(uri.host)
return true
end
unless @no_proxy
return false
end
@no_proxy.scan(/([^:,]+)(?::(\d+))?/) do |host, port|
if /(\A|\.)#{Regexp.quote(host)}\z/i =~ uri.host &&
(!port || uri.port == port.to_i)
return true
end
end
false
end
class SessionManager
attr_accessor :connect_timeout
attr_accessor :send_timeout
attr_accessor :receive_timeout
end
class Response
attr_reader :status
attr_reader :reason
attr_reader :contenttype
attr_reader :content
def initialize(status, reason, contenttype, content)
@status = status
@reason = reason
@contenttype = contenttype
@content = content
end
def self.from_httpresponse(res)
status = res.code.to_i
reason = res.message
contenttype = res['content-type']
content = res.body
new(status, reason, contenttype, content)
end
end
end
end

34
vendor/gems/soap4r-1.5.8/lib/soap/ns.rb vendored Normal file
View file

@ -0,0 +1,34 @@
# SOAP4R - SOAP Namespace library
# Copyright (C) 2000-2007 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/datatypes'
require 'xsd/ns'
require 'soap/soap'
module SOAP
class NS < XSD::NS
KNOWN_TAG = XSD::NS::KNOWN_TAG.dup.update(
SOAP::EnvelopeNamespace => 'env'
)
def initialize(tag2ns = nil)
super(tag2ns)
end
private
def default_known_tag
KNOWN_TAG
end
end
end

View file

@ -0,0 +1,252 @@
# SOAP4R - SOAP XML Instance Parser library.
# Copyright (C) 2000-2007 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/xmlparser'
require 'soap/soap'
require 'soap/ns'
require 'soap/baseData'
require 'soap/encodingstyle/handler'
module SOAP
class Parser
include SOAP
class ParseError < Error; end
class FormatDecodeError < ParseError; end
class UnexpectedElementError < ParseError; end
private
class ParseFrame
attr_reader :node
attr_reader :name
attr_reader :ns
attr_reader :encodingstyle
attr_reader :handler
class NodeContainer
def initialize(node)
@node = node
end
def node
@node
end
def replace_node(node)
@node = node
end
end
public
def initialize(ns, name, node, encodingstyle, handler)
@ns = ns
@name = name
@node = NodeContainer.new(node)
@encodingstyle = encodingstyle
@handler = handler
end
# to avoid memory consumption
def update(ns, name, node, encodingstyle, handler)
@ns = ns
@name = name
@node.replace_node(node)
@encodingstyle = encodingstyle
@handler = handler
self
end
end
public
attr_accessor :envelopenamespace
attr_accessor :default_encodingstyle
attr_accessor :decode_typemap
attr_accessor :allow_unqualified_element
def initialize(opt = {})
@opt = opt
@parser = XSD::XMLParser.create_parser(self, opt)
@parsestack = nil
@recycleframe = nil
@lastnode = nil
@handlers = {}
@envelopenamespace = opt[:envelopenamespace] || EnvelopeNamespace
@default_encodingstyle = opt[:default_encodingstyle] || EncodingNamespace
@decode_typemap = opt[:decode_typemap] || nil
@allow_unqualified_element = opt[:allow_unqualified_element] || false
end
def charset
@parser.charset
end
def parse(string_or_readable)
@parsestack = []
@lastnode = nil
@handlers.each do |uri, handler|
handler.decode_prologue
end
@parser.do_parse(string_or_readable)
unless @parsestack.empty?
raise FormatDecodeError.new("Unbalanced tag in XML.")
end
@handlers.each do |uri, handler|
handler.decode_epilogue
end
@lastnode
end
def start_element(name, raw_attrs)
lastframe = @parsestack.last
ns = parent = parent_encodingstyle = nil
if lastframe
ns = lastframe.ns
parent = lastframe.node
parent_encodingstyle = lastframe.encodingstyle
else
ns = SOAP::NS.new
parent = ParseFrame::NodeContainer.new(nil)
parent_encodingstyle = nil
end
# ns might be the same
ns, raw_attrs = XSD::XMLParser.filter_ns(ns, raw_attrs)
attrs = decode_attrs(ns, raw_attrs)
encodingstyle = attrs[AttrEncodingStyleName]
# Children's encodingstyle is derived from its parent.
if encodingstyle.nil?
if parent.node.is_a?(SOAPHeader)
encodingstyle = LiteralNamespace
else
encodingstyle = parent_encodingstyle || @default_encodingstyle
end
end
handler = find_handler(encodingstyle)
unless handler
raise FormatDecodeError.new("Unknown encodingStyle: #{ encodingstyle }.")
end
node = decode_tag(ns, name, attrs, parent, handler)
if @recycleframe
@parsestack << @recycleframe.update(ns, name, node, encodingstyle, handler)
@recycleframe = nil
else
@parsestack << ParseFrame.new(ns, name, node, encodingstyle, handler)
end
end
def characters(text)
# Ignore Text outside of SOAP Envelope.
if lastframe = @parsestack.last
# Need not to be cloned because character does not have attr.
decode_text(lastframe.ns, text, lastframe.handler)
end
end
def end_element(name)
lastframe = @parsestack.pop
unless name == lastframe.name
raise UnexpectedElementError.new("Closing element name '#{ name }' does not match with opening element '#{ lastframe.name }'.")
end
decode_tag_end(lastframe.ns, lastframe.node, lastframe.handler)
@lastnode = lastframe.node.node
@recycleframe = lastframe
end
private
def decode_tag(ns, name, attrs, parent, handler)
ele = ns.parse(name)
# Envelope based parsing.
if ((ele.namespace == @envelopenamespace) ||
(@allow_unqualified_element && ele.namespace.nil?))
o = decode_soap_envelope(ns, ele, attrs, parent)
return o if o
end
# Encoding based parsing.
return handler.decode_tag(ns, ele, attrs, parent)
end
def decode_tag_end(ns, node, handler)
return handler.decode_tag_end(ns, node)
end
def decode_attrs(ns, attrs)
extraattr = {}
attrs.each do |key, value|
qname = ns.parse_local(key)
extraattr[qname] = value
end
extraattr
end
def decode_text(ns, text, handler)
handler.decode_text(ns, text)
end
def decode_soap_envelope(ns, ele, attrs, parent)
o = nil
if ele.name == EleEnvelope
o = SOAPEnvelope.new
if ext = @opt[:external_content]
ext.each do |k, v|
o.external_content[k] = v
end
end
elsif ele.name == EleHeader
return nil unless parent.node.is_a?(SOAPEnvelope)
o = SOAPHeader.new
parent.node.header = o
elsif ele.name == EleBody
return nil unless parent.node.is_a?(SOAPEnvelope)
o = SOAPBody.new
parent.node.body = o
elsif ele.name == EleFault
if parent.node.is_a?(SOAPBody)
o = SOAPFault.new
parent.node.fault = o
elsif parent.node.is_a?(SOAPEnvelope)
# live.com server returns SOAPFault as a direct child of SOAPEnvelope.
# support it even if it's not spec compliant.
warn("Fault must be a child of Body.")
body = SOAPBody.new
parent.node.body = body
o = SOAPFault.new
body.fault = o
else
return nil
end
end
o.extraattr.update(attrs) if o
o
end
def find_handler(encodingstyle)
unless @handlers.key?(encodingstyle)
handler_factory = SOAP::EncodingStyle::Handler.handler(encodingstyle) ||
SOAP::EncodingStyle::Handler.handler(EncodingNamespace)
handler = handler_factory.new(@parser.charset)
handler.decode_typemap = @decode_typemap
handler.decode_prologue
@handlers[encodingstyle] = handler
end
@handlers[encodingstyle]
end
end
end

View file

@ -0,0 +1,66 @@
# SOAP4R - marshal/unmarshal interface.
# Copyright (C) 2000-2007 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/datatypes'
require 'soap/soap'
require 'soap/element'
require 'soap/parser'
require 'soap/generator'
require 'soap/encodingstyle/soapHandler'
require 'soap/encodingstyle/literalHandler'
require 'soap/encodingstyle/aspDotNetHandler'
module SOAP
module Processor
@@default_parser_option = {}
class << self
public
def marshal(env, opt = {}, io = nil)
generator = create_generator(opt)
marshalled_str = generator.generate(env, io)
unless env.external_content.empty?
opt[:external_content] = env.external_content
end
marshalled_str
end
def unmarshal(stream, opt = {})
parser = create_parser(opt)
parser.parse(stream)
end
def default_parser_option=(rhs)
@@default_parser_option = rhs
end
def default_parser_option
@@default_parser_option
end
private
def create_generator(opt)
Generator.new(opt)
end
def create_parser(opt)
if opt.empty?
opt = @@default_parser_option
end
::SOAP::Parser.new(opt)
end
end
end
end

View file

@ -0,0 +1,333 @@
# soap/property.rb: SOAP4R - Property implementation.
# Copyright (C) 2000-2007 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.
module SOAP
# Property stream format:
#
# line separator is \r?\n. 1 line per a property.
# line which begins with '#' is a comment line. empty line is ignored, too.
# key/value separator is ':' or '='.
# '\' as escape character. but line separator cannot be escaped.
# \s at the head/tail of key/value are trimmed.
#
# '[' + key + ']' indicates property section. for example,
#
# [aaa.bbb]
# ccc = ddd
# eee.fff = ggg
# []
# aaa.hhh = iii
#
# is the same as;
#
# aaa.bbb.ccc = ddd
# aaa.bbb.eee.fff = ggg
# aaa.hhh = iii
#
class Property
FrozenError = (RUBY_VERSION >= "1.9.0") ? RuntimeError : TypeError
include Enumerable
module Util
def const_from_name(fqname)
fqname.split("::").inject(Kernel) { |klass, name| klass.const_get(name) }
end
module_function :const_from_name
def require_from_name(fqname)
require File.join(fqname.split("::").collect { |ele| ele.downcase })
end
module_function :require_from_name
end
def self.load(stream)
new.load(stream)
end
def self.loadproperty(propname)
new.loadproperty(propname)
end
def initialize
@store = Hash.new
@hook = Hash.new
@self_hook = Array.new
@locked = false
end
KEY_REGSRC = '([^=:\\\\]*(?:\\\\.[^=:\\\\]*)*)'
DEF_REGSRC = '\\s*' + KEY_REGSRC + '\\s*[=:]\\s*(.*)'
COMMENT_REGEXP = Regexp.new('^(?:#.*|)$', nil, 'u')
CATDEF_REGEXP = Regexp.new("^\\[\\s*#{KEY_REGSRC}\\s*\\]$", nil, 'u')
LINE_REGEXP = Regexp.new("^#{DEF_REGSRC}$", nil, 'u')
def load(stream)
key_prefix = ""
stream.each_with_index do |line, lineno|
line.sub!(/\r?\n\z/u, '')
case line
when COMMENT_REGEXP
next
when CATDEF_REGEXP
key_prefix = $1.strip
when LINE_REGEXP
key, value = $1.strip, $2.strip
key = "#{key_prefix}.#{key}" unless key_prefix.empty?
key, value = loadstr(key), loadstr(value)
self[key] = value
else
raise TypeError.new(
"property format error at line #{lineno + 1}: `#{line}'")
end
end
self
end
# find property from $:.
def loadproperty(propname)
return loadpropertyfile(propname) if File.file?(propname)
$:.each do |path|
if File.file?(file = File.join(path, propname))
return loadpropertyfile(file)
end
end
nil
end
# name: a Symbol, String or an Array
def [](name)
referent(name_to_a(name))
end
# name: a Symbol, String or an Array
# value: an Object
def []=(name, value)
name_pair = name_to_a(name).freeze
hooks = assign(name_pair, value)
hooks.each do |hook|
hook.call(name_pair, value)
end
value
end
# value: an Object
# key is generated by property
def <<(value)
self[generate_new_key] = value
end
# name: a Symbol, String or an Array; nil means hook to the root
# cascade: true/false; for cascading hook of sub key
# hook: block which will be called with 2 args, name and value
def add_hook(name = nil, cascade = false, &hook)
if name == nil or name == true or name == false
cascade = name
assign_self_hook(cascade, &hook)
else
assign_hook(name_to_a(name), cascade, &hook)
end
end
def each
@store.each do |key, value|
yield(key, value)
end
end
def empty?
@store.empty?
end
def keys
@store.keys
end
def values
@store.values
end
def lock(cascade = false)
if cascade
each_key do |key|
key.lock(cascade)
end
end
@locked = true
self
end
def unlock(cascade = false)
@locked = false
if cascade
each_key do |key|
key.unlock(cascade)
end
end
self
end
def locked?
@locked
end
protected
def deref_key(key)
check_lock(key)
ref = @store[key] ||= self.class.new
unless propkey?(ref)
raise ArgumentError.new("key `#{key}' already defined as a value")
end
ref
end
def local_referent(key)
check_lock(key)
if propkey?(@store[key]) and @store[key].locked?
raise FrozenError.new("cannot split any key from locked property")
end
@store[key]
end
def local_assign(key, value)
check_lock(key)
if @locked
if propkey?(value)
raise FrozenError.new("cannot add any key to locked property")
elsif propkey?(@store[key])
raise FrozenError.new("cannot override any key in locked property")
end
end
@store[key] = value
end
def local_hook(key, direct)
hooks = []
(@self_hook + (@hook[key] || NO_HOOK)).each do |hook, cascade|
hooks << hook if direct or cascade
end
hooks
end
def local_assign_hook(key, cascade, &hook)
check_lock(key)
@store[key] ||= nil
(@hook[key] ||= []) << [hook, cascade]
end
private
NO_HOOK = [].freeze
def referent(ary)
ary[0..-2].inject(self) { |ref, name|
ref.deref_key(to_key(name))
}.local_referent(to_key(ary.last))
end
def assign(ary, value)
ref = self
hook = NO_HOOK
ary[0..-2].each do |name|
key = to_key(name)
hook += ref.local_hook(key, false)
ref = ref.deref_key(key)
end
last_key = to_key(ary.last)
ref.local_assign(last_key, value)
hook + ref.local_hook(last_key, true)
end
def assign_hook(ary, cascade, &hook)
ary[0..-2].inject(self) { |ref, name|
ref.deref_key(to_key(name))
}.local_assign_hook(to_key(ary.last), cascade, &hook)
end
def assign_self_hook(cascade, &hook)
check_lock(nil)
@self_hook << [hook, cascade]
end
def each_key
self.each do |key, value|
if propkey?(value)
yield(value)
end
end
end
def check_lock(key)
if @locked and (key.nil? or !@store.key?(key))
raise FrozenError.new("cannot add any key to locked property")
end
end
def propkey?(value)
value.is_a?(::SOAP::Property)
end
def name_to_a(name)
case name
when Symbol
[name]
when String
name.scan(/[^.\\]+(?:\\.[^.\\])*/u) # split with unescaped '.'
when Array
name
else
raise ArgumentError.new("Unknown name #{name}(#{name.class})")
end
end
def to_key(name)
name.to_s.downcase
end
def generate_new_key
if @store.empty?
"0"
else
(key_max + 1).to_s
end
end
def key_max
(@store.keys.max { |l, r| l.to_s.to_i <=> r.to_s.to_i }).to_s.to_i
end
def loadpropertyfile(file)
puts "find property at #{file}" if $DEBUG
File.open(file) do |f|
load(f)
end
end
def loadstr(str)
str.gsub(/\\./u) { |c| eval("\"#{c}\"") }
end
end
end
# for ruby/1.6.
unless Enumerable.instance_methods.include?('inject')
module Enumerable
def inject(init)
result = init
each do |item|
result = yield(result, item)
end
result
end
end
end

View file

@ -0,0 +1,14 @@
# SOAP4R - Proxy library.
# Copyright (C) 2000-2007 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 'soap/rpc/proxy'
module SOAP
SOAPProxy = RPC::Proxy
end

View file

@ -0,0 +1,9 @@
# SOAP4R - XML QName definition.
# Copyright (C) 2000-2007 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 'soap/compat'

View file

@ -0,0 +1,247 @@
# SOAP4R - CGI/mod_ruby stub library
# Copyright (C) 2000-2007 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 'soap/streamHandler'
require 'webrick/httpresponse'
require 'webrick/httpstatus'
require 'logger'
require 'soap/rpc/soaplet'
module SOAP
module RPC
###
# SYNOPSIS
# CGIStub.new
#
# DESCRIPTION
# To be written...
#
class CGIStub < Logger::Application
include SOAP
include WEBrick
class SOAPRequest
attr_reader :body
def [](var); end
def meta_vars; end
EMPTY_COOKIES = [].freeze
def cookies; EMPTY_COOKIES; end
def user; end
end
class SOAPStdinRequest < SOAPRequest
attr_reader :body
def initialize(stream)
size = ENV['CONTENT_LENGTH'].to_i || 0
@body = stream.read(size)
end
def [](var)
ENV[var.gsub(/-/, '_').upcase]
end
def meta_vars
{
'HTTP_SOAPACTION' => ENV['HTTP_SOAPAction']
}
end
def cookies
if cookie = ENV['HTTP_Cookie'] || ENV['Cookie']
[WEBrick::Cookie.parse(cookie)]
else
EMPTY_COOKIES
end
end
def user
ENV['REMOTE_USER']
end
end
class SOAPFCGIRequest < SOAPRequest
attr_reader :body
def initialize(request)
@request = request
@body = @request.in.read
end
def [](var)
@request.env[var.gsub(/-/, '_').upcase]
end
def meta_vars
{
'HTTP_SOAPACTION' => @request.env['HTTP_SOAPAction']
}
end
def cookies
if cookie = @request.env['HTTP_Cookie'] || @request.env['Cookie']
[WEBrick::Cookie.parse(cookie)]
else
EMPTY_COOKIES
end
end
def user
@request.env['REMOTE_USER']
end
end
def initialize(appname, default_namespace)
super(appname)
set_log(STDERR)
self.level = ERROR
@default_namespace = default_namespace
@remote_host = ENV['REMOTE_HOST'] || ENV['REMOTE_ADDR'] || 'unknown'
@router = ::SOAP::RPC::Router.new(self.class.name)
@soaplet = ::SOAP::RPC::SOAPlet.new(@router)
on_init
end
def on_init
# do extra initialization in a derived class if needed.
end
def mapping_registry
@router.mapping_registry
end
def mapping_registry=(mapping_registry)
@router.mapping_registry = mapping_registry
end
def literal_mapping_registry
@router.literal_mapping_registry
end
def literal_mapping_registry=(literal_mapping_registry)
@router.literal_mapping_registry = literal_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_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
def filterchain
@router.filterchain
end
# method entry interface
def add_rpc_method(obj, name, *param)
add_rpc_method_with_namespace_as(@default_namespace, obj, name, name, *param)
end
alias add_method add_rpc_method
def add_rpc_method_as(obj, name, name_as, *param)
add_rpc_method_with_namespace_as(@default_namespace, obj, name, name_as, *param)
end
alias add_method_as add_rpc_method_as
def add_rpc_method_with_namespace(namespace, obj, name, *param)
add_rpc_method_with_namespace_as(namespace, obj, name, name, *param)
end
alias add_method_with_namespace add_rpc_method_with_namespace
def add_rpc_method_with_namespace_as(namespace, obj, name, name_as, *param)
qname = XSD::QName.new(namespace, name_as)
soapaction = nil
param_def = SOAPMethod.derive_rpc_param_def(obj, name, *param)
@router.add_rpc_operation(obj, qname, soapaction, name, param_def)
end
alias add_method_with_namespace_as add_rpc_method_with_namespace_as
def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {})
@router.add_rpc_operation(receiver, qname, soapaction, name, param_def, opt)
end
def add_document_operation(receiver, soapaction, name, param_def, opt = {})
@router.add_document_operation(receiver, soapaction, name, param_def, opt)
end
def set_fcgi_request(request)
@fcgi = request
end
private
HTTPVersion = WEBrick::HTTPVersion.new('1.0') # dummy; ignored
def run
res = WEBrick::HTTPResponse.new({:HTTPVersion => HTTPVersion})
begin
@log.info { "received a request from '#{ @remote_host }'" }
if @fcgi
req = SOAPFCGIRequest.new(@fcgi)
else
req = SOAPStdinRequest.new($stdin)
end
@soaplet.do_POST(req, res)
rescue HTTPStatus::EOFError, HTTPStatus::RequestTimeout => ex
res.set_error(ex)
rescue HTTPStatus::Error => ex
res.set_error(ex)
rescue HTTPStatus::Status => ex
res.status = ex.code
rescue StandardError, NameError => ex # for Ruby 1.6
res.set_error(ex, true)
ensure
if defined?(MOD_RUBY)
r = Apache.request
r.status = res.status
r.content_type = res.content_type
r.send_http_header
buf = res.body
else
buf = ''
res.send_response(buf)
buf.sub!(/^[^\r]+\r\n/, '') # Trim status line.
end
@log.debug { "SOAP CGI Response:\n#{ buf }" }
if @fcgi
@fcgi.out.print buf
@fcgi.finish
@fcgi = nil
else
print buf
end
end
0
end
end
end
end

View file

@ -0,0 +1,247 @@
# SOAP4R - SOAP RPC driver
# Copyright (C) 2000-2007 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 'soap/soap'
require 'soap/mapping'
require 'soap/rpc/rpc'
require 'soap/rpc/proxy'
require 'soap/rpc/element'
require 'soap/streamHandler'
require 'soap/property'
require 'soap/header/handlerset'
module SOAP
module RPC
class Driver
class << self
if RUBY_VERSION >= "1.7.0"
def __attr_proxy(symbol, assignable = false)
name = symbol.to_s
define_method(name) {
@proxy.__send__(name)
}
if assignable
aname = name + '='
define_method(aname) { |rhs|
@proxy.__send__(aname, rhs)
}
end
end
else
def __attr_proxy(symbol, assignable = false)
name = symbol.to_s
module_eval <<-EOS
def #{name}
@proxy.#{name}
end
EOS
if assignable
module_eval <<-EOS
def #{name}=(value)
@proxy.#{name} = value
end
EOS
end
end
end
end
__attr_proxy :endpoint_url, true
__attr_proxy :mapping_registry, true
__attr_proxy :literal_mapping_registry, true
__attr_proxy :allow_unqualified_element, true
__attr_proxy :default_encodingstyle, true
__attr_proxy :generate_explicit_type, true
__attr_proxy :use_default_namespace, true
__attr_proxy :return_response_as_xml, true
__attr_proxy :headerhandler
__attr_proxy :filterchain
__attr_proxy :streamhandler
__attr_proxy :test_loopback_response
__attr_proxy :reset_stream
attr_reader :proxy
attr_reader :options
attr_accessor :soapaction
def inspect
"#<#{self.class}:#{@proxy.inspect}>"
end
def httpproxy
options["protocol.http.proxy"]
end
def httpproxy=(httpproxy)
options["protocol.http.proxy"] = httpproxy
end
def wiredump_dev
options["protocol.http.wiredump_dev"]
end
def wiredump_dev=(wiredump_dev)
options["protocol.http.wiredump_dev"] = wiredump_dev
end
def mandatorycharset
options["protocol.mandatorycharset"]
end
def mandatorycharset=(mandatorycharset)
options["protocol.mandatorycharset"] = mandatorycharset
end
def wiredump_file_base
options["protocol.wiredump_file_base"]
end
def wiredump_file_base=(wiredump_file_base)
options["protocol.wiredump_file_base"] = wiredump_file_base
end
def initialize(endpoint_url, namespace = nil, soapaction = nil)
@namespace = namespace
@soapaction = soapaction
@options = setup_options
@wiredump_file_base = nil
@proxy = Proxy.new(endpoint_url, @soapaction, @options)
end
def loadproperty(propertyname)
unless options.loadproperty(propertyname)
raise LoadError.new("No such property to load -- #{propertyname}")
end
end
def add_rpc_method(name, *params)
add_rpc_method_with_soapaction_as(name, name, @soapaction, *params)
end
def add_rpc_method_as(name, name_as, *params)
add_rpc_method_with_soapaction_as(name, name_as, @soapaction, *params)
end
def add_rpc_method_with_soapaction(name, soapaction, *params)
add_rpc_method_with_soapaction_as(name, name, soapaction, *params)
end
def add_rpc_method_with_soapaction_as(name, name_as, soapaction, *params)
param_def = SOAPMethod.create_rpc_param_def(params)
qname = XSD::QName.new(@namespace, name_as)
@proxy.add_rpc_method(qname, soapaction, name, param_def)
add_rpc_method_interface(name, param_def)
end
# add_method is for shortcut of typical rpc/encoded method definition.
alias add_method add_rpc_method
alias add_method_as add_rpc_method_as
alias add_method_with_soapaction add_rpc_method_with_soapaction
alias add_method_with_soapaction_as add_rpc_method_with_soapaction_as
def add_document_method(name, soapaction, req_qname, res_qname)
param_def = SOAPMethod.create_doc_param_def(req_qname, res_qname)
@proxy.add_document_method(soapaction, name, param_def)
add_document_method_interface(name, param_def)
end
def add_rpc_operation(qname, soapaction, name, param_def, opt = {})
@proxy.add_rpc_operation(qname, soapaction, name, param_def, opt)
add_rpc_method_interface(name, param_def)
end
def add_document_operation(soapaction, name, param_def, opt = {})
@proxy.add_document_operation(soapaction, name, param_def, opt)
add_document_method_interface(name, param_def)
end
def invoke(headers, body)
if headers and !headers.is_a?(SOAPHeader)
headers = create_header(headers)
end
set_wiredump_file_base(body.elename.name)
env = @proxy.invoke(headers, body)
if env.nil?
return nil, nil
else
return env.header, env.body
end
end
def call(name, *params)
set_wiredump_file_base(name)
@proxy.call(name, *params)
end
private
def set_wiredump_file_base(name)
if @wiredump_file_base
@proxy.set_wiredump_file_base("#{@wiredump_file_base}_#{name}")
end
end
def create_header(headers)
header = SOAPHeader.new()
headers.each do |content, mustunderstand, encodingstyle|
header.add(SOAPHeaderItem.new(content, mustunderstand, encodingstyle))
end
header
end
def setup_options
if opt = Property.loadproperty(::SOAP::PropertyName)
opt = opt["client"]
end
opt ||= Property.new
opt.add_hook("protocol.mandatorycharset") do |key, value|
@proxy.mandatorycharset = value
end
opt.add_hook("protocol.wiredump_file_base") do |key, value|
@wiredump_file_base = value
end
opt["protocol.http.charset"] ||= XSD::Charset.xml_encoding_label
opt["protocol.http.proxy"] ||= Env::HTTP_PROXY
opt["protocol.http.no_proxy"] ||= Env::NO_PROXY
opt
end
def add_rpc_method_interface(name, param_def)
param_count = RPC::SOAPMethod.param_count(param_def,
RPC::SOAPMethod::IN, RPC::SOAPMethod::INOUT)
add_method_interface(name, param_count)
end
def add_document_method_interface(name, param_def)
param_count = RPC::SOAPMethod.param_count(param_def, RPC::SOAPMethod::IN)
add_method_interface(name, param_count)
end
# Mapping.define_singleton_method calls define_method with proc and it
# exhausts much memory for each singleton Object. just instance_eval instead
# of it.
def add_method_interface(name, param_count)
instance_eval <<-EOS
def #{name}(*arg)
unless arg.size == #{param_count}
raise ArgumentError.new(
"wrong number of arguments (\#{arg.size} for #{param_count})")
end
call(#{name.dump}, *arg)
end
EOS
self.method(name)
end
end
end
end

View file

@ -0,0 +1,369 @@
# SOAP4R - RPC element definition.
# Copyright (C) 2000-2007 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 'soap/baseData'
module SOAP
# Add method definitions for RPC to common definition in element.rb
class SOAPBody < SOAPStruct
public
def request
root_node
end
def response
root = root_node
if !@is_fault
if root.nil?
nil
elsif root.is_a?(SOAPBasetype)
root
else
# Initial element is [retval].
root[0]
end
else
root
end
end
def outparams
root = root_node
if !@is_fault and !root.nil? and !root.is_a?(SOAPBasetype)
op = root[1..-1]
op = nil if op && op.empty?
op
else
nil
end
end
def fault
if @is_fault
self['fault']
else
nil
end
end
def fault=(fault)
@is_fault = true
add('fault', fault)
end
end
module RPC
class RPCError < Error; end
class MethodDefinitionError < RPCError; end
class ParameterError < RPCError; end
class SOAPMethod < SOAPStruct
RETVAL = 'retval'
IN = 'in'
OUT = 'out'
INOUT = 'inout'
attr_reader :param_def
attr_reader :inparam
attr_reader :outparam
attr_reader :retval_name
attr_reader :retval_class_name
def initialize(qname, param_def = nil)
super(nil)
@elename = qname
@encodingstyle = nil
@param_def = param_def
@signature = []
@inparam_names = []
@inoutparam_names = []
@outparam_names = []
@inparam = {}
@outparam = {}
@retval_name = nil
@retval_class_name = nil
init_param(@param_def) if @param_def
end
def have_member
true
end
def have_outparam?
@outparam_names.size > 0
end
def input_params
collect_params(IN, INOUT)
end
def output_params
collect_params(OUT, INOUT)
end
def input_param_types
collect_param_types(IN, INOUT)
end
def output_param_types
collect_param_types(OUT, INOUT)
end
def set_param(params)
params.each do |param, data|
@inparam[param] = data
data.elename = XSD::QName.new(data.elename.namespace, param)
data.parent = self
end
end
def set_outparam(params)
params.each do |param, data|
@outparam[param] = data
data.elename = XSD::QName.new(data.elename.namespace, param)
end
end
def get_paramtypes(names)
types = []
@signature.each do |io_type, name, type_qname|
if type_qname && idx = names.index(name)
types[idx] = type_qname
end
end
types
end
def SOAPMethod.param_count(param_def, *type)
count = 0
param_def.each do |io_type, name, param_type|
if type.include?(io_type)
count += 1
end
end
count
end
def SOAPMethod.derive_rpc_param_def(obj, name, *param)
if param.size == 1 and param[0].is_a?(Array)
return param[0]
end
if param.empty?
method = obj.method(name)
param_names = (1..method.arity.abs).collect { |i| "p#{i}" }
else
param_names = param
end
create_rpc_param_def(param_names)
end
def SOAPMethod.create_rpc_param_def(param_names)
param_def = []
param_names.each do |param_name|
param_def.push([IN, param_name, nil])
end
param_def.push([RETVAL, 'return', nil])
param_def
end
def SOAPMethod.create_doc_param_def(req_qnames, res_qnames)
req_qnames = [req_qnames] if req_qnames.is_a?(XSD::QName)
res_qnames = [res_qnames] if res_qnames.is_a?(XSD::QName)
param_def = []
# req_qnames and res_qnames can be nil
if req_qnames
req_qnames.each do |qname|
param_def << [IN, qname.name, [nil, qname.namespace, qname.name]]
end
end
if res_qnames
res_qnames.each do |qname|
param_def << [OUT, qname.name, [nil, qname.namespace, qname.name]]
end
end
param_def
end
private
def collect_param_types(*type)
names = []
@signature.each do |io_type, name, type_qname|
names << type_qname if type.include?(io_type)
end
names
end
def collect_params(*type)
names = []
@signature.each do |io_type, name, type_qname|
names << name if type.include?(io_type)
end
names
end
def init_param(param_def)
param_def.each do |io_type, name, param_type|
mapped_class, nsdef, namedef = SOAPMethod.parse_param_type(param_type)
if nsdef && namedef
type_qname = XSD::QName.new(nsdef, namedef)
elsif mapped_class
type_qname = TypeMap.index(mapped_class)
end
case io_type
when IN
@signature.push([IN, name, type_qname])
@inparam_names.push(name)
when OUT
@signature.push([OUT, name, type_qname])
@outparam_names.push(name)
when INOUT
@signature.push([INOUT, name, type_qname])
@inoutparam_names.push(name)
when RETVAL
if @retval_name
raise MethodDefinitionError.new('duplicated retval')
end
@retval_name = name
@retval_class_name = mapped_class
else
raise MethodDefinitionError.new("unknown type: #{io_type}")
end
end
end
def self.parse_param_type(param_type)
mapped_class, nsdef, namedef = param_type
# the first element of typedef in param_def can be a String like
# "::SOAP::SOAPStruct" or "CustomClass[]". turn this String to a class if
# we can.
if mapped_class.is_a?(String)
if /\[\]\Z/ =~ mapped_class
# when '[]' is added, ignore this.
mapped_class = nil
else
mapped_class = Mapping.class_from_name(mapped_class)
end
end
[mapped_class, nsdef, namedef]
end
end
class SOAPMethodRequest < SOAPMethod
attr_accessor :soapaction
def SOAPMethodRequest.create_request(qname, *params)
param_def = []
param_value = []
i = 0
params.each do |param|
param_name = "p#{i}"
i += 1
param_def << [IN, param_name, nil]
param_value << [param_name, param]
end
param_def << [RETVAL, 'return', nil]
o = new(qname, param_def)
o.set_param(param_value)
o
end
def initialize(qname, param_def = nil, soapaction = nil)
super(qname, param_def)
@soapaction = soapaction
end
def each
input_params.each do |name|
unless @inparam[name]
raise ParameterError.new("parameter: #{name} was not given")
end
yield(name, @inparam[name])
end
end
def dup
req = self.class.new(@elename.dup, @param_def, @soapaction)
req.encodingstyle = @encodingstyle
req
end
def create_method_response(response_name = nil)
response_name ||=
XSD::QName.new(@elename.namespace, @elename.name + 'Response')
SOAPMethodResponse.new(response_name, @param_def)
end
end
class SOAPMethodResponse < SOAPMethod
def initialize(qname, param_def = nil)
super(qname, param_def)
@retval = nil
end
def retval
@retval
end
def retval=(retval)
@retval = retval
@retval.elename = @retval.elename.dup_name(@retval_name || 'return')
retval.parent = self
retval
end
def each
if @retval_name and !@retval.is_a?(SOAPVoid)
yield(@retval_name, @retval)
end
output_params.each do |name|
unless @outparam[name]
raise ParameterError.new("parameter: #{name} was not given")
end
yield(name, @outparam[name])
end
end
end
# To return(?) void explicitly.
# def foo(input_var)
# ...
# return SOAP::RPC::SOAPVoid.new
# end
class SOAPVoid < XSD::XSDAnySimpleType
include SOAPBasetype
extend SOAPModuleUtils
Name = XSD::QName.new(Mapping::RubyCustomTypeNamespace, nil)
public
def initialize()
@elename = Name
@id = nil
@precedents = []
@parent = nil
end
end
end
end

View file

@ -0,0 +1,169 @@
# SOAP4R - WEBrick HTTP Server
# Copyright (C) 2000-2007 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 'logger'
require 'soap/rpc/soaplet'
require 'soap/streamHandler'
require 'webrick'
module SOAP
module RPC
class HTTPServer < Logger::Application
attr_reader :server
attr_accessor :default_namespace
class << self
if RUBY_VERSION >= "1.7.0"
def __attr_proxy(symbol, assignable = false)
name = symbol.to_s
define_method(name) {
@router.__send__(name)
}
if assignable
aname = name + '='
define_method(aname) { |rhs|
@router.__send__(aname, rhs)
}
end
end
else
def __attr_proxy(symbol, assignable = false)
name = symbol.to_s
module_eval <<-EOS
def #{name}
@router.#{name}
end
EOS
if assignable
module_eval <<-EOS
def #{name}=(value)
@router.#{name} = value
end
EOS
end
end
end
end
__attr_proxy :mapping_registry, true
__attr_proxy :literal_mapping_registry, true
__attr_proxy :generate_explicit_type, true
__attr_proxy :use_default_namespace, true
def initialize(config)
actor = config[:SOAPHTTPServerApplicationName] || self.class.name
super(actor)
@default_namespace = config[:SOAPDefaultNamespace]
@webrick_config = config.dup
self.level = Logger::Severity::ERROR # keep silent by default
@webrick_config[:Logger] ||= @log
@log = @webrick_config[:Logger] # sync logger of App and HTTPServer
@router = ::SOAP::RPC::Router.new(actor)
@soaplet = ::SOAP::RPC::SOAPlet.new(@router)
on_init
@server = WEBrick::HTTPServer.new(@webrick_config)
@server.mount('/soaprouter', @soaplet)
if wsdldir = config[:WSDLDocumentDirectory]
@server.mount('/wsdl', WEBrick::HTTPServlet::FileHandler, wsdldir)
end
# for backward compatibility
@server.mount('/', @soaplet)
end
def on_init
# do extra initialization in a derived class if needed.
end
def status
@server.status if @server
end
def shutdown
@server.shutdown if @server
end
def authenticator
@soaplet.authenticator
end
def authenticator=(authenticator)
@soaplet.authenticator = authenticator
end
# servant entry interface
def add_rpc_request_servant(factory, namespace = @default_namespace)
@router.add_rpc_request_servant(factory, namespace)
end
def add_rpc_servant(obj, namespace = @default_namespace)
@router.add_rpc_servant(obj, namespace)
end
def add_request_headerhandler(factory)
@router.add_request_headerhandler(factory)
end
def add_headerhandler(obj)
@router.add_headerhandler(obj)
end
alias add_rpc_headerhandler add_headerhandler
def filterchain
@router.filterchain
end
# method entry interface
def add_rpc_method(obj, name, *param)
add_rpc_method_as(obj, name, name, *param)
end
alias add_method add_rpc_method
def add_rpc_method_as(obj, name, name_as, *param)
qname = XSD::QName.new(@default_namespace, name_as)
soapaction = nil
param_def = SOAPMethod.derive_rpc_param_def(obj, name, *param)
@router.add_rpc_operation(obj, qname, soapaction, name, param_def)
end
alias add_method_as add_rpc_method_as
def add_document_method(obj, soapaction, name, req_qnames, res_qnames)
param_def = SOAPMethod.create_doc_param_def(req_qnames, res_qnames)
@router.add_document_operation(obj, soapaction, name, param_def)
end
def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {})
@router.add_rpc_operation(receiver, qname, soapaction, name, param_def, opt)
end
def add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt = {})
@router.add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt)
end
def add_document_operation(receiver, soapaction, name, param_def, opt = {})
@router.add_document_operation(receiver, soapaction, name, param_def, opt)
end
def add_document_request_operation(factory, soapaction, name, param_def, opt = {})
@router.add_document_request_operation(factory, soapaction, name, param_def, opt)
end
private
def run
@server.start
end
end
end
end

View file

@ -0,0 +1,576 @@
# SOAP4R - RPC Proxy library.
# Copyright (C) 2000-2007 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 'soap/soap'
require 'soap/processor'
require 'soap/mapping'
require 'soap/mapping/literalregistry'
require 'soap/rpc/rpc'
require 'soap/rpc/element'
require 'soap/header/handlerset'
require 'soap/filter'
require 'soap/streamHandler'
require 'soap/mimemessage'
module SOAP
module RPC
class Proxy
include SOAP
public
attr_accessor :soapaction
attr_accessor :mandatorycharset
attr_accessor :allow_unqualified_element
attr_accessor :default_encodingstyle
attr_accessor :generate_explicit_type
attr_accessor :use_default_namespace
attr_accessor :return_response_as_xml
attr_reader :headerhandler
attr_reader :filterchain
attr_reader :streamhandler
attr_accessor :mapping_registry
attr_accessor :literal_mapping_registry
attr_reader :operation
def initialize(endpoint_url, soapaction, options)
@endpoint_url = endpoint_url
@soapaction = soapaction
@options = options
@protocol_option = options["protocol"] ||= ::SOAP::Property.new
initialize_streamhandler(@protocol_option)
@operation = {}
@operation_by_qname = {}
@operation_by_soapaction = {}
@mandatorycharset = nil
# TODO: set to false by default or drop thie option in 1.6.0
@allow_unqualified_element = true
@default_encodingstyle = nil
@generate_explicit_type = true
@use_default_namespace = false
@return_response_as_xml = false
@headerhandler = Header::HandlerSet.new
@filterchain = Filter::FilterChain.new
@mapping_registry = nil
@literal_mapping_registry = ::SOAP::Mapping::LiteralRegistry.new
end
def inspect
"#<#{self.class}:#{@endpoint_url}>"
end
def endpoint_url
@endpoint_url
end
def endpoint_url=(endpoint_url)
@endpoint_url = endpoint_url
reset_stream
end
def reset_stream
@streamhandler.reset(@endpoint_url)
end
def set_wiredump_file_base(wiredump_file_base)
@streamhandler.wiredump_file_base = wiredump_file_base
end
def test_loopback_response
@streamhandler.test_loopback_response
end
def add_rpc_operation(qname, soapaction, name, param_def, opt = {})
ensure_styleuse_option(opt, :rpc, :encoded)
opt[:request_qname] = qname
op = Operation.new(soapaction, param_def, opt)
assign_operation(name, qname, soapaction, op)
end
def add_document_operation(soapaction, name, param_def, opt = {})
ensure_styleuse_option(opt, :document, :literal)
op = Operation.new(soapaction, param_def, opt)
assign_operation(name, nil, soapaction, op)
end
# add_method is for shortcut of typical rpc/encoded method definition.
alias add_method add_rpc_operation
alias add_rpc_method add_rpc_operation
alias add_document_method add_document_operation
def invoke(req_header, req_body, opt = nil)
opt ||= create_encoding_opt
env = route(req_header, req_body, opt, opt)
if @return_response_as_xml
opt[:response_as_xml]
else
env
end
end
def call(name, *params)
# name must be used only for lookup
op_info = lookup_operation(name)
mapping_opt = create_mapping_opt
req_header = create_request_header
req_body = SOAPBody.new(
op_info.request_body(params, @mapping_registry,
@literal_mapping_registry, mapping_opt)
)
reqopt = create_encoding_opt(
:soapaction => op_info.soapaction || @soapaction,
:envelopenamespace => @options["soap.envelope.requestnamespace"],
:default_encodingstyle =>
@default_encodingstyle || op_info.request_default_encodingstyle,
:use_default_namespace =>
op_info.use_default_namespace || @use_default_namespace
)
resopt = create_encoding_opt(
:envelopenamespace => @options["soap.envelope.responsenamespace"],
:default_encodingstyle =>
@default_encodingstyle || op_info.response_default_encodingstyle
)
env = route(req_header, req_body, reqopt, resopt)
if op_info.response_use.nil?
return nil
end
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
if @return_response_as_xml
resopt[:response_as_xml]
else
op_info.response_obj(env.body, @mapping_registry,
@literal_mapping_registry, mapping_opt)
end
end
def route(req_header, req_body, reqopt, resopt)
req_env = ::SOAP::SOAPEnvelope.new(req_header, req_body)
unless reqopt[:envelopenamespace].nil?
set_envelopenamespace(req_env, reqopt[:envelopenamespace])
end
reqopt[:external_content] = nil
conn_data = marshal(req_env, reqopt)
if ext = reqopt[:external_content]
mime = MIMEMessage.new
ext.each do |k, v|
mime.add_attachment(v.data)
end
mime.add_part(conn_data.send_string + "\r\n")
mime.close
conn_data.send_string = mime.content_str
conn_data.send_contenttype = mime.headers['content-type'].str
end
conn_data = @streamhandler.send(@endpoint_url, conn_data,
reqopt[:soapaction])
if conn_data.receive_string.empty?
return nil
end
unmarshal(conn_data, resopt)
end
def check_fault(body)
if body.fault
raise SOAP::FaultError.new(body.fault)
end
end
private
def ensure_styleuse_option(opt, style, use)
if opt[:request_style] || opt[:response_style] || opt[:request_use] || opt[:response_use]
# do not edit
else
opt[:request_style] ||= style
opt[:response_style] ||= style
opt[:request_use] ||= use
opt[:response_use] ||= use
end
end
def initialize_streamhandler(options)
value = options["streamhandler"]
if value and !value.empty?
factory = Property::Util.const_from_name(value)
else
factory = HTTPStreamHandler
end
@streamhandler = factory.create(options)
options.add_hook("streamhandler") do |key, value|
@streamhandler.reset
if value.respond_to?(:create)
factory = value
elsif value and !value.to_str.empty?
factory = Property::Util.const_from_name(value.to_str)
else
factory = HTTPStreamHandler
end
options.unlock(true)
@streamhandler = factory.create(options)
end
end
def set_envelopenamespace(env, namespace)
env.elename = XSD::QName.new(namespace, env.elename.name)
if env.header
env.header.elename = XSD::QName.new(namespace, env.header.elename.name)
end
if env.body
env.body.elename = XSD::QName.new(namespace, env.body.elename.name)
end
end
def create_request_header
header = ::SOAP::SOAPHeader.new
items = @headerhandler.on_outbound(header)
items.each do |item|
header.add(item.elename.name, item)
end
header
end
def receive_headers(header)
@headerhandler.on_inbound(header) if header
end
def marshal(env, opt)
@filterchain.each do |filter|
env = filter.on_outbound(env, opt)
break unless env
end
send_string = Processor.marshal(env, opt)
StreamHandler::ConnectionData.new(send_string)
end
def unmarshal(conn_data, opt)
contenttype = conn_data.receive_contenttype
xml = nil
if /#{MIMEMessage::MultipartContentType}/i =~ contenttype
opt[:external_content] = {}
mime = MIMEMessage.parse("Content-Type: " + contenttype,
conn_data.receive_string)
mime.parts.each do |part|
value = Attachment.new(part.content)
value.contentid = part.contentid
obj = SOAPAttachment.new(value)
opt[:external_content][value.contentid] = obj if value.contentid
end
opt[:charset] = @mandatorycharset ||
StreamHandler.parse_media_type(mime.root.headers['content-type'].str)
xml = mime.root.content
else
opt[:charset] = @mandatorycharset ||
::SOAP::StreamHandler.parse_media_type(contenttype)
xml = conn_data.receive_string
end
@filterchain.reverse_each do |filter|
xml = filter.on_inbound(xml, opt)
break unless xml
end
env = Processor.unmarshal(xml, opt)
if @return_response_as_xml
opt[:response_as_xml] = xml
end
unless env.is_a?(::SOAP::SOAPEnvelope)
raise ResponseFormatError.new("response is not a SOAP envelope: #{env}")
end
env
end
def create_encoding_opt(hash = nil)
opt = {}
opt[:default_encodingstyle] = @default_encodingstyle
opt[:allow_unqualified_element] = @allow_unqualified_element
opt[:generate_explicit_type] = @generate_explicit_type
opt[:no_indent] = @options["soap.envelope.no_indent"]
opt[:use_numeric_character_reference] =
@options["soap.envelope.use_numeric_character_reference"]
opt.update(hash) if hash
opt
end
def create_mapping_opt(hash = nil)
opt = {
:external_ces => @options["soap.mapping.external_ces"]
}
opt.update(hash) if hash
opt
end
def assign_operation(name, qname, soapaction, op)
assigned = false
if name and !name.empty?
@operation[name] = op
assigned = true
end
if qname
@operation_by_qname[qname] = op
assigned = true
end
if soapaction and !soapaction.empty?
@operation_by_soapaction[soapaction] = op
assigned = true
end
unless assigned
raise MethodDefinitionError.new("cannot assign operation")
end
end
def lookup_operation(name_or_qname_or_soapaction)
if op = @operation[name_or_qname_or_soapaction]
return op
end
if op = @operation_by_qname[name_or_qname_or_soapaction]
return op
end
if op = @operation_by_soapaction[name_or_qname_or_soapaction]
return op
end
raise MethodDefinitionError.new(
"operation: #{name_or_qname_or_soapaction} not supported")
end
class Operation
attr_reader :soapaction
attr_reader :request_style
attr_reader :response_style
attr_reader :request_use
attr_reader :response_use
attr_reader :use_default_namespace
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]
@use_default_namespace =
opt[:use_default_namespace] || opt[:elementformdefault]
if opt.key?(:elementformdefault)
warn("option :elementformdefault is deprecated. use :use_default_namespace instead")
end
check_style(@request_style)
check_style(@response_style)
check_use(@request_use)
check_use(@response_use)
if @request_style == :rpc
@rpc_request_qname = opt[:request_qname]
if @rpc_request_qname.nil?
raise MethodDefinitionError.new("rpc_request_qname must be given")
end
@rpc_method_factory =
RPC::SOAPMethodRequest.new(@rpc_request_qname, param_def, @soapaction)
else
@doc_request_qnames = []
@doc_request_qualified = []
@doc_response_qnames = []
@doc_response_qualified = []
param_def.each do |inout, paramname, typeinfo, eleinfo|
klass_not_used, nsdef, namedef = typeinfo
qualified = eleinfo
if namedef.nil?
raise MethodDefinitionError.new("qname must be given")
end
case inout
when SOAPMethod::IN
@doc_request_qnames << XSD::QName.new(nsdef, namedef)
@doc_request_qualified << qualified
when SOAPMethod::OUT
@doc_response_qnames << XSD::QName.new(nsdef, namedef)
@doc_response_qualified << qualified
else
raise MethodDefinitionError.new(
"illegal inout definition for document style: #{inout}")
end
end
end
end
def request_default_encodingstyle
(@request_use == :encoded) ? EncodingNamespace : LiteralNamespace
end
def response_default_encodingstyle
(@response_use == :encoded) ? EncodingNamespace : LiteralNamespace
end
def request_body(values, mapping_registry, literal_mapping_registry, opt)
if @request_style == :rpc
request_rpc(values, mapping_registry, literal_mapping_registry, opt)
else
request_doc(values, mapping_registry, literal_mapping_registry, opt)
end
end
def response_obj(body, mapping_registry, literal_mapping_registry, opt)
if @response_style == :rpc
response_rpc(body, mapping_registry, literal_mapping_registry, opt)
else
unique_result_for_one_element_array(
response_doc(body, mapping_registry, literal_mapping_registry, opt))
end
end
def raise_fault(e, mapping_registry, literal_mapping_registry)
if @response_style == :rpc
Mapping.fault2exception(e, mapping_registry)
else
Mapping.fault2exception(e, literal_mapping_registry)
end
end
private
# nil for [] / 1 for [1] / [1, 2] for [1, 2]
def unique_result_for_one_element_array(ary)
ary.size <= 1 ? ary[0] : ary
end
def check_style(style)
unless [:rpc, :document].include?(style)
raise MethodDefinitionError.new("unknown style: #{style}")
end
end
# nil means oneway
def check_use(use)
unless [:encoded, :literal, nil].include?(use)
raise MethodDefinitionError.new("unknown use: #{use}")
end
end
def request_rpc(values, mapping_registry, literal_mapping_registry, opt)
if @request_use == :encoded
request_rpc_enc(values, mapping_registry, opt)
else
request_rpc_lit(values, literal_mapping_registry, opt)
end
end
def request_doc(values, mapping_registry, literal_mapping_registry, opt)
if @request_use == :encoded
request_doc_enc(values, mapping_registry, opt)
else
request_doc_lit(values, literal_mapping_registry, opt)
end
end
def request_rpc_enc(values, mapping_registry, opt)
method = @rpc_method_factory.dup
names = method.input_params
types = method.input_param_types
ary = Mapping.objs2soap(values, mapping_registry, types, opt)
soap = {}
0.upto(ary.length - 1) do |idx|
soap[names[idx]] = ary[idx]
end
method.set_param(soap)
method
end
def request_rpc_lit(values, mapping_registry, opt)
method = @rpc_method_factory.dup
names = method.input_params
types = method.get_paramtypes(names)
params = {}
idx = 0
names.each do |name|
params[name] = Mapping.obj2soap(values[idx], mapping_registry,
types[idx], opt)
params[name].elename = XSD::QName.new(nil, name)
idx += 1
end
method.set_param(params)
method
end
def request_doc_enc(values, mapping_registry, opt)
(0...values.size).collect { |idx|
ele = Mapping.obj2soap(values[idx], mapping_registry, nil, opt)
ele.elename = @doc_request_qnames[idx]
ele.qualified = @doc_request_qualified[idx]
ele
}
end
def request_doc_lit(values, mapping_registry, opt)
(0...values.size).collect { |idx|
ele = Mapping.obj2soap(values[idx], mapping_registry,
@doc_request_qnames[idx], opt)
ele.encodingstyle = LiteralNamespace
ele.qualified = @doc_request_qualified[idx]
ele
}
end
def response_rpc(body, mapping_registry, literal_mapping_registry, opt)
if @response_use == :encoded
response_rpc_enc(body, mapping_registry, opt)
else
response_rpc_lit(body, literal_mapping_registry, opt)
end
end
def response_doc(body, mapping_registry, literal_mapping_registry, opt)
if @response_use == :encoded
response_doc_enc(body, mapping_registry, opt)
else
response_doc_lit(body, literal_mapping_registry, opt)
end
end
def response_rpc_enc(body, mapping_registry, opt)
ret = nil
if body.response
ret = Mapping.soap2obj(body.response, mapping_registry,
@rpc_method_factory.retval_class_name, opt)
end
if body.outparams
outparams = body.outparams.collect { |outparam|
Mapping.soap2obj(outparam, mapping_registry, nil, opt)
}
[ret].concat(outparams)
else
ret
end
end
def response_rpc_lit(body, mapping_registry, opt)
body.root_node.collect { |key, value|
Mapping.soap2obj(value, mapping_registry,
@rpc_method_factory.retval_class_name, opt)
}
end
def response_doc_enc(body, mapping_registry, opt)
body.collect { |key, value|
Mapping.soap2obj(value, mapping_registry, nil, opt)
}
end
def response_doc_lit(body, mapping_registry, opt)
body.collect { |key, value|
Mapping.soap2obj(value, mapping_registry)
}
end
end
end
end
end

View file

@ -0,0 +1,669 @@
# SOAP4R - RPC Routing library
# Copyright (C) 2000-2007 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 'soap/soap'
require 'soap/processor'
require 'soap/mapping'
require 'soap/mapping/literalregistry'
require 'soap/rpc/rpc'
require 'soap/rpc/element'
require 'soap/header/handlerset'
require 'soap/filter'
require 'soap/streamHandler'
require 'soap/mimemessage'
require 'soap/header/handlerset'
module SOAP
module RPC
class Router
include SOAP
attr_reader :actor
attr_accessor :mapping_registry
attr_accessor :literal_mapping_registry
attr_accessor :generate_explicit_type
attr_accessor :use_default_namespace
attr_accessor :external_ces
attr_reader :filterchain
def initialize(actor)
@actor = actor
@mapping_registry = nil
@headerhandler = Header::HandlerSet.new
@literal_mapping_registry = ::SOAP::Mapping::LiteralRegistry.new
@generate_explicit_type = true
@use_default_namespace = false
@external_ces = nil
@operation_by_soapaction = {}
@operation_by_qname = {}
@headerhandlerfactory = []
@filterchain = Filter::FilterChain.new
end
###
## header handler interface
#
def add_request_headerhandler(factory)
unless factory.respond_to?(:create)
raise TypeError.new("factory must respond to 'create'")
end
@headerhandlerfactory << factory
end
def add_headerhandler(handler)
@headerhandler.add(handler)
end
###
## servant definition interface
#
def add_rpc_request_servant(factory, namespace)
unless factory.respond_to?(:create)
raise TypeError.new("factory must respond to 'create'")
end
obj = factory.create # a dummy instance for introspection
::SOAP::RPC.defined_methods(obj).each do |name|
begin
qname = XSD::QName.new(namespace, name)
param_def = ::SOAP::RPC::SOAPMethod.derive_rpc_param_def(obj, name)
opt = create_styleuse_option(:rpc, :encoded)
add_rpc_request_operation(factory, qname, nil, name, param_def, opt)
rescue SOAP::RPC::MethodDefinitionError => e
p e if $DEBUG
end
end
end
def add_rpc_servant(obj, namespace)
::SOAP::RPC.defined_methods(obj).each do |name|
begin
qname = XSD::QName.new(namespace, name)
param_def = ::SOAP::RPC::SOAPMethod.derive_rpc_param_def(obj, name)
opt = create_styleuse_option(:rpc, :encoded)
add_rpc_operation(obj, qname, nil, name, param_def, opt)
rescue SOAP::RPC::MethodDefinitionError => e
p e if $DEBUG
end
end
end
alias add_servant add_rpc_servant
###
## operation definition interface
#
def add_rpc_operation(receiver, qname, soapaction, name, param_def, opt = {})
ensure_styleuse_option(opt, :rpc, :encoded)
opt[:request_qname] = qname
op = ApplicationScopeOperation.new(soapaction, receiver, name, param_def,
opt)
if opt[:request_style] != :rpc
raise RPCRoutingError.new("illegal request_style given")
end
assign_operation(soapaction, qname, op)
end
alias add_method add_rpc_operation
alias add_rpc_method add_rpc_operation
def add_rpc_request_operation(factory, qname, soapaction, name, param_def, opt = {})
ensure_styleuse_option(opt, :rpc, :encoded)
opt[:request_qname] = qname
op = RequestScopeOperation.new(soapaction, factory, name, param_def, opt)
if opt[:request_style] != :rpc
raise RPCRoutingError.new("illegal request_style given")
end
assign_operation(soapaction, qname, op)
end
def add_document_operation(receiver, soapaction, name, param_def, opt = {})
#
# adopt workaround for doc/lit wrapper method
# (you should consider to simply use rpc/lit service)
#
#unless soapaction
# raise RPCRoutingError.new("soapaction is a must for document method")
#end
ensure_styleuse_option(opt, :document, :literal)
op = ApplicationScopeOperation.new(soapaction, receiver, name, param_def,
opt)
if opt[:request_style] != :document
raise RPCRoutingError.new("illegal request_style given")
end
assign_operation(soapaction, first_input_part_qname(param_def), op)
end
alias add_document_method add_document_operation
def add_document_request_operation(factory, soapaction, name, param_def, opt = {})
#
# adopt workaround for doc/lit wrapper method
# (you should consider to simply use rpc/lit service)
#
#unless soapaction
# raise RPCRoutingError.new("soapaction is a must for document method")
#end
ensure_styleuse_option(opt, :document, :literal)
op = RequestScopeOperation.new(soapaction, receiver, name, param_def, opt)
if opt[:request_style] != :document
raise RPCRoutingError.new("illegal request_style given")
end
assign_operation(soapaction, first_input_part_qname(param_def), op)
end
def route(conn_data)
# we cannot set request_default_encodingsyle before parsing the content.
env = unmarshal(conn_data)
if env.nil?
raise ArgumentError.new("illegal SOAP marshal format")
end
op = lookup_operation(conn_data.soapaction, env.body)
headerhandler = @headerhandler.dup
@headerhandlerfactory.each do |f|
headerhandler.add(f.create)
end
soap_response = default_encodingstyle = nil
begin
receive_headers(headerhandler, env.header)
soap_response =
op.call(env.body, @mapping_registry, @literal_mapping_registry,
create_mapping_opt)
conn_data.is_fault = true if soap_response.is_a?(SOAPFault)
default_encodingstyle = op.response_default_encodingstyle
rescue Exception => e
# If a wsdl fault was raised by service, the fault declaration details
# is kept in wsdl_fault. Otherwise (exception is a program fault)
# wsdl_fault is nil
wsdl_fault_details = op.faults && op.faults[e.class.name]
soap_response = fault(e, wsdl_fault_details)
conn_data.is_fault = true
default_encodingstyle = nil
end
header = call_headers(headerhandler)
if op.response_use.nil?
conn_data.send_string = ''
conn_data.is_nocontent = true
conn_data
else
body = SOAPBody.new(soap_response, conn_data.is_fault)
env = SOAPEnvelope.new(header, body)
marshal(conn_data, env, default_encodingstyle)
end
end
# Create fault response string.
def create_fault_response(e)
env = SOAPEnvelope.new(SOAPHeader.new, SOAPBody.new(fault(e, nil), true))
opt = {}
opt[:external_content] = nil
@filterchain.reverse_each do |filter|
env = filter.on_outbound(env, opt)
break unless env
end
response_string = Processor.marshal(env, opt)
conn_data = StreamHandler::ConnectionData.new(response_string)
conn_data.is_fault = true
if ext = opt[:external_content]
mimeize(conn_data, ext)
end
conn_data
end
private
def first_input_part_qname(param_def)
param_def.each do |inout, paramname, typeinfo|
if inout == SOAPMethod::IN
klass, nsdef, namedef = typeinfo
return XSD::QName.new(nsdef, namedef)
end
end
nil
end
def create_styleuse_option(style, use)
opt = {}
opt[:request_style] = opt[:response_style] = style
opt[:request_use] = opt[:response_use] = use
opt
end
def ensure_styleuse_option(opt, style, use)
if opt[:request_style] || opt[:response_style] || opt[:request_use] || opt[:response_use]
# do not edit
else
opt[:request_style] ||= style
opt[:response_style] ||= style
opt[:request_use] ||= use
opt[:response_use] ||= use
end
end
def assign_operation(soapaction, qname, op)
assigned = false
if soapaction and !soapaction.empty?
@operation_by_soapaction[soapaction] = op
assigned = true
end
if qname
@operation_by_qname[qname] = op
assigned = true
end
unless assigned
raise RPCRoutingError.new("cannot assign operation")
end
end
def lookup_operation(soapaction, body)
if op = @operation_by_soapaction[soapaction]
return op
end
qname = body.root_node.elename
if op = @operation_by_qname[qname]
return op
end
if soapaction
raise RPCRoutingError.new(
"operation: #{soapaction} #{qname} not supported")
else
raise RPCRoutingError.new("operation: #{qname} not supported")
end
end
def call_headers(headerhandler)
header = ::SOAP::SOAPHeader.new
items = headerhandler.on_outbound(header)
items.each do |item|
header.add(item.elename.name, item)
end
header
end
def receive_headers(headerhandler, header)
headerhandler.on_inbound(header) if header
end
def unmarshal(conn_data)
xml = nil
opt = {}
contenttype = conn_data.receive_contenttype
if /#{MIMEMessage::MultipartContentType}/i =~ contenttype
opt[:external_content] = {}
mime = MIMEMessage.parse("Content-Type: " + contenttype,
conn_data.receive_string)
mime.parts.each do |part|
value = Attachment.new(part.content)
value.contentid = part.contentid
obj = SOAPAttachment.new(value)
opt[:external_content][value.contentid] = obj if value.contentid
end
opt[:charset] =
StreamHandler.parse_media_type(mime.root.headers['content-type'].str)
xml = mime.root.content
else
opt[:charset] = ::SOAP::StreamHandler.parse_media_type(contenttype)
xml = conn_data.receive_string
end
@filterchain.each do |filter|
xml = filter.on_inbound(xml, opt)
break unless xml
end
env = Processor.unmarshal(xml, opt)
charset = opt[:charset]
conn_data.send_contenttype = "text/xml; charset=\"#{charset}\""
env
end
def marshal(conn_data, env, default_encodingstyle = nil)
opt = {}
opt[:external_content] = nil
opt[:default_encodingstyle] = default_encodingstyle
opt[:generate_explicit_type] = @generate_explicit_type
opt[:use_default_namespace] = @use_default_namespace
@filterchain.reverse_each do |filter|
env = filter.on_outbound(env, opt)
break unless env
end
response_string = Processor.marshal(env, opt)
conn_data.send_string = response_string
if ext = opt[:external_content]
mimeize(conn_data, ext)
end
conn_data
end
def mimeize(conn_data, ext)
mime = MIMEMessage.new
ext.each do |k, v|
mime.add_attachment(v.data)
end
mime.add_part(conn_data.send_string + "\r\n")
mime.close
conn_data.send_string = mime.content_str
conn_data.send_contenttype = mime.headers['content-type'].str
conn_data
end
# Create fault response.
def fault(e, wsdl_fault_details)
if e.is_a?(UnhandledMustUnderstandHeaderError)
faultcode = FaultCode::MustUnderstand
else
faultcode = FaultCode::Server
end
# If the exception represents a WSDL fault, the fault element should
# be added as the SOAP fault <detail> element. If the exception is a
# normal program exception, it is wrapped inside a custom SOAP4R
# SOAP exception element.
detail = nil
begin
if (wsdl_fault_details)
registry = wsdl_fault_details[:use] == "literal" ?
@literal_mapping_registry : @mapping_registry
faultQName = XSD::QName.new(
wsdl_fault_details[:ns], wsdl_fault_details[:name]
)
detail = Mapping.obj2soap(e, registry, faultQName)
# wrap fault element (SOAPFault swallows top-level element)
wrapper = SOAP::SOAPElement.new(faultQName)
wrapper.add(detail)
detail = wrapper
else
# Exception is a normal program exception. Wrap it.
detail = Mapping.obj2soap(Mapping::SOAPException.new(e),
@mapping_registry)
detail.elename ||= XSD::QName::EMPTY # for literal mappingregstry
end
rescue
detail = SOAPString.new("failed to serialize detail object: #{$!}")
end
SOAPFault.new(
SOAPElement.new(nil, faultcode),
SOAPString.new(e.to_s),
SOAPString.new(@actor),
detail)
end
def create_mapping_opt
{ :external_ces => @external_ces }
end
class Operation
attr_reader :name
attr_reader :soapaction
attr_reader :request_style
attr_reader :response_style
attr_reader :request_use
attr_reader :response_use
attr_reader :faults
def initialize(soapaction, name, param_def, opt)
@soapaction = soapaction
@name = name
@request_style = opt[:request_style]
@response_style = opt[:response_style]
@request_use = opt[:request_use]
@response_use = opt[:response_use]
@faults = opt[:faults]
check_style(@request_style)
check_style(@response_style)
check_use(@request_use)
check_use(@response_use)
if @response_style == :rpc
request_qname = opt[:request_qname] or raise
@rpc_method_factory =
RPC::SOAPMethodRequest.new(request_qname, param_def, @soapaction)
@rpc_response_qname = opt[:response_qname]
else
@doc_request_qnames = []
@doc_request_qualified = []
@doc_response_qnames = []
@doc_response_qualified = []
param_def.each do |inout, paramname, typeinfo, eleinfo|
klass, nsdef, namedef = typeinfo
qualified = eleinfo
case inout
when SOAPMethod::IN
@doc_request_qnames << XSD::QName.new(nsdef, namedef)
@doc_request_qualified << qualified
when SOAPMethod::OUT
@doc_response_qnames << XSD::QName.new(nsdef, namedef)
@doc_response_qualified << qualified
else
raise ArgumentError.new(
"illegal inout definition for document style: #{inout}")
end
end
end
end
def request_default_encodingstyle
(@request_use == :encoded) ? EncodingNamespace : LiteralNamespace
end
def response_default_encodingstyle
(@response_use == :encoded) ? EncodingNamespace : LiteralNamespace
end
def call(body, mapping_registry, literal_mapping_registry, opt)
if @request_style == :rpc
values = request_rpc(body, mapping_registry, literal_mapping_registry,
opt)
else
values = request_document(body, mapping_registry,
literal_mapping_registry, opt)
end
result = receiver.method(@name.intern).call(*values)
return result if result.is_a?(SOAPFault)
if @response_style == :rpc
response_rpc(result, mapping_registry, literal_mapping_registry, opt)
elsif @doc_response_qnames.empty?
# nothing to do
else
response_doc(result, mapping_registry, literal_mapping_registry, opt)
end
end
private
def receiver
raise NotImplementedError.new('must be defined in derived class')
end
def request_rpc(body, mapping_registry, literal_mapping_registry, opt)
request = body.request
unless request.is_a?(SOAPNameAccessible)
if request.is_a?(SOAPNil)
# SOAP::Lite/0.69 seems to send xsi:nil="true" element as a request.
request = SOAPStruct.new(request.elename)
else
raise RPCRoutingError.new("not an RPC style")
end
end
if @request_use == :encoded
request_rpc_enc(request, mapping_registry, opt)
else
request_rpc_lit(request, literal_mapping_registry, opt)
end
end
def request_document(body, mapping_registry, literal_mapping_registry, opt)
# ToDo: compare names with @doc_request_qnames
if @request_use == :encoded
request_doc_enc(body, mapping_registry, opt)
else
request_doc_lit(body, literal_mapping_registry, opt)
end
end
def request_rpc_enc(request, mapping_registry, opt)
param = Mapping.soap2obj(request, mapping_registry, nil, opt)
request.collect { |key, value|
param[key]
}
end
def request_rpc_lit(request, mapping_registry, opt)
request.collect { |key, value|
Mapping.soap2obj(value, mapping_registry, nil, opt)
}
end
def request_doc_enc(body, mapping_registry, opt)
body.collect { |key, value|
Mapping.soap2obj(value, mapping_registry, nil, opt)
}
end
def request_doc_lit(body, mapping_registry, opt)
body.collect { |key, value|
Mapping.soap2obj(value, mapping_registry, nil, opt)
}
end
def response_rpc(result, mapping_registry, literal_mapping_registry, opt)
if @response_use == :encoded
response_rpc_enc(result, mapping_registry, opt)
else
response_rpc_lit(result, literal_mapping_registry, opt)
end
end
def response_doc(result, mapping_registry, literal_mapping_registry, opt)
if @doc_response_qnames.size == 0
result = []
elsif @doc_response_qnames.size == 1
result = [result]
end
if result.size != @doc_response_qnames.size
raise "required #{@doc_response_qnames.size} responses " +
"but #{result.size} given"
end
if @response_use == :encoded
response_doc_enc(result, mapping_registry, opt)
else
response_doc_lit(result, literal_mapping_registry, opt)
end
end
def response_rpc_enc(result, mapping_registry, opt)
soap_response =
@rpc_method_factory.create_method_response(@rpc_response_qname)
if soap_response.have_outparam?
unless result.is_a?(Array)
raise RPCRoutingError.new("out parameter was not returned")
end
outparams = {}
i = 1
soap_response.output_params.each do |outparam|
outparams[outparam] = Mapping.obj2soap(result[i], mapping_registry,
nil, opt)
i += 1
end
soap_response.set_outparam(outparams)
soap_response.retval = Mapping.obj2soap(result[0], mapping_registry,
nil, opt)
else
soap_response.retval = Mapping.obj2soap(result, mapping_registry, nil,
opt)
end
soap_response
end
def response_rpc_lit(result, mapping_registry, opt)
soap_response =
@rpc_method_factory.create_method_response(@rpc_response_qname)
if soap_response.have_outparam?
unless result.is_a?(Array)
raise RPCRoutingError.new("out parameter was not returned")
end
outparams = {}
i = 1
soap_response.output_params.each do |outparam|
outparams[outparam] = Mapping.obj2soap(result[i], mapping_registry,
XSD::QName.new(nil, outparam), opt)
i += 1
end
soap_response.set_outparam(outparams)
soap_response.retval = Mapping.obj2soap(result[0], mapping_registry,
soap_response.elename, opt)
else
soap_response.retval = Mapping.obj2soap(result, mapping_registry,
soap_response.elename, opt)
end
soap_response
end
def response_doc_enc(result, mapping_registry, opt)
(0...result.size).collect { |idx|
ele = Mapping.obj2soap(result[idx], mapping_registry, nil, opt)
ele.elename = @doc_response_qnames[idx]
ele.qualified = @doc_response_qualified[idx]
ele
}
end
def response_doc_lit(result, mapping_registry, opt)
(0...result.size).collect { |idx|
ele = Mapping.obj2soap(result[idx], mapping_registry,
@doc_response_qnames[idx])
ele.encodingstyle = LiteralNamespace
ele.qualified = @doc_response_qualified[idx]
ele
}
end
def check_style(style)
unless [:rpc, :document].include?(style)
raise ArgumentError.new("unknown style: #{style}")
end
end
# nil means oneway
def check_use(use)
unless [:encoded, :literal, nil].include?(use)
raise ArgumentError.new("unknown use: #{use}")
end
end
end
class ApplicationScopeOperation < Operation
def initialize(soapaction, receiver, name, param_def, opt)
super(soapaction, name, param_def, opt)
@receiver = receiver
end
private
def receiver
@receiver
end
end
class RequestScopeOperation < Operation
def initialize(soapaction, receiver_factory, name, param_def, opt)
super(soapaction, name, param_def, opt)
unless receiver_factory.respond_to?(:create)
raise TypeError.new("factory must respond to 'create'")
end
@receiver_factory = receiver_factory
end
private
def receiver
@receiver_factory.create
end
end
end
end
end

View file

@ -0,0 +1,25 @@
# SOAP4R - RPC utility.
# Copyright (C) 2000-2007 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.
module SOAP
module RPC
ServerException = Mapping::MappedException
def self.defined_methods(obj)
if obj.is_a?(Module)
obj.methods - Module.methods
else
obj.methods - Object.instance_methods(true)
end
end
end
end

View file

@ -0,0 +1,210 @@
# SOAP4R - SOAP handler servlet for WEBrick
# Copyright (C) 2000-2007 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 'webrick/httpservlet/abstract'
require 'webrick/httpstatus'
require 'soap/rpc/router'
require 'soap/streamHandler'
begin
require 'stringio'
require 'zlib'
rescue LoadError
warn("Loading stringio or zlib failed. No gzipped response supported.") if $DEBUG
end
warn("Overriding WEBrick::Log#debug") if $DEBUG
require 'webrick/log'
module WEBrick
class Log < BasicLog
alias __debug debug
def debug(msg = nil)
if block_given? and msg.nil?
__debug(yield)
else
__debug(msg)
end
end
end
end
module SOAP
module RPC
class SOAPlet < WEBrick::HTTPServlet::AbstractServlet
public
attr_reader :options
attr_accessor :authenticator
def initialize(router = nil)
@router = router || ::SOAP::RPC::Router.new(self.class.name)
@options = {}
@authenticator = nil
@config = {}
end
# for backward compatibility
def app_scope_router
@router
end
# for backward compatibility
def add_servant(obj, namespace)
@router.add_rpc_servant(obj, namespace)
end
def allow_content_encoding_gzip=(allow)
@options[:allow_content_encoding_gzip] = allow
end
###
## Servlet interfaces for WEBrick.
#
def get_instance(config, *options)
@config = config
self
end
def require_path_info?
false
end
def do_GET(req, res)
res.header['Allow'] = 'POST'
raise WEBrick::HTTPStatus::MethodNotAllowed, "GET request not allowed"
end
def do_POST(req, res)
logger.debug { "SOAP request: " + req.body } if logger
if @authenticator
@authenticator.authenticate(req, res)
# you can check authenticated user with SOAP::RPC::SOAPlet.user
end
begin
conn_data = ::SOAP::StreamHandler::ConnectionData.new
setup_req(conn_data, req)
@router.external_ces = @options[:external_ces]
Mapping.protect_threadvars(:SOAPlet) do
SOAPlet.user = req.user
SOAPlet.cookies = req.cookies
conn_data = @router.route(conn_data)
setup_res(conn_data, req, res)
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
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
def self.cookies
get_variable(:Cookies)
end
def self.cookies=(cookies)
set_variable(:Cookies, cookies)
end
def self.user
get_variable(:User)
end
def self.user=(user)
set_variable(:User, user)
end
private
def self.get_variable(name)
if var = Thread.current[:SOAPlet]
var[name]
else
nil
end
end
def self.set_variable(name, value)
var = Thread.current[:SOAPlet] ||= {}
var[name] = value
end
def logger
@config[:Logger]
end
def setup_req(conn_data, req)
conn_data.receive_string = req.body
conn_data.receive_contenttype = req['content-type']
conn_data.soapaction = parse_soapaction(req.meta_vars['HTTP_SOAPACTION'])
end
def setup_res(conn_data, req, res)
res['content-type'] = conn_data.send_contenttype
cookies = SOAPlet.cookies
unless cookies.empty?
res['set-cookie'] = cookies.collect { |cookie| cookie.to_s }
end
if conn_data.is_nocontent
res.status = WEBrick::HTTPStatus::RC_ACCEPTED
res.body = ''
return
end
if conn_data.is_fault
res.status = WEBrick::HTTPStatus::RC_INTERNAL_SERVER_ERROR
end
if outstring = encode_gzip(req, conn_data.send_string)
res['content-encoding'] = 'gzip'
res['content-length'] = outstring.size
res.body = outstring
else
res.body = conn_data.send_string
end
end
def parse_soapaction(soapaction)
if !soapaction.nil? and !soapaction.empty?
if /^"(.+)"$/ =~ soapaction
return $1
end
end
nil
end
def encode_gzip(req, outstring)
unless encode_gzip?(req)
return nil
end
begin
ostream = StringIO.new
gz = Zlib::GzipWriter.new(ostream)
gz.write(outstring)
ostream.string
ensure
gz.close
end
end
def encode_gzip?(req)
@options[:allow_content_encoding_gzip] and defined?(::Zlib) and
req['accept-encoding'] and
req['accept-encoding'].split(/,\s*/).include?('gzip')
end
end
end
end

View file

@ -0,0 +1,43 @@
# SOAP4R - WEBrick Server
# Copyright (C) 2000-2007 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 'soap/rpc/httpserver'
module SOAP
module RPC
class StandaloneServer < HTTPServer
def initialize(appname, default_namespace, host = "0.0.0.0", port = 8080)
@appname = appname
@default_namespace = default_namespace
@host = host
@port = port
super(create_config)
end
alias add_servant add_rpc_servant
alias add_headerhandler add_rpc_headerhandler
private
def create_config
{
:BindAddress => @host,
:Port => @port,
:AccessLog => [],
:SOAPDefaultNamespace => @default_namespace,
:SOAPHTTPServerApplicationName => @appname,
}
end
end
end
end

View file

@ -0,0 +1,9 @@
# SOAP4R - RPC Routing library
# Copyright (C) 2000-2007 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 'soap/compat'

View file

@ -0,0 +1,9 @@
# SOAP4R - RPC utility.
# Copyright (C) 2000-2007 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 'soap/compat'

View file

@ -0,0 +1,9 @@
# SOAP4R - Server implementation
# Copyright (C) 2000-2007 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 'soap/compat'

View file

@ -0,0 +1,151 @@
# soap/soap.rb: SOAP4R - Base definitions.
# Copyright (C) 2000-2007 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/charset'
require 'soap/nestedexception'
module SOAP
VERSION = Version = '1.5.8'
PropertyName = 'soap/property'
EnvelopeNamespace = 'http://schemas.xmlsoap.org/soap/envelope/'
EncodingNamespace = 'http://schemas.xmlsoap.org/soap/encoding/'
LiteralNamespace = 'http://xml.apache.org/xml-soap/literalxml'
NextActor = 'http://schemas.xmlsoap.org/soap/actor/next'
EleEnvelope = 'Envelope'
EleHeader = 'Header'
EleBody = 'Body'
EleFault = 'Fault'
EleFaultString = 'faultstring'
EleFaultActor = 'faultactor'
EleFaultCode = 'faultcode'
EleFaultDetail = 'detail'
AttrMustUnderstand = 'mustUnderstand'
AttrEncodingStyle = 'encodingStyle'
AttrActor = 'actor'
AttrRoot = 'root'
AttrArrayType = 'arrayType'
AttrOffset = 'offset'
AttrPosition = 'position'
AttrHref = 'href'
AttrId = 'id'
ValueArray = 'Array'
EleEnvelopeName = XSD::QName.new(EnvelopeNamespace, EleEnvelope).freeze
EleHeaderName = XSD::QName.new(EnvelopeNamespace, EleHeader).freeze
EleBodyName = XSD::QName.new(EnvelopeNamespace, EleBody).freeze
EleFaultName = XSD::QName.new(EnvelopeNamespace, EleFault).freeze
EleFaultStringName = XSD::QName.new(nil, EleFaultString).freeze
EleFaultActorName = XSD::QName.new(nil, EleFaultActor).freeze
EleFaultCodeName = XSD::QName.new(nil, EleFaultCode).freeze
EleFaultDetailName = XSD::QName.new(nil, EleFaultDetail).freeze
AttrActorName = XSD::QName.new(EnvelopeNamespace, AttrActor).freeze
AttrMustUnderstandName = XSD::QName.new(EnvelopeNamespace, AttrMustUnderstand).freeze
AttrEncodingStyleName = XSD::QName.new(EnvelopeNamespace, AttrEncodingStyle).freeze
AttrRootName = XSD::QName.new(EncodingNamespace, AttrRoot).freeze
AttrArrayTypeName = XSD::QName.new(EncodingNamespace, AttrArrayType).freeze
AttrOffsetName = XSD::QName.new(EncodingNamespace, AttrOffset).freeze
AttrPositionName = XSD::QName.new(EncodingNamespace, AttrPosition).freeze
AttrHrefName = XSD::QName.new(nil, AttrHref).freeze
AttrIdName = XSD::QName.new(nil, AttrId).freeze
ValueArrayName = XSD::QName.new(EncodingNamespace, ValueArray).freeze
Base64Literal = 'base64'
MediaType = 'text/xml'
class Error < StandardError; include NestedException; end
class StreamError < Error; end
class HTTPStreamError < StreamError; end
class PostUnavailableError < HTTPStreamError; end
class MPostUnavailableError < HTTPStreamError; end
class ArrayIndexOutOfBoundsError < Error; end
class ArrayStoreError < Error; end
class RPCRoutingError < Error; end
class EmptyResponseError < Error; end
class ResponseFormatError < Error; end
class UnhandledMustUnderstandHeaderError < Error; end
module FaultCode
VersionMismatch = XSD::QName.new(EnvelopeNamespace, 'VersionMismatch').freeze
MustUnderstand = XSD::QName.new(EnvelopeNamespace, 'MustUnderstand').freeze
Client = XSD::QName.new(EnvelopeNamespace, 'Client').freeze
Server = XSD::QName.new(EnvelopeNamespace, 'Server').freeze
end
class FaultError < Error
attr_reader :faultcode
attr_reader :faultstring
attr_reader :faultactor
attr_accessor :detail
def initialize(fault)
@faultcode = fault.faultcode
@faultstring = fault.faultstring
@faultactor = fault.faultactor
@detail = fault.detail
super(self.to_s)
end
def to_s
str = nil
if @faultstring and @faultstring.respond_to?('data')
str = @faultstring.data
end
str || '(No faultstring)'
end
end
module Env
def self.getenv(name)
ENV[name.downcase] || ENV[name.upcase]
end
is_cgi = !getenv('request_method').nil?
HTTP_PROXY = is_cgi ? getenv('cgi_http_proxy') : getenv('http_proxy')
NO_PROXY = getenv('no_proxy')
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

@ -0,0 +1,9 @@
# SOAP4R - Standalone Server
# Copyright (C) 2000-2007 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 'soap/compat'

View file

@ -0,0 +1,302 @@
# SOAP4R - Stream handler.
# Copyright (C) 2000-2007 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 'soap/soap'
require 'soap/httpconfigloader'
require 'soap/filter/filterchain'
begin
require 'stringio'
require 'zlib'
rescue LoadError
warn("Loading stringio or zlib failed. No gzipped response support.") if $DEBUG
end
module SOAP
class StreamHandler
RUBY_VERSION_STRING = "ruby #{ RUBY_VERSION } (#{ RUBY_RELEASE_DATE }) [#{ RUBY_PLATFORM }]"
attr_reader :filterchain
class ConnectionData
attr_accessor :send_string
attr_accessor :send_contenttype
attr_accessor :receive_string
attr_accessor :receive_contenttype
attr_accessor :is_fault
attr_accessor :is_nocontent
attr_accessor :soapaction
def initialize(send_string = nil)
@send_string = send_string
@send_contenttype = nil
@receive_string = nil
@receive_contenttype = nil
@is_fault = false
@is_nocontent = false
@soapaction = nil
end
end
def initialize
@filterchain = Filter::FilterChain.new
end
def self.parse_media_type(str)
if /^#{ MediaType }(?:\s*;\s*charset=([^"]+|"[^"]+"))?$/i !~ str
return nil
end
charset = $1
charset.gsub!(/"/, '') if charset
charset || 'us-ascii'
end
def self.create_media_type(charset)
"#{ MediaType }; charset=#{ charset }"
end
def send(url, conn_data, soapaction = nil, charset = nil)
# send a ConnectionData to specified url.
# return value is a ConnectionData with receive_* property filled.
# You can fill values of given conn_data and return it.
end
def reset(url = nil)
# for initializing connection status if needed.
# return value is not expected.
end
def set_wiredump_file_base(wiredump_file_base)
# for logging. return value is not expected.
# Override it when you want.
raise NotImplementedError
end
def test_loopback_response
# for loopback testing. see HTTPStreamHandler for more detail.
# return value is an Array of loopback responses.
# Override it when you want.
raise NotImplementedError
end
end
class HTTPStreamHandler < StreamHandler
include SOAP
begin
require 'httpclient'
Client = HTTPClient
RETRYABLE = true
rescue LoadError
begin
require 'http-access2'
if HTTPAccess2::VERSION < "2.0"
raise LoadError.new("http-access/2.0 or later is required.")
end
Client = HTTPAccess2::Client
RETRYABLE = true
rescue LoadError
warn("Loading http-access2 failed. Net/http is used.") if $DEBUG
require 'soap/netHttpClient'
Client = SOAP::NetHttpClient
RETRYABLE = false
end
end
class HttpPostRequestFilter
def initialize(filterchain)
@filterchain = filterchain
end
def filter_request(req)
@filterchain.each do |filter|
filter.on_http_outbound(req)
end
end
def filter_response(req, res)
@filterchain.each do |filter|
filter.on_http_inbound(req, res)
end
end
end
public
attr_reader :client
attr_accessor :wiredump_file_base
MAX_RETRY_COUNT = 10 # [times]
def self.create(options)
new(options)
end
def initialize(options)
super()
@client = Client.new(nil, "SOAP4R/#{ Version }")
if @client.respond_to?(:request_filter)
@client.request_filter << HttpPostRequestFilter.new(@filterchain)
end
@wiredump_file_base = nil
@charset = @wiredump_dev = nil
@options = options
set_options
@client.debug_dev = @wiredump_dev
@cookie_store = nil
@accept_encoding_gzip = false
end
def test_loopback_response
@client.test_loopback_response
end
def accept_encoding_gzip=(allow)
@accept_encoding_gzip = allow
end
def inspect
"#<#{self.class}>"
end
def send(url, conn_data, soapaction = nil, charset = @charset)
conn_data.soapaction ||= soapaction # for backward conpatibility
conn_data = send_post(url, conn_data, charset)
@client.save_cookie_store if @cookie_store
conn_data
end
def reset(url = nil)
if url.nil?
@client.reset_all
else
@client.reset(url)
end
@client.save_cookie_store if @cookie_store
end
private
def set_options
@options["http"] ||= ::SOAP::Property.new
HTTPConfigLoader.set_options(@client, @options["http"])
@charset = @options["http.charset"] || XSD::Charset.xml_encoding_label
@options.add_hook("http.charset") do |key, value|
@charset = value
end
@wiredump_dev = @options["http.wiredump_dev"]
@options.add_hook("http.wiredump_dev") do |key, value|
@wiredump_dev = value
@client.debug_dev = @wiredump_dev
end
set_cookie_store_file(@options["http.cookie_store_file"])
@options.add_hook("http.cookie_store_file") do |key, value|
set_cookie_store_file(value)
end
ssl_config = @options["http.ssl_config"]
basic_auth = @options["http.basic_auth"]
auth = @options["http.auth"]
@options["http"].lock(true)
ssl_config.unlock
basic_auth.unlock
auth.unlock
end
def set_cookie_store_file(value)
value = nil if value and value.empty?
@cookie_store = value
@client.set_cookie_store(@cookie_store) if @cookie_store
end
def send_post(url, conn_data, charset)
conn_data.send_contenttype ||= StreamHandler.create_media_type(charset)
if @wiredump_file_base
filename = @wiredump_file_base + '_request.xml'
f = File.open(filename, "w")
f << conn_data.send_string
f.close
end
extheader = {}
extheader['Content-Type'] = conn_data.send_contenttype
extheader['SOAPAction'] = "\"#{ conn_data.soapaction }\""
extheader['Accept-Encoding'] = 'gzip' if send_accept_encoding_gzip?
send_string = conn_data.send_string
@wiredump_dev << "Wire dump:\n\n" if @wiredump_dev
begin
retry_count = 0
while true
res = @client.post(url, send_string, extheader)
if RETRYABLE and HTTP::Status.redirect?(res.status)
retry_count += 1
if retry_count >= MAX_RETRY_COUNT
raise HTTPStreamError.new("redirect count exceeded")
end
url = res.header["location"][0]
puts "redirected to #{url}" if $DEBUG
else
break
end
end
rescue
@client.reset(url)
raise
end
@wiredump_dev << "\n\n" if @wiredump_dev
receive_string = res.content
if @wiredump_file_base
filename = @wiredump_file_base + '_response.xml'
f = File.open(filename, "w")
f << receive_string
f.close
end
case res.status
when 405
raise PostUnavailableError.new("#{ res.status }: #{ res.reason }")
when 200, 202, 500
# Nothing to do. 202 is for oneway service.
else
raise HTTPStreamError.new("#{ res.status }: #{ res.reason }")
end
# decode gzipped content, if we know it's there from the headers
if res.respond_to?(:header) and !res.header['content-encoding'].empty? and
res.header['content-encoding'][0].downcase == 'gzip'
receive_string = decode_gzip(receive_string)
# otherwise check for the gzip header
elsif @accept_encoding_gzip && receive_string[0..1] == "\x1f\x8b"
receive_string = decode_gzip(receive_string)
end
conn_data.receive_string = receive_string
conn_data.receive_contenttype = res.contenttype
conn_data
end
def send_accept_encoding_gzip?
@accept_encoding_gzip and defined?(::Zlib)
end
def decode_gzip(instring)
unless send_accept_encoding_gzip?
raise HTTPStreamError.new("Gzipped response content.")
end
begin
gz = Zlib::GzipReader.new(StringIO.new(instring))
gz.read
ensure
gz.close
end
end
end
end

View file

@ -0,0 +1,597 @@
# SOAP4R - SOAP WSDL driver
# Copyright (C) 2000-2007 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/parser'
require 'wsdl/importer'
require 'xsd/qname'
require 'xsd/codegen/gensupport'
require 'soap/mapping/wsdlencodedregistry'
require 'soap/mapping/wsdlliteralregistry'
require 'soap/rpc/driver'
require 'wsdl/soap/methodDefCreator'
require 'wsdl/soap/classDefCreatorSupport'
require 'wsdl/soap/classNameCreator'
module SOAP
class WSDLDriverFactory
include WSDL::SOAP::ClassDefCreatorSupport
class FactoryError < StandardError; end
attr_reader :wsdl
def initialize(wsdl)
@wsdl = import(wsdl)
name_creator = WSDL::SOAP::ClassNameCreator.new
@modulepath = 'WSDLDriverFactory'
@methoddefcreator =
WSDL::SOAP::MethodDefCreator.new(@wsdl, name_creator, @modulepath, {})
end
def inspect
sprintf("#<%s:%s:0x%x\n\n%s>", self.class.name, @wsdl.name, __id__, dump_method_signatures)
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
# deprecated old interface
def create_driver(servicename = nil, portname = nil)
warn("WSDLDriverFactory#create_driver is deprecated. Use create_rpc_driver instead.")
port = find_port(servicename, portname)
WSDLDriver.new(@wsdl, port, nil)
end
# Backward compatibility.
alias createDriver create_driver
def dump_method_signatures(servicename = nil, portname = nil)
targetservice = XSD::QName.new(@wsdl.targetnamespace, servicename) if servicename
targetport = XSD::QName.new(@wsdl.targetnamespace, portname) if portname
sig = []
element_definitions = @wsdl.collect_elements
@wsdl.services.each do |service|
next if targetservice and service.name != targetservice
service.ports.each do |port|
next if targetport and port.name != targetport
sig << port.porttype.operations.collect { |operation|
dump_method_signature(operation, element_definitions).gsub(/^#/, ' ')
}.join("\n")
end
end
sig.join("\n")
end
private
def find_port(servicename = nil, portname = nil)
service = port = nil
if servicename
service = @wsdl.service(
XSD::QName.new(@wsdl.targetnamespace, servicename))
else
service = @wsdl.services[0]
end
if service.nil?
raise FactoryError.new("service #{servicename} not found in WSDL")
end
if portname
port = service.ports[XSD::QName.new(@wsdl.targetnamespace, portname)]
if port.nil?
raise FactoryError.new("port #{portname} not found in WSDL")
end
else
port = service.ports.find { |port| !port.soap_address.nil? }
if port.nil?
raise FactoryError.new("no ports have soap:address")
end
end
if port.soap_address.nil?
raise FactoryError.new("soap:address element not found in WSDL")
end
port
end
def init_driver(drv, port)
wsdl_elements = @wsdl.collect_elements
wsdl_types = @wsdl.collect_complextypes + @wsdl.collect_simpletypes
rpc_decode_typemap = wsdl_types +
@wsdl.soap_rpc_complextypes(port.find_binding)
drv.proxy.mapping_registry =
Mapping::WSDLEncodedRegistry.new(rpc_decode_typemap)
drv.proxy.literal_mapping_registry =
Mapping::WSDLLiteralRegistry.new(wsdl_types, wsdl_elements)
end
def add_operation(drv, port)
port.find_binding.operations.each do |op_bind|
op_name = op_bind.soapoperation_name
soapaction = op_bind.soapaction || ''
orgname = op_name.name
name = XSD::CodeGen::GenSupport.safemethodname(orgname)
param_def = create_param_def(op_bind)
opt = {
:request_style => op_bind.soapoperation_style,
:response_style => op_bind.soapoperation_style,
:request_use => op_bind.soapbody_use_input,
:response_use => op_bind.soapbody_use_output
}
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_type, name, param_type|
[io_type, name, ::SOAP::RPC::SOAPMethod.parse_param_type(param_type)]
}
end
def partqname(part)
if part.type
part.type
else
part.element
end
end
def param_def(type, name, klass, partqname)
[type, name, [klass, partqname.namespace, partqname.name]]
end
def filter_parts(partsdef, partssource)
parts = partsdef.split(/\s+/)
partssource.find_all { |part| parts.include?(part.name) }
end
end
class WSDLDriver
class << self
if RUBY_VERSION >= "1.7.0"
def __attr_proxy(symbol, assignable = false)
name = symbol.to_s
define_method(name) {
@servant.__send__(name)
}
if assignable
aname = name + '='
define_method(aname) { |rhs|
@servant.__send__(aname, rhs)
}
end
end
else
def __attr_proxy(symbol, assignable = false)
name = symbol.to_s
module_eval <<-EOS
def #{name}
@servant.#{name}
end
EOS
if assignable
module_eval <<-EOS
def #{name}=(value)
@servant.#{name} = value
end
EOS
end
end
end
end
__attr_proxy :options
__attr_proxy :headerhandler
__attr_proxy :streamhandler
__attr_proxy :test_loopback_response
__attr_proxy :endpoint_url, true
__attr_proxy :mapping_registry, true # for RPC unmarshal
__attr_proxy :wsdl_mapping_registry, true # for RPC marshal
__attr_proxy :default_encodingstyle, true
__attr_proxy :generate_explicit_type, true
__attr_proxy :allow_unqualified_element, true
def httpproxy
@servant.options["protocol.http.proxy"]
end
def httpproxy=(httpproxy)
@servant.options["protocol.http.proxy"] = httpproxy
end
def wiredump_dev
@servant.options["protocol.http.wiredump_dev"]
end
def wiredump_dev=(wiredump_dev)
@servant.options["protocol.http.wiredump_dev"] = wiredump_dev
end
def mandatorycharset
@servant.options["protocol.mandatorycharset"]
end
def mandatorycharset=(mandatorycharset)
@servant.options["protocol.mandatorycharset"] = mandatorycharset
end
def wiredump_file_base
@servant.options["protocol.wiredump_file_base"]
end
def wiredump_file_base=(wiredump_file_base)
@servant.options["protocol.wiredump_file_base"] = wiredump_file_base
end
def initialize(wsdl, port, logdev)
@servant = Servant__.new(self, wsdl, port, logdev)
end
def inspect
"#<#{self.class}:#{@servant.port.name}>"
end
def reset_stream
@servant.reset_stream
end
# Backward compatibility.
alias generateEncodeType= generate_explicit_type=
class Servant__
include SOAP
attr_reader :options
attr_reader :port
attr_accessor :soapaction
attr_accessor :default_encodingstyle
attr_accessor :allow_unqualified_element
attr_accessor :generate_explicit_type
attr_accessor :mapping_registry
attr_accessor :wsdl_mapping_registry
def initialize(host, wsdl, port, logdev)
@host = host
@wsdl = wsdl
@port = port
@logdev = logdev
@soapaction = nil
@options = setup_options
@default_encodingstyle = nil
@allow_unqualified_element = nil
@generate_explicit_type = false
@mapping_registry = nil # for rpc unmarshal
@wsdl_mapping_registry = nil # for rpc marshal
@wiredump_file_base = nil
@mandatorycharset = nil
@wsdl_elements = @wsdl.collect_elements
@wsdl_types = @wsdl.collect_complextypes + @wsdl.collect_simpletypes
@rpc_decode_typemap = @wsdl_types +
@wsdl.soap_rpc_complextypes(port.find_binding)
@wsdl_mapping_registry = Mapping::WSDLEncodedRegistry.new(
@rpc_decode_typemap)
@doc_mapper = Mapping::WSDLLiteralRegistry.new(
@wsdl_types, @wsdl_elements)
endpoint_url = @port.soap_address.location
# Convert a map which key is QName, to a Hash which key is String.
@operation = {}
@port.inputoperation_map.each do |op_name, op_info|
orgname = op_name.name
name = XSD::CodeGen::GenSupport.safemethodname(orgname)
@operation[name] = @operation[orgname] = op_info
add_method_interface(op_info)
end
@proxy = ::SOAP::RPC::Proxy.new(endpoint_url, @soapaction, @options)
end
def inspect
"#<#{self.class}:#{@proxy.inspect}>"
end
def endpoint_url
@proxy.endpoint_url
end
def endpoint_url=(endpoint_url)
@proxy.endpoint_url = endpoint_url
end
def headerhandler
@proxy.headerhandler
end
def streamhandler
@proxy.streamhandler
end
def test_loopback_response
@proxy.test_loopback_response
end
def reset_stream
@proxy.reset_stream
end
def rpc_call(name, *values)
set_wiredump_file_base(name)
unless op_info = @operation[name]
raise RuntimeError, "method: #{name} not defined"
end
req_header = create_request_header
req_body = create_request_body(op_info, *values)
reqopt = create_options({
:soapaction => op_info.soapaction || @soapaction})
resopt = create_options({
:decode_typemap => @rpc_decode_typemap})
env = @proxy.route(req_header, req_body, reqopt, resopt)
raise EmptyResponseError unless env
receive_headers(env.header)
begin
@proxy.check_fault(env.body)
rescue ::SOAP::FaultError => e
Mapping.fault2exception(e)
end
ret = env.body.response ?
Mapping.soap2obj(env.body.response, @mapping_registry) : nil
if env.body.outparams
outparams = env.body.outparams.collect { |outparam|
Mapping.soap2obj(outparam)
}
return [ret].concat(outparams)
else
return ret
end
end
# req_header: [[element, mustunderstand, encodingstyle(QName/String)], ...]
# req_body: SOAPBasetype/SOAPCompoundtype
def document_send(name, header_obj, body_obj)
set_wiredump_file_base(name)
unless op_info = @operation[name]
raise RuntimeError, "method: #{name} not defined"
end
req_header = header_obj ? header_from_obj(header_obj, op_info) : nil
req_body = body_from_obj(body_obj, op_info)
opt = create_options({
:soapaction => op_info.soapaction || @soapaction,
:decode_typemap => @wsdl_types})
env = @proxy.invoke(req_header, req_body, opt)
raise EmptyResponseError unless env
if env.body.fault
raise ::SOAP::FaultError.new(env.body.fault)
end
res_body_obj = env.body.response ?
Mapping.soap2obj(env.body.response, @mapping_registry) : nil
return env.header, res_body_obj
end
private
def create_options(hash = nil)
opt = {}
opt[:default_encodingstyle] = @default_encodingstyle
opt[:allow_unqualified_element] = @allow_unqualified_element
opt[:generate_explicit_type] = @generate_explicit_type
opt.update(hash) if hash
opt
end
def set_wiredump_file_base(name)
if @wiredump_file_base
@proxy.set_wiredump_file_base(@wiredump_file_base + "_#{name}")
end
end
def create_request_header
header = SOAPHeader.new
items = @proxy.headerhandler.on_outbound(header)
items.each do |item|
header.add(item.elename.name, item)
end
header
end
def receive_headers(header)
@proxy.headerhandler.on_inbound(header) if header
end
def create_request_body(op_info, *values)
method = create_method_struct(op_info, *values)
SOAPBody.new(method)
end
def create_method_struct(op_info, *params)
parts_names = op_info.bodyparts.collect { |part| part.name }
obj = create_method_obj(parts_names, params)
method = Mapping.obj2soap(obj, @wsdl_mapping_registry, op_info.op_name)
if method.members.size != parts_names.size
new_method = SOAPStruct.new
method.each do |key, value|
if parts_names.include?(key)
new_method.add(key, value)
end
end
method = new_method
end
method.elename = op_info.op_name
method.type = XSD::QName.new # Request should not be typed.
method
end
def create_method_obj(names, params)
o = Object.new
idx = 0
while idx < params.length
o.instance_variable_set('@' + names[idx], params[idx])
idx += 1
end
o
end
def header_from_obj(obj, op_info)
if obj.is_a?(SOAPHeader)
obj
elsif op_info.headerparts.empty?
if obj.nil?
nil
else
raise RuntimeError.new("no header definition in schema: #{obj}")
end
elsif op_info.headerparts.size == 1
part = op_info.headerparts[0]
header = SOAPHeader.new()
header.add(headeritem_from_obj(obj, part.element || part.eletype))
header
else
header = SOAPHeader.new()
op_info.headerparts.each do |part|
child = Mapping.get_attribute(obj, part.name)
ele = headeritem_from_obj(child, part.element || part.eletype)
header.add(part.name, ele)
end
header
end
end
def headeritem_from_obj(obj, name)
if obj.nil?
SOAPElement.new(name)
elsif obj.is_a?(SOAPHeaderItem)
obj
else
Mapping.obj2soap(obj, @doc_mapper, name)
end
end
def body_from_obj(obj, op_info)
if obj.is_a?(SOAPBody)
obj
elsif op_info.bodyparts.empty?
if obj.nil?
nil
else
raise RuntimeError.new("no body found in schema")
end
elsif op_info.bodyparts.size == 1
part = op_info.bodyparts[0]
ele = bodyitem_from_obj(obj, part.element || part.type)
SOAPBody.new(ele)
else
body = SOAPBody.new
op_info.bodyparts.each do |part|
child = Mapping.get_attribute(obj, part.name)
ele = bodyitem_from_obj(child, part.element || part.type)
body.add(ele.elename.name, ele)
end
body
end
end
def bodyitem_from_obj(obj, name)
if obj.nil?
SOAPElement.new(name)
elsif obj.is_a?(SOAPElement)
obj
else
Mapping.obj2soap(obj, @doc_mapper, name)
end
end
def add_method_interface(op_info)
name = XSD::CodeGen::GenSupport.safemethodname(op_info.op_name.name)
orgname = op_info.op_name.name
parts_names = op_info.bodyparts.collect { |part| part.name }
case op_info.style
when :document
if orgname != name and orgname.capitalize == name.capitalize
add_document_method_interface(orgname, parts_names)
end
add_document_method_interface(name, parts_names)
when :rpc
if orgname != name and orgname.capitalize == name.capitalize
add_rpc_method_interface(orgname, parts_names)
end
add_rpc_method_interface(name, parts_names)
else
raise RuntimeError.new("unknown style: #{op_info.style}")
end
end
def add_rpc_method_interface(name, parts_names)
param_count = parts_names.size
@host.instance_eval <<-EOS
def #{name}(*arg)
unless arg.size == #{param_count}
raise ArgumentError.new(
"wrong number of arguments (\#{arg.size} for #{param_count})")
end
@servant.rpc_call(#{name.dump}, *arg)
end
EOS
@host.method(name)
end
def add_document_method_interface(name, parts_names)
@host.instance_eval <<-EOS
def #{name}(h, b)
@servant.document_send(#{name.dump}, h, b)
end
EOS
@host.method(name)
end
def setup_options
if opt = Property.loadproperty(::SOAP::PropertyName)
opt = opt["client"]
end
opt ||= Property.new
opt.add_hook("protocol.mandatorycharset") do |key, value|
@mandatorycharset = value
end
opt.add_hook("protocol.wiredump_file_base") do |key, value|
@wiredump_file_base = value
end
opt["protocol.http.charset"] ||= XSD::Charset.xml_encoding_label
opt["protocol.http.proxy"] ||= Env::HTTP_PROXY
opt["protocol.http.no_proxy"] ||= Env::NO_PROXY
opt
end
end
end
end

5690
vendor/gems/soap4r-1.5.8/lib/tags vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,65 @@
# WSDL4R - WSDL binding definition.
# Copyright (C) 2000-2007 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 'xsd/namedelements'
module WSDL
class Binding < Info
attr_reader :name # required
attr_reader :type # required
attr_reader :operations
attr_reader :soapbinding
def initialize
super
@name = nil
@type = nil
@operations = XSD::NamedElements.new
@soapbinding = nil
end
def targetnamespace
parent.targetnamespace
end
def parse_element(element)
case element
when OperationName
o = OperationBinding.new
@operations << o
o
when SOAPBindingName
o = WSDL::SOAP::Binding.new
@soapbinding = o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(targetnamespace, value.source)
when TypeAttrName
@type = value
else
nil
end
end
end
end

View file

@ -0,0 +1,64 @@
# WSDL4R - WSDL data definitions.
# Copyright (C) 2000-2007 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 'wsdl/documentation'
require 'wsdl/definitions'
require 'wsdl/types'
require 'wsdl/message'
require 'wsdl/part'
require 'wsdl/portType'
require 'wsdl/operation'
require 'wsdl/param'
require 'wsdl/binding'
require 'wsdl/operationBinding'
require 'wsdl/service'
require 'wsdl/port'
require 'wsdl/import'
module WSDL
ArrayTypeAttrName = XSD::QName.new(Namespace, 'arrayType')
BindingName = XSD::QName.new(Namespace, 'binding')
DefinitionsName = XSD::QName.new(Namespace, 'definitions')
DocumentationName = XSD::QName.new(Namespace, 'documentation')
FaultName = XSD::QName.new(Namespace, 'fault')
ImportName = XSD::QName.new(Namespace, 'import')
InputName = XSD::QName.new(Namespace, 'input')
MessageName = XSD::QName.new(Namespace, 'message')
OperationName = XSD::QName.new(Namespace, 'operation')
OutputName = XSD::QName.new(Namespace, 'output')
PartName = XSD::QName.new(Namespace, 'part')
PortName = XSD::QName.new(Namespace, 'port')
PortTypeName = XSD::QName.new(Namespace, 'portType')
ServiceName = XSD::QName.new(Namespace, 'service')
TypesName = XSD::QName.new(Namespace, 'types')
SchemaName = XSD::QName.new(XSD::Namespace, 'schema')
SOAPAddressName = XSD::QName.new(SOAPBindingNamespace, 'address')
SOAPBindingName = XSD::QName.new(SOAPBindingNamespace, 'binding')
SOAPHeaderName = XSD::QName.new(SOAPBindingNamespace, 'header')
SOAPBodyName = XSD::QName.new(SOAPBindingNamespace, 'body')
SOAPFaultName = XSD::QName.new(SOAPBindingNamespace, 'fault')
SOAPOperationName = XSD::QName.new(SOAPBindingNamespace, 'operation')
BindingAttrName = XSD::QName.new(nil, 'binding')
ElementAttrName = XSD::QName.new(nil, 'element')
LocationAttrName = XSD::QName.new(nil, 'location')
MessageAttrName = XSD::QName.new(nil, 'message')
NameAttrName = XSD::QName.new(nil, 'name')
NamespaceAttrName = XSD::QName.new(nil, 'namespace')
ParameterOrderAttrName = XSD::QName.new(nil, 'parameterOrder')
TargetNamespaceAttrName = XSD::QName.new(nil, 'targetNamespace')
TypeAttrName = XSD::QName.new(nil, 'type')
end

View file

@ -0,0 +1,236 @@
# WSDL4R - WSDL definitions.
# Copyright (C) 2000-2007 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 'xsd/namedelements'
module WSDL
class Definitions < Info
attr_reader :name
attr_reader :targetnamespace
attr_reader :imports
attr_accessor :location
attr_reader :importedschema
def initialize
super
@name = nil
@targetnamespace = nil
@location = nil
@importedschema = {}
@types = nil
@imports = []
@messages = XSD::NamedElements.new
@porttypes = XSD::NamedElements.new
@bindings = XSD::NamedElements.new
@services = XSD::NamedElements.new
@anontypes = XSD::NamedElements.new
@root = self
end
def inspect
sprintf("#<%s:0x%x %s>", self.class.name, __id__, @name || '(unnamed)')
end
def targetnamespace=(targetnamespace)
@targetnamespace = targetnamespace
if @name
@name = XSD::QName.new(@targetnamespace, @name.name)
end
end
def collect_attributes
collect_imports(:collect_attributes)
end
def collect_modelgroups
collect_imports(:collect_modelgroups)
end
def collect_attributegroups
collect_imports(:collect_attributegroups)
end
def collect_elements
collect_imports(:collect_elements)
end
def collect_complextypes
result = collect_imports(:collect_complextypes)
@anontypes.dup.concat(result)
end
def collect_simpletypes
collect_imports(:collect_simpletypes)
end
# ToDo: simpletype must be accepted...
def add_type(complextype)
@anontypes << complextype
end
def messages
result = @messages.dup
@imports.each do |import|
result.concat(import.content.messages) if self.class === import.content
end
result
end
def porttypes
result = @porttypes.dup
@imports.each do |import|
result.concat(import.content.porttypes) if self.class === import.content
end
result
end
def bindings
result = @bindings.dup
@imports.each do |import|
result.concat(import.content.bindings) if self.class === import.content
end
result
end
def services
result = @services.dup
@imports.each do |import|
result.concat(import.content.services) if self.class === import.content
end
result
end
def message(name)
message = @messages[name]
return message if message
@imports.each do |import|
message = import.content.message(name) if self.class === import.content
return message if message
end
nil
end
def porttype(name)
porttype = @porttypes[name]
return porttype if porttype
@imports.each do |import|
porttype = import.content.porttype(name) if self.class === import.content
return porttype if porttype
end
nil
end
def binding(name)
binding = @bindings[name]
return binding if binding
@imports.each do |import|
binding = import.content.binding(name) if self.class === import.content
return binding if binding
end
nil
end
def service(name)
service = @services[name]
return service if service
@imports.each do |import|
service = import.content.service(name) if self.class === import.content
return service if service
end
nil
end
def porttype_binding(name)
binding = @bindings.find { |item| item.type == name }
return binding if binding
@imports.each do |import|
binding = import.content.porttype_binding(name) if self.class === import.content
return binding if binding
end
nil
end
def parse_element(element)
case element
when ImportName
o = Import.new
@imports << o
o
when TypesName
o = Types.new
@types = o
o
when MessageName
o = Message.new
@messages << o
o
when PortTypeName
o = PortType.new
@porttypes << o
o
when BindingName
o = Binding.new
@bindings << o
o
when ServiceName
o = Service.new
@services << o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(targetnamespace, value.source)
when TargetNamespaceAttrName
self.targetnamespace = value.source
else
nil
end
end
def self.parse_element(element)
if element == DefinitionsName
Definitions.new
else
nil
end
end
private
def collect_imports(method)
result = XSD::NamedElements.new
if @types
@types.schemas.each do |schema|
result.concat(schema.send(method))
end
end
@imports.each do |import|
result.concat(import.content.send(method))
end
result
end
end
end

View file

@ -0,0 +1,32 @@
# WSDL4R - WSDL SOAP documentation element.
# Copyright (C) 2000-2007 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'
module WSDL
class Documentation < Info
def initialize
super
end
def parse_element(element)
# Accepts any element.
self
end
def parse_attr(attr, value)
# Accepts any attribute.
true
end
end
end

View file

@ -0,0 +1,80 @@
# WSDL4R - WSDL import definition.
# Copyright (C) 2000-2007 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/importer'
module WSDL
class Import < Info
attr_reader :namespace
attr_reader :location
attr_reader :content
def initialize
super
@namespace = nil
@location = nil
@content = nil
@web_client = nil
end
def parse_element(element)
case element
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NamespaceAttrName
@namespace = value.source
if @content
@content.targetnamespace = @namespace
end
@namespace
when LocationAttrName
@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
if @namespace
@content.targetnamespace = @namespace
end
end
root.importedschema[@location] = @content
end
@location
else
nil
end
end
private
def import(location)
Importer.import(location, root)
end
end
end

View file

@ -0,0 +1,38 @@
# WSDL4R - WSDL importer library.
# Copyright (C) 2000-2007 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/xmlSchema/importer'
require 'wsdl/parser'
module WSDL
class Importer < WSDL::XMLSchema::Importer
def self.import(location, originalroot = nil)
new.import(location, originalroot)
end
private
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
end
end
end

View file

@ -0,0 +1,50 @@
# WSDL4R - WSDL information base.
# Copyright (C) 2000-2007 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.
module WSDL
class Info
attr_accessor :root
attr_accessor :parent
attr_accessor :id
def initialize
@root = nil
@parent = nil
@id = nil
end
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
def parse_attr(attr, value); end # abstract
def parse_epilogue; end # abstract
private
def to_int(value)
Integer(value.source)
end
def to_boolean(value)
s = value.source
s == "true" or s == "1"
end
end
end

View file

@ -0,0 +1,54 @@
# WSDL4R - WSDL message definition.
# Copyright (C) 2000-2007 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'
module WSDL
class Message < Info
attr_reader :name # required
attr_reader :parts
def initialize
super
@name = nil
@parts = []
end
def targetnamespace
parent.targetnamespace
end
def parse_element(element)
case element
when PartName
o = Part.new
@parts << o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(parent.targetnamespace, value.source)
else
nil
end
end
end
end

View file

@ -0,0 +1,178 @@
# WSDL4R - WSDL operation definition.
# Copyright (C) 2000-2007 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'
module WSDL
class Operation < Info
class NameInfo
attr_reader :op_name
attr_reader :optype_name
attr_reader :parts
def initialize(op_name, optype_name, parts)
@op_name = op_name
@optype_name = optype_name
@parts = parts
end
end
attr_reader :name # required
attr_reader :parameter_order # optional
attr_reader :input
attr_reader :output
attr_reader :fault
attr_reader :type # required
def initialize
super
@name = nil
@type = nil
@parameter_order = nil
@input = nil
@output = nil
@fault = []
end
def targetnamespace
parent.targetnamespace
end
def operationname
as_operationname(@name)
end
def input_info
if message = input_message
typename = message.name
else
typename = nil
end
NameInfo.new(operationname, typename, inputparts)
end
def output_info
if message = output_message
typename = message.name
else
typename = nil
end
NameInfo.new(operationname, typename, outputparts)
end
EMPTY = [].freeze
def inputparts
if message = input_message
sort_parts(message.parts)
else
EMPTY
end
end
def inputname
if input
as_operationname(input.name ? input.name.name : @name)
else
nil
end
end
def outputparts
if message = output_message
sort_parts(message.parts)
else
EMPTY
end
end
def outputname
if output
as_operationname(output.name ? output.name.name : @name + 'Response')
else
nil
end
end
def parse_element(element)
case element
when InputName
o = Param.new
@input = o
o
when OutputName
o = Param.new
@output = o
o
when FaultName
o = Param.new
@fault << o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = value.source
when TypeAttrName
@type = value
when ParameterOrderAttrName
@parameter_order = value.source.split(/\s+/)
else
nil
end
end
private
def input_message
if input and message = input.find_message
message
else
nil
end
end
def output_message
if output and message = output.find_message
message
else
nil
end
end
def sort_parts(parts)
return parts.dup unless parameter_order
result = []
parameter_order.each do |orderitem|
if (ele = parts.find { |part| part.name == orderitem })
result << ele
end
end
if result.length == 0
return parts.dup
end
# result length can be shorter than parts's.
# return part must not be a part of the parameterOrder.
result
end
def as_operationname(name)
XSD::QName.new(targetnamespace, name)
end
end
end

View file

@ -0,0 +1,130 @@
# WSDL4R - WSDL bound operation definition.
# Copyright (C) 2000-2007 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'
module WSDL
class OperationBinding < Info
attr_reader :name # required
attr_reader :input
attr_reader :output
attr_reader :fault
attr_reader :soapoperation
def initialize
super
@name = nil
@input = nil
@output = nil
@fault = []
@soapoperation = nil
end
def targetnamespace
parent.targetnamespace
end
def porttype
root.porttype(parent.type)
end
def find_operation
porttype.operations.each do |op|
next if op.name != @name
next if op.input and @input and op.input.name and @input.name and
op.input.name != @input.name
next if op.output and @output and op.output.name and @output.name and
op.output.name != @output.name
return op
end
raise RuntimeError.new("#{@name} not found")
end
def soapoperation_name
op_name = find_operation.operationname
if @input and @input.soapbody and @input.soapbody.namespace
op_name = XSD::QName.new(@input.soapbody.namespace, op_name.name)
end
op_name
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 soapbody_use_input
soapbody_use(@input)
end
def soapbody_use_output
soapbody_use(@output)
end
def soapaction
if @soapoperation
@soapoperation.soapaction
else
nil
end
end
def parse_element(element)
case element
when InputName
o = Param.new
@input = o
o
when OutputName
o = Param.new
@output = o
o
when FaultName
o = Param.new
@fault << o
o
when SOAPOperationName
o = WSDL::SOAP::Operation.new
@soapoperation = o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = value.source
else
nil
end
end
private
def soapbody_use(param)
param ? param.soapbody_use : nil
end
end
end

View file

@ -0,0 +1,93 @@
# WSDL4R - WSDL param definition.
# Copyright (C) 2000-2007 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'
module WSDL
class Param < Info
attr_reader :message # required
attr_reader :name # optional but required for fault.
attr_reader :soapbody
attr_reader :soapheader
attr_reader :soapfault
def initialize
super
@message = nil
@name = nil
@soapbody = nil
@soapheader = []
@soapfault = nil
end
def targetnamespace
parent.targetnamespace
end
def find_message
root.message(@message) or raise RuntimeError.new("#{@message} not found")
end
def soapbody_use
if @soapbody
@soapbody.use || :literal
else
nil
end
end
def soapbody_encodingstyle
if @soapbody
@soapbody.encodingstyle
else
nil
end
end
def parse_element(element)
case element
when SOAPBodyName
o = WSDL::SOAP::Body.new
@soapbody = o
o
when SOAPHeaderName
o = WSDL::SOAP::Header.new
@soapheader << o
o
when SOAPFaultName
o = WSDL::SOAP::Fault.new
@soapfault = o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
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)
else
nil
end
end
end
end

View file

@ -0,0 +1,164 @@
# WSDL4R - WSDL XML Instance parser library.
# Copyright (C) 2000-2007 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/charset'
require 'xsd/datatypes'
require 'xsd/xmlparser'
require 'soap/ns'
require 'wsdl/wsdl'
require 'wsdl/data'
require 'wsdl/xmlSchema/data'
require 'wsdl/soap/data'
module WSDL
class Parser
include WSDL
class ParseError < Error; end
class FormatDecodeError < ParseError; end
class UnknownElementError < FormatDecodeError; end
class UnknownAttributeError < FormatDecodeError; end
class UnexpectedElementError < FormatDecodeError; end
class ElementConstraintError < FormatDecodeError; end
class AttributeConstraintError < FormatDecodeError; end
private
class ParseFrame
attr_reader :ns
attr_reader :name
attr_accessor :node
private
def initialize(ns, name, node)
@ns = ns
@name = name
@node = node
end
end
public
def initialize(opt = {})
@parser = XSD::XMLParser.create_parser(self, opt)
@parsestack = nil
@lastnode = nil
@ignored = {}
@location = opt[:location]
@originalroot = opt[:originalroot]
end
def parse(string_or_readable)
@parsestack = []
@lastnode = nil
@textbuf = ''
@parser.do_parse(string_or_readable)
@lastnode
end
def charset
@parser.charset
end
def start_element(name, attrs)
lastframe = @parsestack.last
ns = parent = nil
if lastframe
ns = lastframe.ns
parent = lastframe.node
else
ns = ::SOAP::NS.new
parent = nil
end
# ns might be the same
ns, attrs = XSD::XMLParser.filter_ns(ns, attrs)
node = decode_tag(ns, name, attrs, parent)
@parsestack << ParseFrame.new(ns, name, node)
end
def characters(text)
lastframe = @parsestack.last
if lastframe
# Need not to be cloned because character does not have attr.
ns = lastframe.ns
decode_text(ns, text)
else
p text if $DEBUG
end
end
def end_element(name)
lastframe = @parsestack.pop
unless name == lastframe.name
raise UnexpectedElementError.new("closing element name '#{name}' does not match with opening element '#{lastframe.name}'")
end
decode_tag_end(lastframe.ns, lastframe.node)
@lastnode = lastframe.node
end
private
def decode_tag(ns, name, attrs, parent)
o = nil
elename = ns.parse(name)
if !parent
if elename == DefinitionsName
o = Definitions.parse_element(elename)
o.location = @location
else
raise UnknownElementError.new("unknown element: #{elename}")
end
o.root = @originalroot if @originalroot # o.root = o otherwise
else
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
if o.nil?
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|
attr_ele = ns.parse(key, true)
value_ele = ns.parse(value, false)
value_ele.source = value # for recovery; value may not be a QName
if o.parse_attr(attr_ele, value_ele).nil?
unless @ignored.key?(attr_ele)
warn("ignored attr: #{attr_ele}")
@ignored[attr_ele] = attr_ele
end
end
end
o
end
def decode_tag_end(ns, node)
node.parse_epilogue
end
def decode_text(ns, text)
@textbuf << text
end
end
end

View file

@ -0,0 +1,52 @@
# WSDL4R - WSDL part definition.
# Copyright (C) 2000-2007 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'
module WSDL
class Part < Info
attr_reader :name # required
attr_reader :element # optional
attr_reader :type # optional
def initialize
super
@name = nil
@element = nil
@type = nil
end
def parse_element(element)
case element
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = value.source
when ElementAttrName
@element = value
when TypeAttrName
@type = value
else
nil
end
end
end
end

View file

@ -0,0 +1,84 @@
# WSDL4R - WSDL port definition.
# Copyright (C) 2000-2007 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'
module WSDL
class Port < Info
attr_reader :name # required
attr_reader :binding # required
attr_reader :soap_address
def initialize
super
@name = nil
@binding = nil
@soap_address = nil
end
def targetnamespace
parent.targetnamespace
end
def porttype
root.porttype(find_binding.type)
end
def find_binding
root.binding(@binding) or raise RuntimeError.new("#{@binding} not found")
end
def inputoperation_map
result = {}
find_binding.operations.each do |op_bind|
op_info = op_bind.soapoperation.input_info
result[op_info.op_name] = op_info
end
result
end
def outputoperation_map
result = {}
find_binding.operations.each do |op_bind|
op_info = op_bind.soapoperation.output_info
result[op_info.op_name] = op_info
end
result
end
def parse_element(element)
case element
when SOAPAddressName
o = WSDL::SOAP::Address.new
@soap_address = o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(targetnamespace, value.source)
when BindingAttrName
@binding = value
else
nil
end
end
end
end

View file

@ -0,0 +1,75 @@
# WSDL4R - WSDL portType definition.
# Copyright (C) 2000-2007 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 'xsd/namedelements'
module WSDL
class PortType < Info
attr_reader :name # required
attr_reader :operations
def targetnamespace
parent.targetnamespace
end
def initialize
super
@name = nil
@operations = XSD::NamedElements.new
end
# may be nil if not defined
def find_binding
root.bindings.find { |item| item.type == @name }
end
def locations
binding = find_binding
return [] if binding.nil?
bind_name = binding.name
result = []
root.services.each do |service|
service.ports.each do |port|
if port.binding == bind_name
result << port.soap_address.location if port.soap_address
end
end
end
result
end
def parse_element(element)
case element
when OperationName
o = Operation.new
@operations << o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(targetnamespace, value.source)
else
nil
end
end
end
end

View file

@ -0,0 +1,61 @@
# WSDL4R - WSDL service definition.
# Copyright (C) 2000-2007 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 'xsd/namedelements'
module WSDL
class Service < Info
attr_reader :name # required
attr_reader :ports
attr_reader :soap_address
def initialize
super
@name = nil
@ports = XSD::NamedElements.new
@soap_address = nil
end
def targetnamespace
parent.targetnamespace
end
def parse_element(element)
case element
when PortName
o = Port.new
@ports << o
o
when SOAPAddressName
o = WSDL::SOAP::Address.new
@soap_address = o
o
when DocumentationName
o = Documentation.new
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(targetnamespace, value.source)
else
nil
end
end
end
end

View file

@ -0,0 +1,40 @@
# WSDL4R - WSDL SOAP address definition.
# Copyright (C) 2000-2007 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'
module WSDL
module SOAP
class Address < Info
attr_reader :location
def initialize
super
@location = nil
end
def parse_element(element)
nil
end
def parse_attr(attr, value)
case attr
when LocationAttrName
@location = value.source
else
nil
end
end
end
end
end

View file

@ -0,0 +1,49 @@
# WSDL4R - WSDL SOAP binding definition.
# Copyright (C) 2000-2007 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'
module WSDL
module SOAP
class Binding < Info
attr_reader :style
attr_reader :transport
def initialize
super
@style = nil
@transport = nil
end
def parse_element(element)
nil
end
def parse_attr(attr, value)
case attr
when StyleAttrName
if ["document", "rpc"].include?(value.source)
@style = value.source.intern
else
raise Parser::AttributeConstraintError.new(
"Unexpected value #{ value }.")
end
when TransportAttrName
@transport = value.source
else
nil
end
end
end
end
end

View file

@ -0,0 +1,58 @@
# WSDL4R - WSDL SOAP body definition.
# Copyright (C) 2000-2007 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'
module WSDL
module SOAP
class Body < Info
attr_reader :parts
attr_reader :use # required
attr_reader :encodingstyle
attr_reader :namespace
def initialize
super
@parts = nil
@use = nil
@encodingstyle = nil
@namespace = nil
end
def parse_element(element)
nil
end
def parse_attr(attr, value)
case attr
when PartsAttrName
@parts = value.source
when UseAttrName
if ['literal', 'encoded'].include?(value.source)
@use = value.source.intern
else
raise RuntimeError.new("unknown use of soap:body: #{value.source}")
end
when EncodingStyleAttrName
@encodingstyle = value.source
@encodingstyle = nil if @encodingstyle.to_s.empty?
value.source
when NamespaceAttrName
@namespace = value.source
else
nil
end
end
end
end
end

View file

@ -0,0 +1,93 @@
# WSDL4R - Creating CGI stub code from WSDL.
# Copyright (C) 2000-2007 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/soap/mappingRegistryCreator'
require 'wsdl/soap/methodDefCreator'
require 'wsdl/soap/classDefCreatorSupport'
module WSDL
module SOAP
class CGIStubCreator
include ClassDefCreatorSupport
attr_reader :definitions
def initialize(definitions, name_creator, modulepath = nil)
@definitions = definitions
@name_creator = name_creator
@modulepath = modulepath
end
def dump(service_name)
warn("CGI stub can have only 1 port. Creating stub for the first port... Rests are ignored.")
services = @definitions.service(service_name)
unless services
raise RuntimeError.new("service not defined: #{service_name}")
end
ports = services.ports
if ports.empty?
raise RuntimeError.new("ports not found for #{service_name}")
end
port = ports[0]
if port.porttype.nil?
raise RuntimeError.new("porttype not found for #{port}")
end
dump_porttype(port.porttype)
end
private
def dump_porttype(porttype)
class_name = mapped_class_name(porttype.name, @modulepath)
defined_const = {}
result = MethodDefCreator.new(@definitions, @name_creator, @modulepath, defined_const).dump(porttype.name)
methoddef = result[:methoddef]
wsdl_name = @definitions.name ? @definitions.name.name : 'default'
mrname = safeconstname(wsdl_name + 'MappingRegistry')
c1 = XSD::CodeGen::ClassDef.new(class_name)
c1.def_require("soap/rpc/cgistub")
c1.def_code <<-EOD
Methods = [
#{methoddef.gsub(/^/, " ")}
]
EOD
defined_const.each do |ns, tag|
c1.def_const(tag, dq(ns))
end
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 |definitions|
opt = definitions.last
if opt[:request_style] == :document
@router.add_document_operation(servant, *definitions)
else
@router.add_rpc_operation(servant, *definitions)
end
end
self.mapping_registry = #{mrname}::EncodedRegistry
self.literal_mapping_registry = #{mrname}::LiteralRegistry
self.level = Logger::Severity::ERROR
EOD
end
c1.dump + "\n" + c2.dump + format(<<-EOD)
#{class_name}App.new('app', nil).start
EOD
end
end
end
end

View file

@ -0,0 +1,433 @@
# WSDL4R - Creating class definition from WSDL
# Copyright (C) 2000-2007 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/data'
require 'wsdl/soap/classDefCreatorSupport'
require 'xsd/codegen'
require 'set'
module WSDL
module SOAP
class ClassDefCreator
include ClassDefCreatorSupport
include XSD::CodeGen
def initialize(definitions, name_creator, modulepath = nil)
@definitions = definitions
@name_creator = name_creator
@modulepath = modulepath
@elements = definitions.collect_elements
@elements.uniq!
@attributes = definitions.collect_attributes
@attributes.uniq!
@simpletypes = definitions.collect_simpletypes
@simpletypes.uniq!
@complextypes = definitions.collect_complextypes
@complextypes.uniq!
@modelgroups = definitions.collect_modelgroups
@modelgroups.uniq!
@faulttypes = nil
if definitions.respond_to?(:collect_faulttypes)
@faulttypes = definitions.collect_faulttypes
end
@defined_const = {}
end
def dump(type = nil)
result = "require 'xsd/qname'\n"
# cannot use @modulepath because of multiple classes
if @modulepath
result << "\n"
result << modulepath_split(@modulepath).collect { |ele| "module #{ele}" }.join("; ")
result << "\n\n"
end
if type
result << dump_classdef(type.name, type)
else
str = dump_group
unless str.empty?
result << "\n" unless result.empty?
result << str
end
str = dump_complextype
unless str.empty?
result << "\n" unless result.empty?
result << str
end
str = dump_simpletype
unless str.empty?
result << "\n" unless result.empty?
result << str
end
str = dump_element
unless str.empty?
result << "\n" unless result.empty?
result << str
end
str = dump_attribute
unless str.empty?
result << "\n" unless result.empty?
result << str
end
end
if @modulepath
result << "\n\n"
result << modulepath_split(@modulepath).collect { |ele| "end" }.join("; ")
result << "\n"
end
result
end
private
def dump_element
@elements.collect { |ele|
next if @complextypes[ele.name]
c = create_elementdef(@modulepath, ele)
c ? c.dump : nil
}.compact.join("\n")
end
def dump_attribute
@attributes.collect { |attribute|
if attribute.local_simpletype
c = create_simpletypedef(@modulepath, attribute.name, attribute.local_simpletype)
end
c ? c.dump : nil
}.compact.join("\n")
end
def dump_simpletype
@simpletypes.collect { |type|
c = create_simpletypedef(@modulepath, type.name, type)
c ? c.dump : nil
}.compact.join("\n")
end
def dump_complextype
definitions = sort_dependency(@complextypes).collect { |type|
c = create_complextypedef(@modulepath, type.name, type)
c ? c.dump : nil
}.compact.join("\n")
end
def dump_group
definitions = @modelgroups.collect { |group|
# TODO: not dumped for now but may be useful in the future
}.compact.join("\n")
end
def create_elementdef(mpath, ele)
qualified = (ele.elementform == 'qualified')
if ele.local_complextype
create_complextypedef(mpath, ele.name, ele.local_complextype, qualified)
elsif ele.local_simpletype
create_simpletypedef(mpath, ele.name, ele.local_simpletype, qualified)
elsif ele.empty?
create_simpleclassdef(mpath, ele.name, nil)
else
# ignores type only element
nil
end
end
def create_simpletypedef(mpath, qname, simpletype, qualified = false)
if simpletype.restriction
create_simpletypedef_restriction(mpath, qname, simpletype, qualified)
elsif simpletype.list
create_simpletypedef_list(mpath, qname, simpletype, qualified)
elsif simpletype.union
create_simpletypedef_union(mpath, qname, simpletype, qualified)
else
raise RuntimeError.new("unknown kind of simpletype: #{simpletype}")
end
end
def create_simpletypedef_restriction(mpath, qname, typedef, qualified)
restriction = typedef.restriction
unless restriction.enumeration?
# not supported. minlength?
return nil
end
classname = mapped_class_basename(qname, mpath)
c = ClassDef.new(classname, '::String')
c.comment = "#{qname}"
define_classenum_restriction(c, classname, restriction.enumeration)
c
end
def create_simpletypedef_list(mpath, qname, typedef, qualified)
list = typedef.list
classname = mapped_class_basename(qname, mpath)
c = ClassDef.new(classname, '::Array')
c.comment = "#{qname}"
if simpletype = list.local_simpletype
if simpletype.restriction.nil?
raise RuntimeError.new(
"unknown kind of simpletype: #{simpletype}")
end
define_stringenum_restriction(c, simpletype.restriction.enumeration)
c.comment << "\n contains list of #{classname}::*"
elsif list.itemtype
c.comment << "\n contains list of #{mapped_class_basename(list.itemtype, mpath)}::*"
else
raise RuntimeError.new("unknown kind of list: #{list}")
end
c
end
def create_simpletypedef_union(mpath, qname, typedef, qualified)
union = typedef.union
classname = mapped_class_basename(qname, mpath)
c = ClassDef.new(classname, '::String')
c.comment = "#{qname}"
if union.member_types
# fixme
c.comment << "\n any of #{union.member_types}"
end
c
end
def define_stringenum_restriction(c, enumeration)
const = {}
enumeration.each do |value|
constname = safeconstname(value)
const[constname] ||= 0
if (const[constname] += 1) > 1
constname += "_#{const[constname]}"
end
c.def_const(constname, ndq(value))
end
end
def define_classenum_restriction(c, classname, enumeration)
const = {}
enumeration.each do |value|
constname = safeconstname(value)
const[constname] ||= 0
if (const[constname] += 1) > 1
constname += "_#{const[constname]}"
end
c.def_const(constname, "#{classname}.new(#{ndq(value)})")
end
end
def create_simpleclassdef(mpath, qname, type_or_element)
classname = mapped_class_basename(qname, mpath)
c = ClassDef.new(classname, '::String')
c.comment = "#{qname}"
init_lines = []
if type_or_element and !type_or_element.attributes.empty?
define_attribute(c, type_or_element.attributes)
init_lines << "@__xmlattr = {}"
end
c.def_method('initialize', '*arg') do
"super\n" + init_lines.join("\n")
end
c
end
def create_complextypedef(mpath, qname, type, qualified = false)
case type.compoundtype
when :TYPE_STRUCT, :TYPE_EMPTY
create_structdef(mpath, qname, type, qualified)
when :TYPE_ARRAY
create_arraydef(mpath, qname, type)
when :TYPE_SIMPLE
create_simpleclassdef(mpath, qname, type)
when :TYPE_MAP
# mapped as a general Hash
nil
else
raise RuntimeError.new(
"unknown kind of complexContent: #{type.compoundtype}")
end
end
def create_structdef(mpath, qname, typedef, qualified = false)
classname = mapped_class_basename(qname, mpath)
baseclassname = nil
if typedef.complexcontent
if base = typedef.complexcontent.base
# :TYPE_ARRAY must not be derived (#424)
basedef = @complextypes[base]
if basedef and basedef.compoundtype != :TYPE_ARRAY
# baseclass should be a toplevel complexType
baseclassname = mapped_class_basename(base, @modulepath)
end
end
end
if @faulttypes and @faulttypes.index(qname)
c = ClassDef.new(classname, '::StandardError')
else
c = ClassDef.new(classname, baseclassname)
end
c.comment = "#{qname}"
c.comment << "\nabstract" if typedef.abstract
parentmodule = mapped_class_name(qname, mpath)
init_lines, init_params =
parse_elements(c, typedef.elements, qname.namespace, parentmodule)
unless typedef.attributes.empty?
define_attribute(c, typedef.attributes)
init_lines << "@__xmlattr = {}"
end
c.def_method('initialize', *init_params) do
init_lines.join("\n")
end
c
end
def parse_elements(c, elements, base_namespace, mpath, as_array = false)
init_lines = []
init_params = []
any = false
elements.each do |element|
case element
when XMLSchema::Any
# only 1 <any/> is allowed for now.
raise RuntimeError.new("duplicated 'any'") if any
any = true
attrname = '__xmlele_any'
c.def_attr(attrname, false, attrname)
c.def_method('set_any', 'elements') do
'@__xmlele_any = elements'
end
init_lines << "@__xmlele_any = nil"
when XMLSchema::Element
next if element.ref == SchemaName
name = name_element(element).name
typebase = @modulepath
if element.anonymous_type?
inner = create_elementdef(mpath, element)
unless as_array
inner.comment = "inner class for member: #{name}\n" + inner.comment
end
c.innermodule << inner
typebase = mpath
end
unless as_array
attrname = safemethodname(name)
varname = safevarname(name)
c.def_attr(attrname, true, varname)
init_lines << "@#{varname} = #{varname}"
if element.map_as_array?
init_params << "#{varname} = []"
else
init_params << "#{varname} = nil"
end
c.comment << "\n #{attrname} - #{create_type_name(typebase, element) || '(any)'}"
end
when WSDL::XMLSchema::Sequence
child_init_lines, child_init_params =
parse_elements(c, element.elements, base_namespace, mpath, as_array)
init_lines.concat(child_init_lines)
init_params.concat(child_init_params)
when WSDL::XMLSchema::Choice
child_init_lines, child_init_params =
parse_elements(c, element.elements, base_namespace, mpath, as_array)
init_lines.concat(child_init_lines)
init_params.concat(child_init_params)
when WSDL::XMLSchema::Group
if element.content.nil?
warn("no group definition found: #{element}")
next
end
child_init_lines, child_init_params =
parse_elements(c, element.content.elements, base_namespace, mpath, as_array)
init_lines.concat(child_init_lines)
init_params.concat(child_init_params)
else
raise RuntimeError.new("unknown type: #{element}")
end
end
[init_lines, init_params]
end
def define_attribute(c, attributes)
const = {}
unless attributes.empty?
c.def_method("__xmlattr") do <<-__EOD__
@__xmlattr ||= {}
__EOD__
end
end
attributes.each do |attribute|
name = name_attribute(attribute)
methodname = safemethodname('xmlattr_' + name.name)
constname = 'Attr' + safeconstname(name.name)
const[constname] ||= 0
if (const[constname] += 1) > 1
constname += "_#{const[constname]}"
end
c.def_const(constname, dqname(name))
c.def_method(methodname) do <<-__EOD__
__xmlattr[#{constname}]
__EOD__
end
c.def_method(methodname + '=', 'value') do <<-__EOD__
__xmlattr[#{constname}] = value
__EOD__
end
c.comment << "\n #{methodname} - #{attribute_basetype(attribute) || '(any)'}"
end
end
def create_arraydef(mpath, qname, typedef)
classname = mapped_class_basename(qname, mpath)
c = ClassDef.new(classname, '::Array')
c.comment = "#{qname}"
parentmodule = mapped_class_name(qname, mpath)
parse_elements(c, typedef.elements, qname.namespace, parentmodule, true)
c
end
def sort_dependency(types)
dep = {}
root = []
types.each do |type|
if type.complexcontent and (base = type.complexcontent.base)
dep[base] ||= []
dep[base] << type
else
root << type
end
end
sorted = []
root.each do |type|
sorted.concat(collect_dependency(type, dep))
end
sorted.concat(dep.values.flatten)
sorted
end
# removes collected key from dep
def collect_dependency(type, dep)
result = [type]
return result unless dep.key?(type.name)
dep[type.name].each do |deptype|
result.concat(collect_dependency(deptype, dep))
end
dep.delete(type.name)
result
end
def modulepath_split(modulepath)
if modulepath.is_a?(::Array)
modulepath
else
modulepath.to_s.split('::')
end
end
end
end
end

View file

@ -0,0 +1,230 @@
# WSDL4R - Creating class code support from WSDL.
# Copyright (C) 2000-2007 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 'soap/mapping'
require 'soap/mapping/typeMap'
require 'xsd/codegen/gensupport'
module WSDL
module SOAP
# requires @defined_const, @simpletypes, @name_creator
module ClassDefCreatorSupport
include XSD::CodeGen::GenSupport
def mapped_class_name(qname, modulepath)
@name_creator.assign_name(qname, modulepath)
end
def mapped_class_basename(qname, modulepath)
classname = @name_creator.assign_name(qname, modulepath)
classname.sub(/\A.*:/, '')
end
def basetype_mapped_class(name)
::SOAP::TypeMap[name]
end
def dump_method_signature(operation, element_definitions)
name = operation.name
input = operation.input
output = operation.output
fault = operation.fault
signature = "#{ name }#{ dump_inputparam(input) }"
str = <<__EOD__
# SYNOPSIS
# #{name}#{dump_inputparam(input)}
#
# ARGS
#{dump_inout_type(input, element_definitions).chomp}
#
# RETURNS
#{dump_inout_type(output, element_definitions).chomp}
#
__EOD__
unless fault.empty?
str <<<<__EOD__
# RAISES
#{dump_fault_type(fault, element_definitions)}
#
__EOD__
end
str
end
def dq(ele)
ele.dump
end
def ndq(ele)
ele.nil? ? 'nil' : dq(ele)
end
def sym(ele)
':' + ele.id2name
end
def nsym(ele)
ele.nil? ? 'nil' : sym(ele)
end
def dqname(qname)
if @defined_const.key?(qname.namespace)
qname.dump(@defined_const[qname.namespace])
else
qname.dump
end
end
def assign_const(value, prefix = '')
return if value.nil? or @defined_const.key?(value)
name = value.scan(/[^:\/]+\/?\z/)[0] || 'C'
tag = prefix + safeconstname(name)
if @defined_const.value?(tag)
idx = 0
while true
tag = prefix + safeconstname(name + "_#{idx}")
break unless @defined_const.value?(tag)
idx += 1
raise RuntimeError.new("too much similar names") if idx > 100
end
end
@defined_const[value] = tag
end
def create_type_name(modulepath, element)
if element.type == XSD::AnyTypeName
# nil means anyType.
nil
elsif simpletype = @simpletypes[element.type]
if simpletype.restriction and simpletype.restriction.enumeration?
mapped_class_name(element.type, modulepath)
else
nil
end
elsif klass = element_basetype(element)
klass.name
elsif element.type
mapped_class_name(element.type, modulepath)
elsif element.ref
mapped_class_name(element.ref, modulepath)
elsif element.anonymous_type?
# inner class
mapped_class_name(element.name, modulepath)
else
nil
end
end
private
def dump_inout_type(param, element_definitions)
if param
message = param.find_message
params = ""
message.parts.each do |part|
name = safevarname(part.name)
if part.type
typename = safeconstname(part.type.name)
qname = part.type
params << add_at("# #{name}", "#{typename} - #{qname}\n", 20)
elsif part.element
ele = element_definitions[part.element]
if ele.type
typename = safeconstname(ele.type.name)
qname = ele.type
else
typename = safeconstname(ele.name.name)
qname = ele.name
end
params << add_at("# #{name}", "#{typename} - #{qname}\n", 20)
end
end
unless params.empty?
return params
end
end
"# N/A\n"
end
def dump_inputparam(input)
message = input.find_message
params = ""
message.parts.each do |part|
params << ", " unless params.empty?
params << safevarname(part.name)
end
if params.empty?
""
else
"(#{ params })"
end
end
def add_at(base, str, pos)
if base.size >= pos
base + ' ' + str
else
base + ' ' * (pos - base.size) + str
end
end
def dump_fault_type(fault, element_definitions)
fault.collect { |ele|
dump_inout_type(ele, element_definitions).chomp
}.join("\n")
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)
return nil if type.nil?
if simpletype = @simpletypes[type]
basetype_mapped_class(simpletype.base)
else
basetype_mapped_class(type)
end
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
end
end
end

View file

@ -0,0 +1,54 @@
# WSDL4R - Class name creator.
# Copyright (C) 2000-2007 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 'soap/mapping/typeMap'
require 'xsd/codegen/gensupport'
module WSDL
module SOAP
class ClassNameCreator
include XSD::CodeGen::GenSupport
def initialize
@classname = {}
end
def assign_name(qname, modulepath = nil)
key = [modulepath, qname]
unless @classname.key?(key)
if klass = ::SOAP::TypeMap[qname]
name =
::SOAP::Mapping::DefaultRegistry.find_mapped_obj_class(klass).name
else
name = safeconstname(qname.name)
if modulepath
name = [modulepath, name].join('::')
end
while @classname.value?(name)
name += '_'
end
check_classname(name)
end
@classname[key] = name.freeze
end
@classname[key]
end
def check_classname(name)
if Object.constants.include?(name)
warn("created definition re-opens an existing toplevel class: #{name}. consider to use --module_path option of wsdl2ruby.rb")
end
end
end
end
end

View file

@ -0,0 +1,95 @@
# WSDL4R - Creating client skelton code from WSDL.
# Copyright (C) 2000-2007 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/soap/classDefCreatorSupport'
module WSDL
module SOAP
class ClientSkeltonCreator
include ClassDefCreatorSupport
attr_reader :definitions
def initialize(definitions, name_creator, modulepath = nil)
@definitions = definitions
@name_creator = name_creator
@modulepath = modulepath
end
def dump(service_name)
services = @definitions.service(service_name)
unless services
raise RuntimeError.new("service not defined: #{service_name}")
end
result = ""
if @modulepath
result << "\n"
result << @modulepath.collect { |ele| "module #{ele}" }.join("; ")
result << "\n\n"
end
services.ports.each do |port|
result << dump_porttype(port.porttype)
result << "\n"
end
if @modulepath
result << "\n\n"
result << @modulepath.collect { |ele| "end" }.join("; ")
result << "\n"
end
result
end
private
def dump_porttype(porttype)
drv_name = mapped_class_basename(porttype.name, @modulepath)
result = ""
result << <<__EOD__
endpoint_url = ARGV.shift
obj = #{ drv_name }.new(endpoint_url)
# run ruby with -d to see SOAP wiredumps.
obj.wiredump_dev = STDERR if $DEBUG
__EOD__
element_definitions = @definitions.collect_elements
porttype.operations.each do |operation|
result << dump_method_signature(operation, element_definitions)
result << dump_input_init(operation.input) << "\n"
result << dump_operation(operation) << "\n\n"
end
result
end
def dump_operation(operation)
name = operation.name
input = operation.input
"puts obj.#{ safemethodname(name) }#{ dump_inputparam(input) }"
end
def dump_input_init(input)
result = input.find_message.parts.collect { |part|
safevarname(part.name)
}.join(" = ")
if result.empty?
""
else
result << " = nil"
end
result
end
end
end
end

View file

@ -0,0 +1,172 @@
# WSDL4R - SOAP complexType definition for WSDL.
# Copyright (C) 2000-2007 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/xmlSchema/complexType'
require 'soap/mapping'
module WSDL
module XMLSchema
class ComplexType < Info
def compoundtype
@compoundtype ||= check_type
end
def check_type
if have_any?
:TYPE_STRUCT
elsif content
if attributes.empty? and map_as_array?
if name == ::SOAP::Mapping::MapQName
:TYPE_MAP
else
:TYPE_ARRAY
end
else
:TYPE_STRUCT
end
elsif complexcontent
complexcontent.check_type
elsif simplecontent
:TYPE_SIMPLE
elsif !attributes.empty?
:TYPE_STRUCT
else # empty complexType definition (seen in partner.wsdl of salesforce)
:TYPE_EMPTY
end
end
def child_type(name = nil)
case compoundtype
when :TYPE_STRUCT
if ele = find_element(name)
ele.type
elsif ele = find_element_by_name(name.name)
ele.type
end
when :TYPE_ARRAY
@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)
ele.type
elsif ele = content.find_element_by_name(name.name)
ele.type
end
else
raise NotImplementedError.new("Unknown kind of complexType.")
end
end
def child_defined_complextype(name)
ele = nil
case compoundtype
when :TYPE_STRUCT, :TYPE_MAP
unless ele = find_element(name)
if name.namespace.nil?
ele = find_element_by_name(name.name)
end
end
when :TYPE_ARRAY
e = elements
if e.size == 1
ele = e[0]
else
raise RuntimeError.new("Assert: must not reach.")
end
else
raise RuntimeError.new("Assert: Not implemented.")
end
unless ele
raise RuntimeError.new("Cannot find #{name} as a children of #{@name}.")
end
ele.local_complextype
end
def find_soapenc_arytype
unless compoundtype == :TYPE_ARRAY
raise RuntimeError.new("Assert: not for array")
end
if complexcontent
if complexcontent.restriction
complexcontent.restriction.attributes.each do |attribute|
if attribute.ref == ::SOAP::AttrArrayTypeName
return attribute.arytype
end
end
end
end
end
def find_arytype
unless compoundtype == :TYPE_ARRAY
raise RuntimeError.new("Assert: not for array")
end
if arytype = find_soapenc_arytype
return arytype
end
if map_as_array?
return element_simpletype(elements[0])
end
raise RuntimeError.new("Assert: Unknown array definition.")
end
def find_aryelement
unless compoundtype == :TYPE_ARRAY
raise RuntimeError.new("Assert: not for array")
end
if map_as_array?
return nested_elements[0]
end
nil # use default item name
end
private
def element_simpletype(element)
case element
when XMLSchema::Element
if element.type
element.type
elsif element.local_simpletype
element.local_simpletype.base
else
# element definition
nil
end
when XMLSchema::Any
XSD::AnyTypeName
else
nil
end
end
def map_as_array?
e = nested_elements
e.size == 1 and e[0].map_as_array?
end
def content_arytype
if arytype = find_arytype
ns = arytype.namespace
name = arytype.name.sub(/\[(?:,)*\]$/, '')
XSD::QName.new(ns, name)
else
nil
end
end
end
end
end

View file

@ -0,0 +1,42 @@
# WSDL4R - WSDL SOAP binding data definitions.
# Copyright (C) 2000-2007 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 'wsdl/soap/definitions'
require 'wsdl/soap/binding'
require 'wsdl/soap/operation'
require 'wsdl/soap/body'
require 'wsdl/soap/element'
require 'wsdl/soap/header'
require 'wsdl/soap/headerfault'
require 'wsdl/soap/fault'
require 'wsdl/soap/address'
require 'wsdl/soap/complexType'
module WSDL
module SOAP
HeaderFaultName = XSD::QName.new(SOAPBindingNamespace, 'headerfault')
LocationAttrName = XSD::QName.new(nil, 'location')
StyleAttrName = XSD::QName.new(nil, 'style')
TransportAttrName = XSD::QName.new(nil, 'transport')
UseAttrName = XSD::QName.new(nil, 'use')
PartsAttrName = XSD::QName.new(nil, 'parts')
PartAttrName = XSD::QName.new(nil, 'part')
NameAttrName = XSD::QName.new(nil, 'name')
MessageAttrName = XSD::QName.new(nil, 'message')
EncodingStyleAttrName = XSD::QName.new(nil, 'encodingStyle')
NamespaceAttrName = XSD::QName.new(nil, 'namespace')
SOAPActionAttrName = XSD::QName.new(nil, 'soapAction')
end
end

View file

@ -0,0 +1,200 @@
# WSDL4R - WSDL additional definitions for SOAP.
# Copyright (C) 2000-2007 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 'xsd/namedelements'
require 'soap/mapping'
module WSDL
class Definitions < Info
def self.soap_rpc_complextypes
types = XSD::NamedElements.new
types << array_complextype
types << fault_complextype
types << exception_complextype
types
end
def self.array_complextype
type = XMLSchema::ComplexType.new(::SOAP::ValueArrayName)
type.complexcontent = XMLSchema::ComplexContent.new
type.complexcontent.restriction = XMLSchema::ComplexRestriction.new
type.complexcontent.restriction.base = ::SOAP::ValueArrayName
attr = XMLSchema::Attribute.new
attr.ref = ::SOAP::AttrArrayTypeName
anyarray = XSD::QName.new(
XSD::AnyTypeName.namespace,
XSD::AnyTypeName.name + '[]')
attr.arytype = anyarray
type.complexcontent.restriction.attributes << attr
type
end
=begin
<xs:complexType name="Fault" final="extension">
<xs:sequence>
<xs:element name="faultcode" type="xs:QName" />
<xs:element name="faultstring" type="xs:string" />
<xs:element name="faultactor" type="xs:anyURI" minOccurs="0" />
<xs:element name="detail" type="tns:detail" minOccurs="0" />
</xs:sequence>
</xs:complexType>
=end
def self.fault_complextype
type = XMLSchema::ComplexType.new(::SOAP::EleFaultName)
faultcode = XMLSchema::Element.new(::SOAP::EleFaultCodeName, XSD::XSDQName::Type)
faultstring = XMLSchema::Element.new(::SOAP::EleFaultStringName, XSD::XSDString::Type)
faultactor = XMLSchema::Element.new(::SOAP::EleFaultActorName, XSD::XSDAnyURI::Type)
faultactor.minoccurs = 0
detail = XMLSchema::Element.new(::SOAP::EleFaultDetailName, XSD::AnyTypeName)
detail.minoccurs = 0
type.all_elements = [faultcode, faultstring, faultactor, detail]
type.final = 'extension'
type
end
def self.exception_complextype
type = XMLSchema::ComplexType.new(XSD::QName.new(
::SOAP::Mapping::RubyCustomTypeNamespace, 'SOAPException'))
excn_name = XMLSchema::Element.new(XSD::QName.new(nil, 'excn_type_name'), XSD::XSDString::Type)
cause = XMLSchema::Element.new(XSD::QName.new(nil, 'cause'), XSD::AnyTypeName)
backtrace = XMLSchema::Element.new(XSD::QName.new(nil, 'backtrace'), ::SOAP::ValueArrayName)
message = XMLSchema::Element.new(XSD::QName.new(nil, 'message'), XSD::XSDString::Type)
type.all_elements = [excn_name, cause, backtrace, message]
type
end
def soap_rpc_complextypes(binding)
types = rpc_operation_complextypes(binding)
types + self.class.soap_rpc_complextypes
end
def collect_faulttypes
result = []
collect_fault_messages.each do |name|
faultparts = message(name).parts
if faultparts.size != 1
raise RuntimeError.new("Expecting fault message \"#{name}\" to have ONE part")
end
fault_part = faultparts[0]
# WS-I Basic Profile Version 1.1 (R2205) requires fault message parts
# to refer to elements rather than types
faulttype = fault_part.element
if not faulttype
warn("Fault message \"#{name}\" part \"#{fault_part.name}\" must specify an \"element\" attribute")
faulttype = fault_part.type
end
if faulttype and result.index(faulttype).nil?
result << faulttype
end
end
result
end
private
def get_fault_binding(op_binding, fault_name)
op_binding.fault.each do |fault|
return fault if fault.name == fault_name
end
return nil
end
def op_binding_declares_fault(op_binding, fault_name)
return get_fault_binding(op_binding, fault_name) != nil
end
def collect_fault_messages
result = []
porttypes.each do |porttype|
port_binding = porttype.find_binding()
next unless port_binding
porttype.operations.each do |operation|
op_binding = port_binding.operations.find { |ele| ele.name == operation.name }
next unless op_binding
operation.fault.each do |fault|
# Make sure the operation fault has a name
if not fault.name
warn("Operation \"#{operation.name}\": fault must specify a \"name\" attribute")
next
end
# Make sure that portType fault has a corresponding soap:fault
# definition in binding section.
if not op_binding_declares_fault(op_binding, fault.name)
warn("Operation \"#{operation.name}\", fault \"#{fault.name}\": no corresponding wsdl:fault binding found with a matching \"name\" attribute")
next
end
fault_binding = get_fault_binding(op_binding, fault.name)
if fault_binding.soapfault.nil?
warn("WARNING: no soap:fault found for wsdl:fault \"#{fault_binding.name}\" in operation \"#{operation.name}\" \n\n")
next
end
if fault_binding.soapfault.name != fault_binding.name
warn("WARNING: name of soap:fault \"#{fault_binding.soapfault.name}\" doesn't match the name of wsdl:fault \"#{fault_binding.name}\" in operation \"#{operation.name}\" \n\n")
next
end
# According to WS-I (R2723): if in a wsdl:binding the use attribute
# on a contained soapbind:fault element is present, its value MUST
# be "literal".
if fault_binding.soapfault.use and fault_binding.soapfault.use != "literal"
warn("Operation \"#{operation.name}\", fault \"#{fault.name}\": soap:fault \"use\" attribute must be \"literal\"")
end
if result.index(fault.message).nil?
result << fault.message
end
end
end
end
result
end
def rpc_operation_complextypes(binding)
types = XSD::NamedElements.new
binding.operations.each do |op_bind|
if op_bind_rpc?(op_bind)
operation = op_bind.find_operation
if op_bind.input
type = XMLSchema::ComplexType.new(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.outputname)
message = messages[operation.output.message]
type.sequence_elements = elements_from_message(message)
types << type
end
end
end
types
end
def op_bind_rpc?(op_bind)
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
end

View file

@ -0,0 +1,118 @@
# WSDL4R - Creating driver code from WSDL.
# Copyright (C) 2000-2007 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/soap/mappingRegistryCreator'
require 'wsdl/soap/methodDefCreator'
require 'wsdl/soap/classDefCreatorSupport'
require 'xsd/codegen'
module WSDL
module SOAP
class DriverCreator
include ClassDefCreatorSupport
attr_reader :definitions
attr_accessor :drivername_postfix
def initialize(definitions, name_creator, modulepath = nil)
@definitions = definitions
@name_creator = name_creator
@modulepath = modulepath
@drivername_postfix = ''
end
def dump(porttype = nil)
result = "require 'soap/rpc/driver'\n\n"
if @modulepath
@modulepath.each do |name|
result << "module #{name}\n"
end
result << "\n"
end
if porttype.nil?
@definitions.porttypes.each do |type|
result << dump_porttype(type.name)
result << "\n"
end
else
result << dump_porttype(porttype)
end
if @modulepath
result << "\n"
@modulepath.each do |name|
result << "end\n"
end
end
result
end
private
def dump_porttype(porttype)
drivername = porttype.name + @drivername_postfix
qname = XSD::QName.new(porttype.namespace, drivername)
class_name = mapped_class_basename(qname, @modulepath)
defined_const = {}
result = MethodDefCreator.new(@definitions, @name_creator, @modulepath, defined_const).dump(porttype)
methoddef = result[:methoddef]
binding = @definitions.bindings.find { |item| item.type == porttype }
if binding.nil? or binding.soapbinding.nil?
# not bind or not a SOAP binding
return ''
end
address = @definitions.porttype(porttype).locations[0]
c = XSD::CodeGen::ClassDef.new(class_name, "::SOAP::RPC::Driver")
c.def_const("DefaultEndpointUrl", ndq(address))
c.def_code <<-EOD
Methods = [
#{methoddef.gsub(/^/, " ")}
]
EOD
wsdl_name = @definitions.name ? @definitions.name.name : 'default'
mrname = safeconstname(wsdl_name + 'MappingRegistry')
c.def_method("initialize", "endpoint_url = nil") do
%Q[endpoint_url ||= DefaultEndpointUrl\n] +
%Q[super(endpoint_url, nil)\n] +
%Q[self.mapping_registry = #{mrname}::EncodedRegistry\n] +
%Q[self.literal_mapping_registry = #{mrname}::LiteralRegistry\n] +
%Q[init_methods]
end
c.def_privatemethod("init_methods") do
<<-EOD
Methods.each do |definitions|
opt = definitions.last
if opt[:request_style] == :document
add_document_operation(*definitions)
else
add_rpc_operation(*definitions)
qname = definitions[0]
name = definitions[2]
if qname.name != name and qname.name.capitalize == name.capitalize
::SOAP::Mapping.define_singleton_method(self, qname.name) do |*arg|
__send__(name, *arg)
end
end
end
end
EOD
end
defined_const.each do |ns, tag|
c.def_const(tag, dq(ns))
end
c.dump
end
end
end
end

View file

@ -0,0 +1,33 @@
# WSDL4R - XMLSchema element definition for WSDL.
# Copyright (C) 2000-2007 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/xmlSchema/element'
module WSDL
module XMLSchema
class Element < Info
def map_as_array?
# parent sequence / choice may be marked as maxOccurs="unbounded"
maxoccurs.nil? or maxoccurs != 1 or (parent and parent.map_as_array?)
end
def anonymous_type?
!@ref and @name and @local_complextype
end
def attributes
@local_complextype.attributes
end
end
end
end

View file

@ -0,0 +1,73 @@
# WSDL4R - Creating EncodedMappingRegistry code from WSDL.
# Copyright (C) 2000-2007 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/soap/mappingRegistryCreatorSupport'
module WSDL
module SOAP
class EncodedMappingRegistryCreator
include MappingRegistryCreatorSupport
attr_reader :definitions
def initialize(definitions, name_creator, modulepath, defined_const)
@definitions = definitions
@name_creator = name_creator
@modulepath = modulepath
@simpletypes = definitions.collect_simpletypes
@simpletypes.uniq!
@complextypes = definitions.collect_complextypes
@complextypes.uniq!
@varname = nil
@defined_const = defined_const
end
def dump(varname)
@varname = varname
result = ''
str = dump_complextype
unless str.empty?
result << "\n" unless result.empty?
result << str
end
str = dump_simpletype
unless str.empty?
result << "\n" unless result.empty?
result << str
end
result
end
private
def dump_complextype
@complextypes.collect { |type|
unless type.abstract
dump_with_inner {
dump_complextypedef(@modulepath, type.name, type, nil, :encoded => true)
}
end
}.compact.join("\n")
end
def dump_simpletype
@simpletypes.collect { |type|
dump_with_inner {
dump_simpletypedef(@modulepath, type.name, type, nil, :encoded => true)
}
}.compact.join("\n")
end
end
end
end

View file

@ -0,0 +1,56 @@
# WSDL4R - WSDL SOAP body definition.
# Copyright (C) 2000-2007 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'
module WSDL
module SOAP
class Fault < Info
attr_reader :name # required
attr_reader :use # required
attr_reader :encodingstyle
attr_reader :namespace
def initialize
super
@name = nil
@use = nil
@encodingstyle = nil
@namespace = nil
end
def targetnamespace
parent.targetnamespace
end
def parse_element(element)
nil
end
def parse_attr(attr, value)
case attr
when NameAttrName
@name = XSD::QName.new(targetnamespace, value.source)
when UseAttrName
@use = value.source
when EncodingStyleAttrName
@encodingstyle = value.source
when NamespaceAttrName
@namespace = value.source
else
nil
end
end
end
end
end

View file

@ -0,0 +1,86 @@
# WSDL4R - WSDL SOAP body definition.
# Copyright (C) 2000-2007 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'
module WSDL
module SOAP
class Header < Info
attr_reader :headerfault
attr_reader :message # required
attr_reader :part # required
attr_reader :use # required
attr_reader :encodingstyle
attr_reader :namespace
def initialize
super
@message = nil
@part = nil
@use = nil
@encodingstyle = nil
@namespace = nil
@headerfault = nil
end
def targetnamespace
parent.targetnamespace
end
def find_message
root.message(@message) or raise RuntimeError.new("#{@message} not found")
end
def find_part
find_message.parts.each do |part|
if part.name == @part
return part
end
end
raise RuntimeError.new("#{@part} not found")
end
def parse_element(element)
case element
when HeaderFaultName
o = WSDL::SOAP::HeaderFault.new
@headerfault = o
o
else
nil
end
end
def parse_attr(attr, value)
case attr
when MessageAttrName
if value.namespace.nil?
value = XSD::QName.new(targetnamespace, value.source)
end
@message = value
when PartAttrName
@part = value.source
when UseAttrName
@use = value.source
when EncodingStyleAttrName
@encodingstyle = value.source
when NamespaceAttrName
@namespace = value.source
else
nil
end
end
end
end
end

View file

@ -0,0 +1,56 @@
# WSDL4R - WSDL SOAP body definition.
# Copyright (C) 2000-2007 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'
module WSDL
module SOAP
class HeaderFault < Info
attr_reader :message # required
attr_reader :part # required
attr_reader :use # required
attr_reader :encodingstyle
attr_reader :namespace
def initialize
super
@message = nil
@part = nil
@use = nil
@encodingstyle = nil
@namespace = nil
end
def parse_element(element)
nil
end
def parse_attr(attr, value)
case attr
when MessageAttrName
@message = value
when PartAttrName
@part = value.source
when UseAttrName
@use = value.source
when EncodingStyleAttrName
@encodingstyle = value.source
when NamespaceAttrName
@namespace = value.source
else
nil
end
end
end
end
end

View file

@ -0,0 +1,115 @@
# WSDL4R - Creating LiteralMappingRegistry code from WSDL.
# Copyright (C) 2000-2007 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/soap/mappingRegistryCreatorSupport'
module WSDL
module SOAP
class LiteralMappingRegistryCreator
include MappingRegistryCreatorSupport
def initialize(definitions, name_creator, modulepath, defined_const)
@definitions = definitions
@name_creator = name_creator
@modulepath = modulepath
@elements = definitions.collect_elements
@elements.uniq!
@attributes = definitions.collect_attributes
@attributes.uniq!
@simpletypes = definitions.collect_simpletypes
@simpletypes.uniq!
@complextypes = definitions.collect_complextypes
@complextypes.uniq!
@varname = nil
@defined_const = defined_const
end
def dump(varname)
@varname = varname
result = ''
str = dump_complextype
unless str.empty?
result << "\n" unless result.empty?
result << str
end
str = dump_simpletype
unless str.empty?
result << "\n" unless result.empty?
result << str
end
str = dump_element
unless str.empty?
result << "\n" unless result.empty?
result << str
end
str = dump_attribute
unless str.empty?
result << "\n" unless result.empty?
result << str
end
result
end
private
def dump_element
@elements.collect { |ele|
# has the definition different from the complexType of the same name
next if ele.type.nil? and @complextypes[ele.name]
dump_with_inner {
if typedef = ele.local_complextype
dump_complextypedef(@modulepath, ele.name, typedef)
elsif typedef = ele.local_simpletype
dump_simpletypedef(@modulepath, ele.name, typedef)
elsif ele.type
if typedef = @complextypes[ele.type]
dump_complextypedef(@modulepath, ele.type, typedef, ele.name)
elsif typedef = @simpletypes[ele.type]
dump_simpletypedef(@modulepath, ele.type, typedef, ele.name)
end
end
}
}.compact.join("\n")
end
def dump_attribute
@attributes.collect { |attr|
if attr.local_simpletype
dump_with_inner {
dump_simpletypedef(@modulepath, attr.name, attr.local_simpletype)
}
end
}.compact.join("\n")
end
def dump_simpletype
@simpletypes.collect { |type|
dump_with_inner {
dump_simpletypedef(@modulepath, type.name, type)
}
}.compact.join("\n")
end
def dump_complextype
@complextypes.collect { |type|
unless type.abstract
dump_with_inner {
dump_complextypedef(@modulepath, type.name, type)
}
end
}.compact.join("\n")
end
end
end
end

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