soap-lc 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.
@@ -0,0 +1,155 @@
1
+ require 'soap/lc/response'
2
+
3
+ module SOAP
4
+ class Request
5
+ def initialize( wsdl ) #:nodoc:
6
+ @wsdl = wsdl
7
+ @request = nil
8
+ end
9
+
10
+ # Call a method for the current Request and get a SOAP::Response
11
+ #
12
+ # Example:
13
+ # wsdl = SOAP::LC.new( ).wsdl( "http://..." )
14
+ # request = wsdl.request( )
15
+ # response = request.myMethod( :param1 => "hello" )
16
+ # # => #<SOAP::Response:0xNNNNNN>
17
+ def method_missing( id, *args )
18
+ call( id.id2name, args[0] )
19
+ end
20
+
21
+ # Call a method for the current Request and get a SOAP::Response
22
+ #
23
+ # Example:
24
+ # wsdl = SOAP::LC.new( ).wsdl( "http://..." )
25
+ # request = wsdl.request( )
26
+ # response = request.call( "myMethod", :param1 => "hello" )
27
+ # # => #<SOAP::Response:0xNNNNNN>
28
+ def call( methodName, args )
29
+ args = (args || {}).keys_to_sym!
30
+
31
+ # Get Binding
32
+ binding = @wsdl.bindings.getBindingForOperationName( methodName )
33
+ raise SOAP::LCNoMethodError, "Undefined method `#{methodName}'" if binding.nil?
34
+
35
+ # Get Binding Operation
36
+ binding_operation = binding.operations[methodName]
37
+
38
+ # Get PortType
39
+ portType = @wsdl.portTypes[binding.type.nns]
40
+ portType_operation = portType.operations[methodName]
41
+
42
+ # Get message for input operation
43
+ input_message = @wsdl.messages[portType_operation[:input][:message].nns]
44
+
45
+ # Create method
46
+ soap_method = "<#{methodName} xmlns=\"#{@wsdl.targetNamespace}\">\n"
47
+ input_message.parts.each do |_, attrs|
48
+
49
+ case attrs[:mode]
50
+ when :type
51
+ if SOAP::XSD::ANY_SIMPLE_TYPE.include?( attrs[attrs[:mode]].nns )
52
+ # Part refer to a builtin SimpleType
53
+ soap_method << SOAP::XSD.displayBuiltinType( attrs[:name], args, 1, 1 )
54
+ else
55
+ # Part refer to an XSD simpleType or complexType defined in types
56
+ element = @wsdl.types[attrs[attrs[:mode]].nns][:value]
57
+ case element[:type]
58
+ when :simpleType
59
+ soap_method << "<#{attrs[:name]}>\n#{element.display( @wsdl.types, args )}\n</#{attrs[:name]}>\n" # MAYBE ##########
60
+ when :complexType
61
+ soap_method << "<#{attrs[:name]}>\n#{element.display( @wsdl.types, args )}\n</#{attrs[:name]}>\n" # MAYBE ##########
62
+ else
63
+ raise SOAP::LCWSDLError, "Malformated part #{attrs[:name]}"
64
+ end
65
+ end
66
+ when :element
67
+ # Part refer to an XSD element
68
+ element = @wsdl.types[attrs[attrs[:mode]].nns][:value]
69
+ case element[:type]
70
+ when :simpleType
71
+ soap_method << element[element[:type]].display( @wsdl.types, args )
72
+ when :complexType
73
+ soap_method << element[element[:type]].display( @wsdl.types, args )
74
+ else
75
+ raise SOAL::LCWSDLError, "Malformated element `#{attrs[attrs[:mode]]}'"
76
+ end
77
+
78
+ ## TODO ---------- USE element[:key]
79
+ else
80
+ raise SOAP::LCWSDLError, "Malformated part #{attrs[:name]}"
81
+ end
82
+ end
83
+ soap_method += "</#{methodName}>\n"
84
+
85
+ # Create SOAP Envelope
86
+ envelope = soap_envelop do
87
+ soap_header + soap_body( soap_method )
88
+ end
89
+
90
+ # Create headers
91
+ headers = {
92
+ 'Content-Type' => 'application/soap+xml; charset=utf-8',
93
+ 'Content-Length' => "#{envelope.length}"
94
+ }
95
+ # Add SOAPAction to headers (if exist)
96
+ action = begin
97
+ binding_operation[:soapAction]
98
+ rescue
99
+ nil
100
+ end
101
+ headers['SOAPAction'] = action unless action.nil? or action.length == 0
102
+
103
+ # Search URI
104
+ service_port = @wsdl.services.getServicePortForBindingName( binding.name )
105
+ address = service_port[:address]
106
+
107
+ # Complete request
108
+ @request = {
109
+ :headers => headers,
110
+ :envelope => envelope,
111
+ :uri => address,
112
+ :response => @wsdl.messages[portType_operation[:output][:message].nns].name
113
+ }
114
+
115
+ return self
116
+ end
117
+
118
+ # Get the SOAP Body for the request
119
+ def soap_body( soap_method )
120
+ "<SOAP-ENV:Body>\n" + soap_method + "</SOAP-ENV:Body>\n"
121
+ end
122
+
123
+ # Send request to the server and get a response (SOAP::Response)
124
+ def response( )
125
+ return( SOAP::Response.new( @request ) )
126
+ end
127
+ alias_method :result, :response
128
+
129
+ # Get the SOAP Envelope for the request
130
+ def envelope( )
131
+ @request[:envelope] || nil
132
+ end
133
+
134
+ # Get request headers
135
+ def headers( )
136
+ @request[:headers] || nil
137
+ end
138
+
139
+ private
140
+ def soap_envelop( &b )
141
+ "<SOAP-ENV:Envelope
142
+ xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"
143
+ xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\"
144
+ xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
145
+ xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"
146
+ SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" +
147
+ yield() +
148
+ '</SOAP-ENV:Envelope>'
149
+ end
150
+
151
+ def soap_header()
152
+ "<SOAP-ENV:Header/>\n"
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,31 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+
4
+ module SOAP
5
+ class Response
6
+ # XML response
7
+ attr_reader :to_xml
8
+ # Hash response
9
+ attr_reader :to_h
10
+
11
+ def initialize( request ) #:nodoc:
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 = Hash.from_xml( @soap_response.body )["Envelope"]["Body"][request[:response]]
19
+ end
20
+
21
+ # Return SOAP error
22
+ def error
23
+ @soap_response.error!
24
+ end
25
+
26
+ def method_missing( id, *args ) #:nodoc:
27
+ puts id.id2name
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,42 @@
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 ) #:nodoc:
9
+ @parse = SOAP::WSDL::Parser.new( uri )
10
+ end
11
+
12
+ # Call a method for the current WSDL and get the corresponding SOAP::Request
13
+ #
14
+ # Example:
15
+ # wsdl = SOAP::LC.new( ).wsdl( "http://..." )
16
+ # request = wsdl.myMethod( :param1 => "hello" )
17
+ # # => #<SOAP::Request:0xNNNNNN>
18
+ def method_missing( id, *args )
19
+ return request.call( id.id2name, args[0] )
20
+ end
21
+
22
+ # Call a method for the current WSDL and get the corresponding SOAP::Request
23
+ #
24
+ # Example:
25
+ # wsdl = SOAP::LC.new( ).wsdl( "http://..." )
26
+ # request = wsdl.call( "myMethod", { :param1 => "hello" } )
27
+ # # => #<SOAP::Request:0xNNNNNN>
28
+ def call( name, args )
29
+ return request.call( name, args )
30
+ end
31
+
32
+ # Get a SOAP::Request object for the current WSDL
33
+ #
34
+ # Example:
35
+ # wsdl = SOAP::LC.new( ).wsdl( "http://..." )
36
+ # request = wsdl.request( )
37
+ # # => #<SOAP::Request:0xNNNNNN>
38
+ def request( )
39
+ return SOAP::Request.new( @parse )
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,160 @@
1
+ module SOAP
2
+ class WSDL
3
+ class Bindings < Hash
4
+ def getBindingForOperationName( name )
5
+ self.each do |binding_name, binding|
6
+ return binding if binding.operations.keys.include?(name)
7
+ end
8
+ return nil
9
+ end
10
+ end
11
+
12
+ class Binding
13
+ attr_reader :operations
14
+ attr_reader :name
15
+ attr_reader :type
16
+ attr_reader :style
17
+ attr_reader :transport
18
+
19
+ def initialize( element )
20
+ @operations = Hash.new
21
+ @name = element.attributes['name']
22
+ @type = element.attributes['type'] # because of Object#type
23
+ @style = nil
24
+ @transport = nil
25
+
26
+ # Process all binding and operation
27
+ element.find_all {|e| e.class == REXML::Element }.each { |operation|
28
+ case operation.name
29
+ when "binding"
30
+ # Get binding attributs
31
+ operation.attributes.each { |name, value|
32
+ case name
33
+ when 'style'
34
+ @style = value
35
+ when 'transport'
36
+ @transport = value
37
+ else
38
+ warn "Ignoring attribut `#{name}' for wsdlsoap:binding in binding `#{element.attributes['name']}'"
39
+ end
40
+ }
41
+ when "operation"
42
+ # Store operations
43
+ @operations[operation.attributes['name']] = Hash.new()
44
+
45
+ # Get operation attributs
46
+ operation.attributes.each { |name, value|
47
+ case name
48
+ when 'name'
49
+ @operations[operation.attributes['name']][:name] = value
50
+ else
51
+ warn "Ignoring attribut `#{name}' for operation `#{operation.attributes['name']}' in binding `#{element.attributes['name']}'"
52
+ end
53
+ }
54
+
55
+ # Store operation input, output, fault and operation
56
+ operation.find_all {|e| e.class == REXML::Element }.each { |action|
57
+ case action.name
58
+ when "operation"
59
+ # Get operation attributs
60
+ action.attributes.each { |name, value|
61
+ case name
62
+ when 'soapAction'
63
+ @operations[operation.attributes['name']][:soapAction] = value
64
+ else
65
+ warn "Ignoring attribut `#{name}' for wsdlsoap:operation in operation `#{operation.attributes['name']}' in binding `#{element.attributes['name']}'"
66
+ end
67
+ }
68
+ when "input"
69
+ @operations[operation.attributes['name']][:input] = Hash.new
70
+
71
+ # Store input attributs
72
+ action.attributes.each { |name, value|
73
+ case name
74
+ when 'name'
75
+ @operations[operation.attributes['name']][:input][:name] = value
76
+ else
77
+ warn "Ignoring attribut `#{name}' in #{action.name} `#{action.attributes['name']}' in operation `#{operation.attributes['name']}' for binding `#{element.attributes['name']}'"
78
+ end
79
+ }
80
+
81
+ # Store body
82
+ action.find_all {|e| e.class == REXML::Element }.each { |body|
83
+ case body.name
84
+ when "body"
85
+ @operations[operation.attributes['name']][:input][:body] = Hash.new
86
+
87
+ # Store body attributes
88
+ body.attributes.each { |name, value|
89
+ @operations[operation.attributes['name']][:input][:body][name.to_sym] = value
90
+ }
91
+ else
92
+ warn "Ignoring element `#{body.name}' in #{action.name} `#{action.attributes['name']}' in operation `#{operation.attributes['name']}' for binding `#{element.attributes['name']}'"
93
+ end
94
+ }
95
+ when "output"
96
+ @operations[operation.attributes['name']][:output] = Hash.new
97
+
98
+ # Store input attributs
99
+ action.attributes.each { |name, value|
100
+ case name
101
+ when 'name'
102
+ @operations[operation.attributes['name']][:output][:name] = value
103
+ else
104
+ warn "Ignoring attribut `#{name}' in #{action.name} `#{action.attributes['name']}' in operation `#{operation.attributes['name']}' for binding `#{element.attributes['name']}'"
105
+ end
106
+ }
107
+
108
+ # Store body
109
+ action.find_all {|e| e.class == REXML::Element }.each { |body|
110
+ case body.name
111
+ when "body"
112
+ @operations[operation.attributes['name']][:output][:body] = Hash.new
113
+
114
+ # Store body attributes
115
+ body.attributes.each { |name, value|
116
+ @operations[operation.attributes['name']][:output][:body][name.to_sym] = value
117
+ }
118
+ else
119
+ warn "Ignoring element `#{body.name}' in #{action.name} `#{action.attributes['name']}' in operation `#{operation.attributes['name']}' for binding `#{element.attributes['name']}'"
120
+ end
121
+ }
122
+ when "fault"
123
+ @operations[operation.attributes['name']][:fault] = Hash.new
124
+
125
+ # Store input attributs
126
+ action.attributes.each { |name, value|
127
+ case name
128
+ when 'name'
129
+ @operations[operation.attributes['name']][:fault][:name] = value
130
+ else
131
+ warn "Ignoring attribut `#{name}' in #{action.name} `#{action.attributes['name']}' in operation `#{operation.attributes['name']}' for binding `#{element.attributes['name']}'"
132
+ end
133
+ }
134
+
135
+ # Store body
136
+ action.find_all {|e| e.class == REXML::Element }.each { |body|
137
+ case body.name
138
+ when "body"
139
+ @operations[operation.attributes['name']][:fault][:body] = Hash.new
140
+
141
+ # Store body attributes
142
+ body.attributes.each { |name, value|
143
+ @operations[operation.attributes['name']][:fault][:body][name.to_sym] = value
144
+ }
145
+ else
146
+ warn "Ignoring element `#{body.name}' in #{action.name} `#{action.attributes['name']}' in operation `#{operation.attributes['name']}' for binding `#{element.attributes['name']}'"
147
+ end
148
+ }
149
+ else
150
+ warn "Ignoring element `#{action.name}' in operation `#{operation.attributes['name']}' for binding `#{element.attributes['name']}'"
151
+ end
152
+ }
153
+ else
154
+ warn "Ignoring element `#{operation.name}' in binding `#{element.attributes['name']}'"
155
+ end
156
+ }
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,44 @@
1
+ require 'soap/lc/error'
2
+
3
+ module SOAP
4
+ class WSDL
5
+ class Messages < Hash
6
+ end
7
+
8
+ class Message
9
+ attr_reader :parts
10
+ attr_reader :name
11
+
12
+ def initialize( element )
13
+ @parts = Hash.new
14
+ @name = element.attributes['name']
15
+
16
+ # Process all parts
17
+ element.find_all {|e| e.class == REXML::Element }.each { |part|
18
+ case part.name
19
+ when "part"
20
+ @parts[part.attributes['name']] = Hash.new
21
+
22
+ # Store part attributs
23
+ part.attributes.each { |name, value|
24
+ case name
25
+ when 'name'
26
+ @parts[part.attributes['name']][:name] = value
27
+ when 'element'
28
+ @parts[part.attributes['name']][:element] = value
29
+ @parts[part.attributes['name']][:mode] = :element
30
+ when 'type'
31
+ @parts[part.attributes['name']][:type] = value
32
+ @parts[part.attributes['name']][:mode] = :type
33
+ else
34
+ warn "Ignoring attribut `#{name}' in part `#{part.attributes['name']}' for message `#{element.attributes['name']}'"
35
+ end
36
+ }
37
+ else
38
+ warn "Ignoring element `#{part.name}' in message `#{element.attributes['name']}'"
39
+ end
40
+ }
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,109 @@
1
+ require 'open-uri'
2
+ require 'rexml/document'
3
+
4
+ require 'soap/lc/error'
5
+ require 'soap/lc/wsdl/message'
6
+ require 'soap/lc/wsdl/portType'
7
+ require 'soap/lc/wsdl/binding'
8
+ require 'soap/lc/wsdl/service'
9
+ require 'soap/lc/xsd'
10
+
11
+ module SOAP
12
+ class WSDL
13
+ class Parser
14
+ attr_reader :types
15
+ attr_reader :messages
16
+ attr_reader :portTypes
17
+ attr_reader :bindings
18
+ attr_reader :services
19
+
20
+ attr_reader :prefixes
21
+ attr_reader :targetNamespace
22
+
23
+ attr_reader :document
24
+
25
+ def initialize( uri )
26
+ @types = SOAP::XSD.new()
27
+ @messages = SOAP::WSDL::Messages.new
28
+ @portTypes = SOAP::WSDL::PortTypes.new
29
+ @bindings = SOAP::WSDL::Bindings.new
30
+ @services = SOAP::WSDL::Services.new
31
+
32
+ @prefixes = Hash.new
33
+ @targetNamespace = ""
34
+
35
+ # Get WSDL
36
+ source = nil
37
+ begin
38
+ open( uri ) do |f|
39
+ source = f.read
40
+ end
41
+ rescue Errno::ECONNREFUSED, Errno::ENOENT, OpenURI::HTTPError => e
42
+ raise SOAP::LCError, "Can't open '#{uri}' : #{e.message}"
43
+ end
44
+
45
+ # Parse WSDL content
46
+ @document = REXML::Document.new( source )
47
+
48
+ processAttributes @document.root.attributes
49
+ processContent @document.root.children
50
+ end
51
+
52
+ private
53
+ def processAttributes( attributes )
54
+ @targetNamespace = attributes["targetNamespace"]
55
+ attributes.values.each{ |attribute|
56
+ if attribute.prefix == "xmlns" then
57
+ @prefixes[attribute.name] = attribute.value
58
+ end
59
+ }
60
+ if(default_namespace = attributes["xmlns"]) then
61
+ @prefixes["__default__"] = default_namespace
62
+ end
63
+ end
64
+
65
+ def processContent( elements )
66
+ elements.find_all {|e| e.class == REXML::Element }.each { |element|
67
+ case element.name
68
+ when "types"
69
+ processTypes( element )
70
+ when "message"
71
+ processMessage( element )
72
+ when "portType"
73
+ processPortType( element )
74
+ when "binding"
75
+ processBinding( element )
76
+ when "service"
77
+ processService( element )
78
+ else
79
+ warn "Ignoring #{element}"
80
+ end
81
+ }
82
+ end
83
+
84
+ def processTypes( element )
85
+ @types.add_schema( element )
86
+ end
87
+
88
+ def processMessage( element )
89
+ name = element.attributes['name']
90
+ @messages[name] = SOAP::WSDL::Message.new( element )
91
+ end
92
+
93
+ def processPortType( element )
94
+ name = element.attributes['name']
95
+ @portTypes[name] = SOAP::WSDL::PortType.new( element )
96
+ end
97
+
98
+ def processBinding( element )
99
+ name = element.attributes['name']
100
+ @bindings[name] = SOAP::WSDL::Binding.new( element )
101
+ end
102
+
103
+ def processService( element )
104
+ name = element.attributes['name']
105
+ @services[name] = SOAP::WSDL::Service.new( element )
106
+ end
107
+ end
108
+ end
109
+ end