wsdl-reader 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. data/.gitignore +4 -0
  2. data/.idea/.name +1 -0
  3. data/.idea/.rakeTasks +7 -0
  4. data/.idea/encodings.xml +5 -0
  5. data/.idea/misc.xml +350 -0
  6. data/.idea/modules.xml +9 -0
  7. data/.idea/projectCodeStyle.xml +123 -0
  8. data/.idea/vcs.xml +7 -0
  9. data/.idea/workspace.xml +683 -0
  10. data/.idea/wsdl-reader.iml +25 -0
  11. data/.rspec +2 -0
  12. data/Gemfile +4 -0
  13. data/Guardfile +9 -0
  14. data/Rakefile +1 -0
  15. data/lib/wsdl-reader.rb +15 -0
  16. data/lib/wsdl-reader/binding.rb +148 -0
  17. data/lib/wsdl-reader/core_ext.rb +28 -0
  18. data/lib/wsdl-reader/error.rb +29 -0
  19. data/lib/wsdl-reader/message.rb +50 -0
  20. data/lib/wsdl-reader/parser.rb +105 -0
  21. data/lib/wsdl-reader/port_type.rb +106 -0
  22. data/lib/wsdl-reader/request.rb +213 -0
  23. data/lib/wsdl-reader/response.rb +72 -0
  24. data/lib/wsdl-reader/service.rb +56 -0
  25. data/lib/wsdl-reader/version.rb +5 -0
  26. data/lib/wsdl-reader/wsdl.rb +48 -0
  27. data/lib/wsdl-reader/xsd.rb +98 -0
  28. data/lib/wsdl-reader/xsd/complextype.rb +136 -0
  29. data/lib/wsdl-reader/xsd/convert.rb +142 -0
  30. data/lib/wsdl-reader/xsd/element.rb +168 -0
  31. data/lib/wsdl-reader/xsd/enumeration.rb +6 -0
  32. data/lib/wsdl-reader/xsd/restriction.rb +76 -0
  33. data/lib/wsdl-reader/xsd/sequence.rb +117 -0
  34. data/lib/wsdl-reader/xsd/simpletype.rb +83 -0
  35. data/spec/binding_spec.rb +67 -0
  36. data/spec/fixtures/OneFileUserService.wsdl +114 -0
  37. data/spec/fixtures/UserService.wsdl +63 -0
  38. data/spec/fixtures/UserService.xsd +56 -0
  39. data/spec/message_spec.rb +22 -0
  40. data/spec/parser_spec.rb +56 -0
  41. data/spec/port_type_spec.rb +32 -0
  42. data/spec/request_spec.rb +9 -0
  43. data/spec/spec_helper.rb +24 -0
  44. data/wsdl-reader.gemspec +27 -0
  45. metadata +122 -0
@@ -0,0 +1,213 @@
1
+ require 'wsdl-reader/core_ext'
2
+
3
+ require 'wsdl-reader/xsd'
4
+ require 'wsdl-reader/response'
5
+
6
+ module SOAP
7
+ class Request
8
+ def initialize(wsdl, binding = nil) #:nodoc:
9
+ @wsdl = wsdl
10
+ @binding = binding
11
+ @request = nil
12
+ end
13
+
14
+ # Call a method for the current Request and get a SOAP::Response
15
+ #
16
+ # Example:
17
+ # wsdl = SOAP::LC.new.wsdl("http://...")
18
+ # request = wsdl.request
19
+ # response = request.myMethod(:param1 => "hello")
20
+ # # => #<SOAP::Response:0xNNNNNN>
21
+ def method_missing(id, *args)
22
+ call(id.id2name, args[0])
23
+ end
24
+
25
+ # Create a new SOAP::Request with the given envelope, uri and headers
26
+ #
27
+ # Example:
28
+ # e = '<SOAP-ENV:Envelope
29
+ # xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
30
+ # xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
31
+ # xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
32
+ # xmlns:xsd="http://www.w3.org/2001/XMLSchema"
33
+ # SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
34
+ # <SOAP-ENV:Header/>
35
+ # <SOAP-ENV:Body>
36
+ # <HelloWorld xmlns="urn:MyWebService">
37
+ # <from>Greg</from>
38
+ # </HelloWorld>
39
+ # </SOAP-ENV:Body>
40
+ # </SOAP-ENV:Envelope>'
41
+ # r = SOAP::Request.request(e, "http://localhost:3000/hello/wsdl", "SOAPAction" => "my.soap.action")
42
+ def self.request(envelope, uri, headers = {})
43
+ req = new(nil, nil)
44
+ req.r(envelope, uri, headers)
45
+ return req
46
+ end
47
+ def r(envelope, uri, headers) #:nodoc:
48
+ @request = {
49
+ :headers => make_header(envelope, headers),
50
+ :envelope => envelope,
51
+ :uri => uri,
52
+ :wsdl => nil,
53
+ :response => nil,
54
+ :binding => @binding,
55
+ :method => nil
56
+ }
57
+ end
58
+
59
+ # Return available SOAP actions
60
+ def operations
61
+ @wsdl.bindings.get_operations(@binding)
62
+ end
63
+
64
+ # Call a method for the current Request
65
+ #
66
+ # Example:
67
+ # wsdl = SOAP::LC.new.wsdl("http://...")
68
+ # request = wsdl.request
69
+ # response = request.call("myMethod", :param1 => "hello")
70
+ # # => #<SOAP::Response:0xNNNNNN>
71
+ def call(method_name, args)
72
+ args = (args || {}).keys_to_sym!
73
+
74
+ # Get Binding
75
+ binding = @wsdl.bindings.get_binding_for_operation_name(@binding, method_name)
76
+ if binding.size == 0
77
+ raise SOAP::LCNoMethodError, "Undefined method `#{method_name}'"
78
+ elsif binding.size > 1
79
+ raise SOAP::LCError, "Ambigous method name `#{method_name}', please, specify a binding name"
80
+ else
81
+ binding = binding[0]
82
+ @binding = binding.name
83
+ end
84
+
85
+ # Get Binding Operation
86
+ binding_operation = binding.operations[method_name]
87
+
88
+ # Get PortType
89
+ port_type = @wsdl.port_types[binding.type.nns]
90
+ port_type_operation = port_type.operations[method_name]
91
+
92
+ # Get message for input operation
93
+ input_message = @wsdl.messages[port_type_operation[:input][:message].nns]
94
+
95
+ # Create method
96
+ soap_method = "<#{method_name} xmlns=\"#{@wsdl.target_namespace}\">\n"
97
+ input_message.parts.each do |_, attrs|
98
+ case attrs[:mode]
99
+ when :type
100
+ if SOAP::XSD::ANY_SIMPLE_TYPE.include?(attrs[attrs[:mode]].nns)
101
+ # Part refer to a builtin SimpleType
102
+ soap_method << SOAP::XSD.displayBuiltinType(attrs[:name], args, 1, 1)
103
+ else
104
+ # Part refer to an XSD simpleType or complexType defined in types
105
+ element = @wsdl.types[attrs[attrs[:mode]].nns][:value]
106
+ case element[:type]
107
+ when :simpleType
108
+ soap_method << "<#{attrs[:name]}>\n#{element.display(@wsdl.types, args)}\n</#{attrs[:name]}>\n" # MAYBE ##########
109
+ when :complexType
110
+ soap_method << "<#{attrs[:name]}>\n#{element.display(@wsdl.types, args)}\n</#{attrs[:name]}>\n" # MAYBE ##########
111
+ else
112
+ raise SOAP::LCWSDLError, "Malformated part #{attrs[:name]}"
113
+ end
114
+ end
115
+ when :element
116
+ # Part refer to an XSD element
117
+ element = @wsdl.types[attrs[attrs[:mode]].nns][:value]
118
+ case @wsdl.types[attrs[attrs[:mode]].nns][:type]
119
+ when :simpleType
120
+ soap_method << element[element[:type]].display(@wsdl.types, args)
121
+ when :complexType
122
+ soap_method << element[element[:type]].display(@wsdl.types, args)
123
+ else
124
+ raise SOAP::LCWSDLError, "Malformed element `#{attrs[attrs[:mode]]}'"
125
+ end
126
+
127
+ ## TODO ---------- USE element[:key]
128
+ else
129
+ raise SOAP::LCWSDLError, "Malformed part #{attrs[:name]}"
130
+ end
131
+ end
132
+ soap_method += "</#{method_name}>\n"
133
+
134
+ # Create SOAP Envelope
135
+ envelope = soap_envelop { soap_header + soap_body(soap_method) }
136
+
137
+ # Create headers
138
+ headers = Hash.new
139
+
140
+ # Add SOAPAction to headers (if exist)
141
+ action = binding_operation[:soapAction] rescue nil
142
+
143
+ headers['SOAPAction'] = action unless action.nil? || action.length == 0
144
+
145
+ # Search URI
146
+ service_port = @wsdl.services.getServicePortForBindingName(binding.name)
147
+ address = service_port[:address]
148
+
149
+ # Complete request
150
+ @request = {
151
+ :headers => make_header(envelope, headers),
152
+ :envelope => envelope,
153
+ :uri => address,
154
+ :wsdl => @wsdl,
155
+ :response => @wsdl.messages[port_type_operation[:output][:message].nns].name,
156
+ :binding => @binding,
157
+ :method => method_name
158
+ }
159
+
160
+ self
161
+ end
162
+
163
+ # Get the SOAP Body for the request
164
+ def soap_body(soap_method)
165
+ "<SOAP-ENV:Body>\n" + soap_method + "</SOAP-ENV:Body>\n"
166
+ end
167
+
168
+ # Send request to the server and get a response (SOAP::Response)
169
+ def response
170
+ SOAP::Response.new(@request)
171
+ end
172
+ alias_method :result, :response
173
+
174
+ # Get the SOAP Envelope for the request
175
+ def envelope
176
+ @request[:envelope] || nil
177
+ end
178
+
179
+ # Get request headers
180
+ def headers
181
+ @request[:headers] || nil
182
+ end
183
+
184
+ # Get request URI
185
+ def uri
186
+ @request[:uri] || nil
187
+ end
188
+
189
+ private
190
+ def make_header(e, h = {}) #:nodoc:
191
+ {
192
+ 'User-Agent' => "SOAP::LC (#{SOAP::LC::VERSION}); Ruby (#{VERSION})",
193
+ 'Content-Type' => 'text/xml', #'application/soap+xml; charset=utf-8',
194
+ 'Content-Length' => "#{e.length}"
195
+ }.merge(h)
196
+ end
197
+
198
+ def soap_envelop(&b) #:nodoc:
199
+ "<SOAP-ENV:Envelope
200
+ xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"
201
+ xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"
202
+ xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
203
+ xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
204
+ SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" +
205
+ yield +
206
+ '</SOAP-ENV:Envelope>'
207
+ end
208
+
209
+ def soap_header
210
+ "<SOAP-ENV:Header/>\n"
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,72 @@
1
+ require 'rexml/document'
2
+
3
+ module SOAP
4
+ class Response
5
+ # XML response
6
+ attr_reader :to_xml
7
+ # Hash response
8
+ attr_reader :to_h
9
+
10
+ def initialize(request) #:nodoc:
11
+ @request = request
12
+ url = URI.parse(request[:uri])
13
+ @soap_response = Net::HTTP.new(url.host, url.port).start { |http|
14
+ http.post(url.request_uri, @request[:envelope], @request[:headers])
15
+ }
16
+
17
+ @to_xml = @soap_response.body
18
+ @to_h = {}
19
+
20
+ if @request[:wsdl].nil? or @request[:response].nil?
21
+ require 'rubygems'
22
+ require 'active_support'
23
+
24
+ @to_h = Hash.from_xml(@soap_response.body)
25
+ else
26
+ processResponse()
27
+ end
28
+ end
29
+
30
+ def method_missing(id, *args)
31
+ get(id.id2name)
32
+ end
33
+
34
+ def [](name)
35
+ @to_h[name]
36
+ end
37
+ def get(name)
38
+ @to_h[name]
39
+ end
40
+
41
+ # Return SOAP error
42
+ def error
43
+ @soap_response.error!
44
+ end
45
+
46
+ private
47
+ def processResponse
48
+ xml_result = REXML::Document.new(@to_xml)
49
+ # raise SOAP::LCElementError, "Invalide SOAP response!" if xml_result.root.children[0].children[0].name != "#{@request[:method]}Response"
50
+
51
+ xml_response = xml_result.root.children[0].children[0].children
52
+ @request[:wsdl].messages[@request[:response]].parts.each do |node, attrs|
53
+ case attrs[:mode]
54
+ when :element
55
+ @to_h = @request[:wsdl].types[attrs[:element].nns][:value].responseToHash(xml_response, @request[:wsdl].types)
56
+ when :type
57
+ if SOAP::XSD::ANY_SIMPLE_TYPE.include?(attrs[:type].nns)
58
+ # **************************** NEED TO BE VERIFIED ************************************
59
+ @to_h = { node.to_sym => SOAP::XSD::Convert.to_ruby(attrs[:type].to_s, xml_response[0].children[0].to_s) }
60
+ # **************************** TODO ************************************
61
+ else
62
+ # **************************** TODO ************************************
63
+ warn("Complex type #{attrs[:type]} not yet supported! for #{xml_response}")
64
+ # **************************** TODO ************************************
65
+ end
66
+ else
67
+ end
68
+ end
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,56 @@
1
+ module SOAP
2
+ class WSDL
3
+ class Services < Hash
4
+ def getServicePortForBindingName( name )
5
+ self.each do |binding_name, binding|
6
+ binding.ports.each do |port_name, port|
7
+ return port if port[:binding].nns == name
8
+ end
9
+ end
10
+ return nil
11
+ end
12
+ end
13
+
14
+ class Service
15
+ attr_reader :ports
16
+ attr_reader :name
17
+
18
+ def initialize( element )
19
+ @ports = Hash.new
20
+ @name = element.attributes['name']
21
+
22
+ # Process all ports
23
+ element.find_all {|e| e.class == REXML::Element }.each { |port|
24
+ case port.name
25
+ when "port"
26
+ @ports[port.attributes['name']] = Hash.new
27
+
28
+ # Store port attributs
29
+ port.attributes.each { |name, value|
30
+ case name
31
+ when 'name'
32
+ @ports[port.attributes['name']][:name] = value
33
+ when 'binding'
34
+ @ports[port.attributes['name']][:binding] = value
35
+ else
36
+ warn "Ignoring attribut `#{name}' in port `#{port.attributes['name']}' for service `#{element.attributes['name']}'"
37
+ end
38
+ }
39
+
40
+ # Store port soap:address
41
+ port.find_all {|e| e.class == REXML::Element }.each { |address|
42
+ case address.name
43
+ when "address"
44
+ @ports[port.attributes['name']][:address] = address.attributes['location']
45
+ else
46
+ warn "Ignoring element `#{address.name}' in port `#{port.attributes['name']}' for service `#{element.attributes['name']}'"
47
+ end
48
+ }
49
+ else
50
+ warn "Ignoring element `#{port.name}' in service `#{element.attributes['name']}'"
51
+ end
52
+ }
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ module Wsdl
2
+ module Reader
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,48 @@
1
+ require 'soap/lc/wsdl/parser'
2
+ require 'soap/lc/request'
3
+
4
+ module SOAP
5
+ class WSDL
6
+ attr_reader :parse
7
+
8
+ def initialize(uri, binding) #:nodoc:
9
+ @parse = SOAP::WSDL::Parser.new(uri)
10
+ @binding = binding
11
+ end
12
+
13
+ # Call a method for the current WSDL and get the corresponding SOAP::Request
14
+ #
15
+ # Example:
16
+ # wsdl = SOAP::LC.new.wsdl("http://...")
17
+ # request = wsdl.myMethod(:param1 => "hello")
18
+ # # => #<SOAP::Request:0xNNNNNN>
19
+ def method_missing(id, *args)
20
+ request(@binding).call(id.id2name, args[0])
21
+ end
22
+
23
+ # Return available SOAP operations
24
+ def operations
25
+ request(@binding).operations
26
+ end
27
+
28
+ # Call a method for the current WSDL and get the corresponding SOAP::Request
29
+ #
30
+ # Example:
31
+ # wsdl = SOAP::LC.new.wsdl("http://...")
32
+ # request = wsdl.call("myMethod", { :param1 => "hello" })
33
+ # # => #<SOAP::Request:0xNNNNNN>
34
+ def call(name, args = {})
35
+ request(@binding).call(name, args)
36
+ end
37
+
38
+ # Get a SOAP::Request object for the current WSDL
39
+ #
40
+ # Example:
41
+ # wsdl = SOAP::LC.new.wsdl("http://...")
42
+ # request = wsdl.request
43
+ # # => #<SOAP::Request:0xNNNNNN>
44
+ def request(binding = nil)
45
+ SOAP::Request.new(@parse, binding)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,98 @@
1
+ require 'wsdl-reader/error'
2
+ require 'wsdl-reader/core_ext'
3
+
4
+ require 'wsdl-reader/xsd/complextype'
5
+ require 'wsdl-reader/xsd/convert'
6
+ require 'wsdl-reader/xsd/element'
7
+ require 'wsdl-reader/xsd/enumeration'
8
+ require 'wsdl-reader/xsd/restriction'
9
+ require 'wsdl-reader/xsd/sequence'
10
+ require 'wsdl-reader/xsd/simpletype'
11
+
12
+ module SOAP
13
+ class XSD
14
+ include Comparable
15
+ attr_reader :elements
16
+ attr_reader :simpleTypes
17
+ attr_reader :complexType
18
+
19
+ ANY_SIMPLE_TYPE = %w(duration dateTime time date gYearMonth gYear gMonthDay gDay gMonth
20
+ boolean base64Binary hexBinary float double anyURI QName NOTATION string normalizedString
21
+ token language Name NMTOKEN NCName NMTOKENS ID IDREF ENTITY IDREFS ENTITIES
22
+ decimal integer nonPositiveInteger long nonNegativeInteger negativeInteger int unsignedLong positiveInteger
23
+ short unsignedInt byte unsignedShort unsignedByte)
24
+
25
+ def initialize()
26
+ @elements = Hash.new
27
+ @simpleTypes = Hash.new
28
+ @complexTypes = Hash.new
29
+ @types = Hash.new
30
+ end
31
+
32
+ def <=>(other)
33
+ @types <=> other.instance_variable_get(:@types)
34
+ end
35
+
36
+ def add_schema(types)
37
+ # Process all schema
38
+ types.children.find_all { |e| e.class == REXML::Element }.each { |schema|
39
+ schema.find_all { |e| e.class == REXML::Element }.each { |type|
40
+ processType type
41
+ }
42
+ }
43
+ end
44
+
45
+ def any_defined_type
46
+ @types.keys
47
+ end
48
+
49
+ def [](name)
50
+ @types[name]
51
+ end
52
+
53
+ def self.displayBuiltinType(name, args, min = 1, max = 1)
54
+ r = ""
55
+
56
+ if args.keys.include?(name.to_sym)
57
+ args[name.to_sym] = [args[name.to_sym]] unless args[name.to_sym].class == Array
58
+ if args[name.to_sym].size < min or args[name.to_sym].size > max
59
+ raise SOAP::LCArgumentError, "Wrong number or values for parameter `#{name}'"
60
+ end
61
+ args[name.to_sym].each { |v|
62
+ r << "<#{name}>#{v}</#{name}>\n"
63
+ }
64
+ elsif min > 0
65
+ raise SOAP::LCArgumentError, "Missing parameter `#{name}'" if min > 0
66
+ end
67
+
68
+ return r
69
+ end
70
+
71
+ private
72
+
73
+ def processType(type)
74
+ case type.name
75
+ when "element"
76
+ @elements[type.attributes['name']] = SOAP::XSD::Element.new(type)
77
+ @types[type.attributes['name']] = {
78
+ :type => :element,
79
+ :value => @elements[type.attributes['name']]
80
+ }
81
+ when "complexType"
82
+ @complexTypes[type.attributes['name']] = SOAP::XSD::ComplexType.new(type)
83
+ @types[type.attributes['name']] = {
84
+ :type => :complexType,
85
+ :value => @complexTypes[type.attributes['name']]
86
+ }
87
+ when "simpleType"
88
+ @simpleTypes[type.attributes['name']] = SOAP::XSD::SimpleType.new(type)
89
+ @types[type.attributes['name']] = {
90
+ :type => :simpleType,
91
+ :value => @simpleTypes[type.attributes['name']]
92
+ }
93
+ else
94
+ warn "Ignoring type '#{type.name}' in #{__FILE__}:#{__LINE__}" if ::WSDL::Reader.debugging?
95
+ end
96
+ end
97
+ end
98
+ end