zinfinit-actionwebservice 2.3.4.2

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 (80) hide show
  1. data/CHANGELOG +323 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +381 -0
  4. data/Rakefile +173 -0
  5. data/examples/googlesearch/README +143 -0
  6. data/examples/googlesearch/autoloading/google_search_api.rb +50 -0
  7. data/examples/googlesearch/autoloading/google_search_controller.rb +57 -0
  8. data/examples/googlesearch/delegated/google_search_service.rb +108 -0
  9. data/examples/googlesearch/delegated/search_controller.rb +7 -0
  10. data/examples/googlesearch/direct/google_search_api.rb +50 -0
  11. data/examples/googlesearch/direct/search_controller.rb +58 -0
  12. data/examples/metaWeblog/README +17 -0
  13. data/examples/metaWeblog/apis/blogger_api.rb +60 -0
  14. data/examples/metaWeblog/apis/blogger_service.rb +34 -0
  15. data/examples/metaWeblog/apis/meta_weblog_api.rb +67 -0
  16. data/examples/metaWeblog/apis/meta_weblog_service.rb +48 -0
  17. data/examples/metaWeblog/controllers/xmlrpc_controller.rb +16 -0
  18. data/generators/web_service/USAGE +28 -0
  19. data/generators/web_service/templates/api_definition.rb +5 -0
  20. data/generators/web_service/templates/controller.rb +8 -0
  21. data/generators/web_service/templates/functional_test.rb +19 -0
  22. data/generators/web_service/web_service_generator.rb +29 -0
  23. data/lib/action_web_service.rb +68 -0
  24. data/lib/action_web_service/api.rb +297 -0
  25. data/lib/action_web_service/base.rb +38 -0
  26. data/lib/action_web_service/casting.rb +149 -0
  27. data/lib/action_web_service/client.rb +3 -0
  28. data/lib/action_web_service/client/base.rb +28 -0
  29. data/lib/action_web_service/client/soap_client.rb +113 -0
  30. data/lib/action_web_service/client/xmlrpc_client.rb +58 -0
  31. data/lib/action_web_service/container.rb +3 -0
  32. data/lib/action_web_service/container/action_controller_container.rb +93 -0
  33. data/lib/action_web_service/container/delegated_container.rb +86 -0
  34. data/lib/action_web_service/container/direct_container.rb +69 -0
  35. data/lib/action_web_service/dispatcher.rb +2 -0
  36. data/lib/action_web_service/dispatcher/abstract.rb +207 -0
  37. data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +397 -0
  38. data/lib/action_web_service/invocation.rb +202 -0
  39. data/lib/action_web_service/protocol.rb +4 -0
  40. data/lib/action_web_service/protocol/abstract.rb +112 -0
  41. data/lib/action_web_service/protocol/discovery.rb +37 -0
  42. data/lib/action_web_service/protocol/soap_protocol.rb +176 -0
  43. data/lib/action_web_service/protocol/soap_protocol/marshaler.rb +242 -0
  44. data/lib/action_web_service/protocol/xmlrpc_protocol.rb +122 -0
  45. data/lib/action_web_service/scaffolding.rb +281 -0
  46. data/lib/action_web_service/simple.rb +53 -0
  47. data/lib/action_web_service/string_to_datetime_for_soap.rb +10 -0
  48. data/lib/action_web_service/struct.rb +68 -0
  49. data/lib/action_web_service/support/class_inheritable_options.rb +26 -0
  50. data/lib/action_web_service/support/signature_types.rb +256 -0
  51. data/lib/action_web_service/templates/scaffolds/layout.html.erb +65 -0
  52. data/lib/action_web_service/templates/scaffolds/methods.html.erb +6 -0
  53. data/lib/action_web_service/templates/scaffolds/parameters.html.erb +29 -0
  54. data/lib/action_web_service/templates/scaffolds/result.html.erb +30 -0
  55. data/lib/action_web_service/test_invoke.rb +110 -0
  56. data/lib/action_web_service/version.rb +9 -0
  57. data/lib/actionwebservice.rb +1 -0
  58. data/setup.rb +1379 -0
  59. data/test/abstract_client.rb +183 -0
  60. data/test/abstract_dispatcher.rb +548 -0
  61. data/test/abstract_unit.rb +39 -0
  62. data/test/api_test.rb +102 -0
  63. data/test/apis/auto_load_api.rb +3 -0
  64. data/test/apis/broken_auto_load_api.rb +2 -0
  65. data/test/base_test.rb +42 -0
  66. data/test/casting_test.rb +94 -0
  67. data/test/client_soap_test.rb +155 -0
  68. data/test/client_xmlrpc_test.rb +153 -0
  69. data/test/container_test.rb +73 -0
  70. data/test/dispatcher_action_controller_soap_test.rb +138 -0
  71. data/test/dispatcher_action_controller_xmlrpc_test.rb +59 -0
  72. data/test/fixtures/db_definitions/mysql.sql +8 -0
  73. data/test/fixtures/users.yml +12 -0
  74. data/test/gencov +3 -0
  75. data/test/invocation_test.rb +185 -0
  76. data/test/run +6 -0
  77. data/test/scaffolded_controller_test.rb +146 -0
  78. data/test/struct_test.rb +52 -0
  79. data/test/test_invoke_test.rb +112 -0
  80. metadata +173 -0
@@ -0,0 +1,2 @@
1
+ require 'action_web_service/dispatcher/abstract'
2
+ require 'action_web_service/dispatcher/action_controller_dispatcher'
@@ -0,0 +1,207 @@
1
+ require 'benchmark'
2
+
3
+ module ActionWebService # :nodoc:
4
+ module Dispatcher # :nodoc:
5
+ class DispatcherError < ActionWebService::ActionWebServiceError # :nodoc:
6
+ def initialize(*args)
7
+ super
8
+ set_backtrace(caller)
9
+ end
10
+ end
11
+
12
+ def self.included(base) # :nodoc:
13
+ base.class_inheritable_option(:web_service_dispatching_mode, :direct)
14
+ base.class_inheritable_option(:web_service_exception_reporting, true)
15
+ base.send(:include, ActionWebService::Dispatcher::InstanceMethods)
16
+ end
17
+
18
+ module InstanceMethods # :nodoc:
19
+ private
20
+ def invoke_web_service_request(protocol_request)
21
+ invocation = web_service_invocation(protocol_request)
22
+ if invocation.is_a?(Array) && protocol_request.protocol.is_a?(Protocol::XmlRpc::XmlRpcProtocol)
23
+ xmlrpc_multicall_invoke(invocation)
24
+ else
25
+ web_service_invoke(invocation)
26
+ end
27
+ end
28
+
29
+ def web_service_direct_invoke(invocation)
30
+ @method_params = invocation.method_ordered_params
31
+ arity = method(invocation.api_method.name).arity rescue 0
32
+ if arity < 0 || arity > 0
33
+ params = @method_params
34
+ else
35
+ params = []
36
+ end
37
+ web_service_filtered_invoke(invocation, params)
38
+ end
39
+
40
+ def web_service_delegated_invoke(invocation)
41
+ web_service_filtered_invoke(invocation, invocation.method_ordered_params)
42
+ end
43
+
44
+ def web_service_filtered_invoke(invocation, params)
45
+ cancellation_reason = nil
46
+ return_value = invocation.service.perform_invocation(invocation.api_method.name, params) do |x|
47
+ cancellation_reason = x
48
+ end
49
+ if cancellation_reason
50
+ raise(DispatcherError, "request canceled: #{cancellation_reason}")
51
+ end
52
+ return_value
53
+ end
54
+
55
+ def web_service_invoke(invocation)
56
+ case web_service_dispatching_mode
57
+ when :direct
58
+ return_value = web_service_direct_invoke(invocation)
59
+ when :delegated, :layered
60
+ return_value = web_service_delegated_invoke(invocation)
61
+ end
62
+ web_service_create_response(invocation.protocol, invocation.protocol_options, invocation.api, invocation.api_method, return_value)
63
+ end
64
+
65
+ def xmlrpc_multicall_invoke(invocations)
66
+ responses = []
67
+ invocations.each do |invocation|
68
+ if invocation.is_a?(Hash)
69
+ responses << [invocation, nil]
70
+ next
71
+ end
72
+ begin
73
+ case web_service_dispatching_mode
74
+ when :direct
75
+ return_value = web_service_direct_invoke(invocation)
76
+ when :delegated, :layered
77
+ return_value = web_service_delegated_invoke(invocation)
78
+ end
79
+ api_method = invocation.api_method
80
+ if invocation.api.has_api_method?(api_method.name)
81
+ response_type = (api_method.returns ? api_method.returns[0] : nil)
82
+ return_value = api_method.cast_returns(return_value)
83
+ else
84
+ response_type = ActionWebService::SignatureTypes.canonical_signature_entry(return_value.class, 0)
85
+ end
86
+ responses << [return_value, response_type]
87
+ rescue Exception => e
88
+ responses << [{ 'faultCode' => 3, 'faultString' => e.message }, nil]
89
+ end
90
+ end
91
+ invocation = invocations[0]
92
+ invocation.protocol.encode_multicall_response(responses, invocation.protocol_options)
93
+ end
94
+
95
+ def web_service_invocation(request, level = 0)
96
+ public_method_name = request.method_name
97
+ invocation = Invocation.new
98
+ invocation.protocol = request.protocol
99
+ invocation.protocol_options = request.protocol_options
100
+ invocation.service_name = request.service_name
101
+ if web_service_dispatching_mode == :layered
102
+ case invocation.protocol
103
+ when Protocol::Soap::SoapProtocol
104
+ soap_action = request.protocol_options[:soap_action]
105
+ if soap_action && soap_action =~ /^\/\w+\/(\w+)\//
106
+ invocation.service_name = $1
107
+ end
108
+ when Protocol::XmlRpc::XmlRpcProtocol
109
+ if request.method_name =~ /^([^\.]+)\.(.*)$/
110
+ public_method_name = $2
111
+ invocation.service_name = $1
112
+ end
113
+ end
114
+ end
115
+ if invocation.protocol.is_a? Protocol::XmlRpc::XmlRpcProtocol
116
+ if public_method_name == 'multicall' && invocation.service_name == 'system'
117
+ if level > 0
118
+ raise(DispatcherError, "Recursive system.multicall invocations not allowed")
119
+ end
120
+ multicall = request.method_params.dup
121
+ unless multicall.is_a?(Array) && multicall[0].is_a?(Array)
122
+ raise(DispatcherError, "Malformed multicall (expected array of Hash elements)")
123
+ end
124
+ multicall = multicall[0]
125
+ return multicall.map do |item|
126
+ raise(DispatcherError, "Multicall elements must be Hash") unless item.is_a?(Hash)
127
+ raise(DispatcherError, "Multicall elements must contain a 'methodName' key") unless item.has_key?('methodName')
128
+ method_name = item['methodName']
129
+ params = item.has_key?('params') ? item['params'] : []
130
+ multicall_request = request.dup
131
+ multicall_request.method_name = method_name
132
+ multicall_request.method_params = params
133
+ begin
134
+ web_service_invocation(multicall_request, level + 1)
135
+ rescue Exception => e
136
+ {'faultCode' => 4, 'faultMessage' => e.message}
137
+ end
138
+ end
139
+ end
140
+ end
141
+ case web_service_dispatching_mode
142
+ when :direct
143
+ invocation.api = self.class.web_service_api
144
+ invocation.service = self
145
+ when :delegated, :layered
146
+ invocation.service = web_service_object(invocation.service_name)
147
+ invocation.api = invocation.service.class.web_service_api
148
+ end
149
+ if invocation.api.nil?
150
+ raise(DispatcherError, "no API attached to #{invocation.service.class}")
151
+ end
152
+ invocation.protocol.register_api(invocation.api)
153
+ request.api = invocation.api
154
+ if invocation.api.has_public_api_method?(public_method_name)
155
+ invocation.api_method = invocation.api.public_api_method_instance(public_method_name)
156
+ else
157
+ if invocation.api.default_api_method.nil?
158
+ raise(DispatcherError, "no such method '#{public_method_name}' on API #{invocation.api}")
159
+ else
160
+ invocation.api_method = invocation.api.default_api_method_instance
161
+ end
162
+ end
163
+ if invocation.service.nil?
164
+ raise(DispatcherError, "no service available for service name #{invocation.service_name}")
165
+ end
166
+ unless invocation.service.respond_to?(invocation.api_method.name)
167
+ raise(DispatcherError, "no such method '#{public_method_name}' on API #{invocation.api} (#{invocation.api_method.name})")
168
+ end
169
+ request.api_method = invocation.api_method
170
+ begin
171
+ invocation.method_ordered_params = invocation.api_method.cast_expects(request.method_params.dup)
172
+ rescue
173
+ logger.warn "Casting of method parameters failed" unless logger.nil?
174
+ invocation.method_ordered_params = request.method_params
175
+ end
176
+ request.method_params = invocation.method_ordered_params
177
+ invocation.method_named_params = {}
178
+ invocation.api_method.param_names.inject(0) do |m, n|
179
+ invocation.method_named_params[n] = invocation.method_ordered_params[m]
180
+ m + 1
181
+ end
182
+ invocation
183
+ end
184
+
185
+ def web_service_create_response(protocol, protocol_options, api, api_method, return_value)
186
+ if api.has_api_method?(api_method.name)
187
+ return_type = api_method.returns ? api_method.returns[0] : nil
188
+ return_value = api_method.cast_returns(return_value)
189
+ else
190
+ return_type = ActionWebService::SignatureTypes.canonical_signature_entry(return_value.class, 0)
191
+ end
192
+ protocol.encode_response(api_method.public_name + 'Response', return_value, return_type, protocol_options)
193
+ end
194
+
195
+ class Invocation # :nodoc:
196
+ attr_accessor :protocol
197
+ attr_accessor :protocol_options
198
+ attr_accessor :service_name
199
+ attr_accessor :api
200
+ attr_accessor :api_method
201
+ attr_accessor :method_ordered_params
202
+ attr_accessor :method_named_params
203
+ attr_accessor :service
204
+ end
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,397 @@
1
+ require 'benchmark'
2
+ require 'builder/xmlmarkup'
3
+
4
+ module ActionWebService # :nodoc:
5
+ module Dispatcher # :nodoc:
6
+ module ActionController # :nodoc:
7
+ def self.included(base) # :nodoc:
8
+ class << base
9
+ include ClassMethods
10
+ alias_method_chain :inherited, :action_controller
11
+ end
12
+ base.class_eval do
13
+ alias_method :web_service_direct_invoke_without_controller, :web_service_direct_invoke
14
+ end
15
+ base.add_web_service_api_callback do |klass, api|
16
+ if klass.web_service_dispatching_mode == :direct
17
+ klass.class_eval 'def api; dispatch_web_service_request; end'
18
+ end
19
+ end
20
+ base.add_web_service_definition_callback do |klass, name, info|
21
+ if klass.web_service_dispatching_mode == :delegated
22
+ klass.class_eval "def #{name}; dispatch_web_service_request; end"
23
+ elsif klass.web_service_dispatching_mode == :layered
24
+ klass.class_eval 'def api; dispatch_web_service_request; end'
25
+ end
26
+ end
27
+ base.send(:include, ActionWebService::Dispatcher::ActionController::InstanceMethods)
28
+ end
29
+
30
+ module ClassMethods # :nodoc:
31
+ def inherited_with_action_controller(child)
32
+ inherited_without_action_controller(child)
33
+ child.send(:include, ActionWebService::Dispatcher::ActionController::WsdlAction)
34
+ end
35
+ end
36
+
37
+ module InstanceMethods # :nodoc:
38
+ private
39
+ def dispatch_web_service_request
40
+ method = request.method.to_s.upcase
41
+ allowed_methods = self.class.web_service_api ? (self.class.web_service_api.allowed_http_methods || []) : [ :post ]
42
+ allowed_methods = allowed_methods.map{|m| m.to_s.upcase }
43
+ if !allowed_methods.include?(method)
44
+ render :text => "#{method} not supported", :status=>500
45
+ return
46
+ end
47
+ exception = nil
48
+ begin
49
+ ws_request = discover_web_service_request(request)
50
+ rescue Exception => e
51
+ exception = e
52
+ end
53
+ if ws_request
54
+ ws_response = nil
55
+ exception = nil
56
+ bm = Benchmark.measure do
57
+ begin
58
+ ws_response = invoke_web_service_request(ws_request)
59
+ rescue Exception => e
60
+ exception = e
61
+ end
62
+ end
63
+ log_request(ws_request, request.raw_post)
64
+ if exception
65
+ log_error(exception) unless logger.nil?
66
+ send_web_service_error_response(ws_request, exception)
67
+ else
68
+ send_web_service_response(ws_response, bm.real)
69
+ end
70
+ else
71
+ exception ||= DispatcherError.new("Malformed SOAP or XML-RPC protocol message")
72
+ log_error(exception) unless logger.nil?
73
+ send_web_service_error_response(ws_request, exception)
74
+ end
75
+ rescue Exception => e
76
+ log_error(e) unless logger.nil?
77
+ send_web_service_error_response(ws_request, e)
78
+ end
79
+
80
+ def send_web_service_response(ws_response, elapsed=nil)
81
+ log_response(ws_response, elapsed)
82
+ options = { :type => ws_response.content_type, :disposition => 'inline' }
83
+ send_data(ws_response.body, options)
84
+ end
85
+
86
+ def send_web_service_error_response(ws_request, exception)
87
+ if ws_request
88
+ unless self.class.web_service_exception_reporting
89
+ exception = DispatcherError.new("Internal server error (exception raised)")
90
+ end
91
+ api_method = ws_request.api_method
92
+ public_method_name = api_method ? api_method.public_name : ws_request.method_name
93
+ return_type = ActionWebService::SignatureTypes.canonical_signature_entry(Exception, 0)
94
+ ws_response = ws_request.protocol.encode_response(public_method_name + 'Response', exception, return_type, ws_request.protocol_options)
95
+ send_web_service_response(ws_response)
96
+ else
97
+ if self.class.web_service_exception_reporting
98
+ message = exception.message
99
+ backtrace = "\nBacktrace:\n#{exception.backtrace.join("\n")}"
100
+ else
101
+ message = "Exception raised"
102
+ backtrace = ""
103
+ end
104
+ render :status => 500, :text => "Internal protocol error: #{message}#{backtrace}"
105
+ end
106
+ end
107
+
108
+ def web_service_direct_invoke(invocation)
109
+ invocation.method_named_params.each do |name, value|
110
+ params[name] = value
111
+ end
112
+ web_service_direct_invoke_without_controller(invocation)
113
+ end
114
+
115
+ def log_request(ws_request, body)
116
+ unless logger.nil?
117
+ name = ws_request.method_name
118
+ api_method = ws_request.api_method
119
+ params = ws_request.method_params
120
+ if api_method && api_method.expects
121
+ params = api_method.expects.zip(params).map{ |type, param| "#{type.name}=>#{param.inspect}" }
122
+ else
123
+ params = params.map{ |param| param.inspect }
124
+ end
125
+ service = ws_request.service_name
126
+ logger.debug("\nWeb Service Request: #{name}(#{params.join(", ")}) Entrypoint: #{service}")
127
+ logger.debug(indent(body))
128
+ end
129
+ end
130
+
131
+ def log_response(ws_response, elapsed=nil)
132
+ unless logger.nil?
133
+ elapsed = (elapsed ? " (%f):" % elapsed : ":")
134
+ logger.debug("\nWeb Service Response" + elapsed + " => #{ws_response.return_value.inspect}")
135
+ logger.debug(indent(ws_response.body))
136
+ end
137
+ end
138
+
139
+ def indent(body)
140
+ body.split(/\n/).map{|x| " #{x}"}.join("\n")
141
+ end
142
+ end
143
+
144
+ module WsdlAction # :nodoc:
145
+ XsdNs = 'http://www.w3.org/2001/XMLSchema'
146
+ WsdlNs = 'http://schemas.xmlsoap.org/wsdl/'
147
+ SoapNs = 'http://schemas.xmlsoap.org/wsdl/soap/'
148
+ SoapEncodingNs = 'http://schemas.xmlsoap.org/soap/encoding/'
149
+ SoapHttpTransport = 'http://schemas.xmlsoap.org/soap/http'
150
+
151
+ def wsdl
152
+ case request.method
153
+ when :get
154
+ begin
155
+ options = { :type => 'text/xml', :disposition => 'inline' }
156
+ send_data(to_wsdl, options)
157
+ rescue Exception => e
158
+ log_error(e) unless logger.nil?
159
+ end
160
+ when :post
161
+ render :status => 500, :text => 'POST not supported'
162
+ end
163
+ end
164
+
165
+ private
166
+ def base_uri
167
+ host = request.host_with_port
168
+ relative_url_root = ::ActionController::Base.relative_url_root
169
+ scheme = request.ssl? ? 'https' : 'http'
170
+ '%s://%s%s/%s/' % [scheme, host, relative_url_root, self.class.controller_path]
171
+ end
172
+
173
+ def to_wsdl
174
+ xml = ''
175
+ dispatching_mode = web_service_dispatching_mode
176
+ global_service_name = wsdl_service_name
177
+ namespace = wsdl_namespace || 'urn:ActionWebService'
178
+ soap_action_base = "/#{controller_name}"
179
+
180
+ marshaler = ActionWebService::Protocol::Soap::SoapMarshaler.new(namespace)
181
+ apis = {}
182
+ case dispatching_mode
183
+ when :direct
184
+ api = self.class.web_service_api
185
+ web_service_name = controller_class_name.sub(/Controller$/, '').underscore
186
+ apis[web_service_name] = [api, register_api(api, marshaler)]
187
+ when :delegated, :layered
188
+ self.class.web_services.each do |web_service_name, info|
189
+ service = web_service_object(web_service_name)
190
+ api = service.class.web_service_api
191
+ apis[web_service_name] = [api, register_api(api, marshaler)]
192
+ end
193
+ end
194
+ custom_types = []
195
+ apis.values.each do |api, bindings|
196
+ bindings.each do |b|
197
+ custom_types << b unless custom_types.include?(b)
198
+ end
199
+ end
200
+
201
+ xm = Builder::XmlMarkup.new(:target => xml, :indent => 2)
202
+ xm.instruct!
203
+ xm.definitions('name' => wsdl_service_name,
204
+ 'targetNamespace' => namespace,
205
+ 'xmlns:typens' => namespace,
206
+ 'xmlns:xsd' => XsdNs,
207
+ 'xmlns:soap' => SoapNs,
208
+ 'xmlns:soapenc' => SoapEncodingNs,
209
+ 'xmlns:wsdl' => WsdlNs,
210
+ 'xmlns' => WsdlNs) do
211
+ # Generate XSD
212
+ if custom_types.size > 0
213
+ xm.types do
214
+ xm.xsd(:schema, 'xmlns' => XsdNs, 'targetNamespace' => namespace) do
215
+ simple_types, array_types, complex_types = [], [], []
216
+ custom_types.each do |binding|
217
+ case
218
+ when binding.type.simple? : simple_types.push binding
219
+ when binding.type.array? : array_types.push binding
220
+ when binding.type.structured? : complex_types.push binding
221
+ end
222
+ end
223
+ simple_types.each do |binding|
224
+ # TODO Should be able to determine if it will use camelize option
225
+ xm.xsd(:simpleType, 'name' => binding.type_name) do
226
+ xm.xsd(:restriction, 'base' => "xsd:#{binding.type.base}") do
227
+ binding.type.restrictions do |name, value|
228
+ xm.xsd(name.to_sym, 'value' => value)
229
+ end
230
+ end
231
+ end
232
+ end
233
+ array_types.each do |binding|
234
+ # TODO Should be able to determine if it will use camelize option
235
+ xm.xsd(:complexType, 'name' => binding.type_name) do
236
+ xm.xsd(:complexContent) do
237
+ xm.xsd(:restriction, 'base' => 'soapenc:Array') do
238
+ xm.xsd(:attribute, 'ref' => 'soapenc:arrayType',
239
+ 'wsdl:arrayType' => binding.element_binding.qualified_type_name('typens') + '[]')
240
+ end
241
+ end
242
+ end
243
+ end
244
+ complex_types.each do |binding|
245
+ # TODO Should be able to determine if it will use camelize option
246
+ xm.xsd(:complexType, 'name' => binding.type_name) do
247
+ xm.xsd(:all) do
248
+ binding.type.each_member do |name, type|
249
+ b = marshaler.register_type(type)
250
+ xm.xsd(:element, 'name' => name, 'type' => b.qualified_type_name('typens'))
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end
257
+ end
258
+
259
+ # APIs
260
+ apis.each do |api_name, values|
261
+ api = values[0]
262
+ api.api_methods.each do |name, method|
263
+ gen = lambda do |msg_name, direction|
264
+ xm.message('name' => message_name_for(api_name, msg_name)) do
265
+ sym = nil
266
+ if direction == :out
267
+ returns = method.returns
268
+ if returns
269
+ binding = marshaler.register_type(returns[0])
270
+ xm.part('name' => 'return', 'type' => binding.qualified_type_name('typens'))
271
+ end
272
+ else
273
+ expects = method.expects
274
+ expects.each do |type|
275
+ binding = marshaler.register_type(type)
276
+ xm.part('name' => type.name, 'type' => binding.qualified_type_name('typens'))
277
+ end if expects
278
+ end
279
+ end
280
+ end
281
+ public_name = method.public_name
282
+ gen.call(public_name, :in)
283
+ gen.call("#{public_name}Response", :out)
284
+ end
285
+
286
+ # Port
287
+ port_name = port_name_for(global_service_name, api_name)
288
+ xm.portType('name' => port_name) do
289
+ api.api_methods.each do |name, method|
290
+ xm.operation('name' => method.public_name) do
291
+ xm.input('message' => "typens:" + message_name_for(api_name, method.public_name))
292
+ xm.output('message' => "typens:" + message_name_for(api_name, "#{method.public_name}Response"))
293
+ end
294
+ end
295
+ end
296
+
297
+ # Bind it
298
+ binding_name = binding_name_for(global_service_name, api_name)
299
+ xm.binding('name' => binding_name, 'type' => "typens:#{port_name}") do
300
+ xm.soap(:binding, 'style' => 'rpc', 'transport' => SoapHttpTransport)
301
+ api.api_methods.each do |name, method|
302
+ xm.operation('name' => method.public_name) do
303
+ case web_service_dispatching_mode
304
+ when :direct
305
+ soap_action = soap_action_base + "/api/" + method.public_name
306
+ when :delegated, :layered
307
+ soap_action = soap_action_base \
308
+ + "/" + api_name.to_s \
309
+ + "/" + method.public_name
310
+ end
311
+ xm.soap(:operation, 'soapAction' => soap_action)
312
+ xm.input do
313
+ xm.soap(:body,
314
+ 'use' => 'encoded',
315
+ 'namespace' => namespace,
316
+ 'encodingStyle' => SoapEncodingNs)
317
+ end
318
+ xm.output do
319
+ xm.soap(:body,
320
+ 'use' => 'encoded',
321
+ 'namespace' => namespace,
322
+ 'encodingStyle' => SoapEncodingNs)
323
+ end
324
+ end
325
+ end
326
+ end
327
+ end
328
+
329
+ # Define it
330
+ xm.service('name' => "#{global_service_name}Service") do
331
+ apis.each do |api_name, values|
332
+ port_name = port_name_for(global_service_name, api_name)
333
+ binding_name = binding_name_for(global_service_name, api_name)
334
+ case web_service_dispatching_mode
335
+ when :direct, :layered
336
+ binding_target = 'api'
337
+ when :delegated
338
+ binding_target = api_name.to_s
339
+ end
340
+ xm.port('name' => port_name, 'binding' => "typens:#{binding_name}") do
341
+ xm.soap(:address, 'location' => "#{base_uri}#{binding_target}")
342
+ end
343
+ end
344
+ end
345
+ end
346
+ end
347
+
348
+ def port_name_for(global_service, service)
349
+ "#{global_service}#{service.to_s.camelize}Port"
350
+ end
351
+
352
+ def binding_name_for(global_service, service)
353
+ "#{global_service}#{service.to_s.camelize}Binding"
354
+ end
355
+
356
+ def message_name_for(api_name, message_name)
357
+ mode = web_service_dispatching_mode
358
+ if mode == :layered || mode == :delegated
359
+ api_name.to_s + '-' + message_name
360
+ else
361
+ message_name
362
+ end
363
+ end
364
+
365
+ def register_api(api, marshaler)
366
+ bindings = {}
367
+ traverse_custom_types(api, marshaler, bindings) do |binding|
368
+ bindings[binding] = nil unless bindings.has_key?(binding)
369
+ element_binding = binding.element_binding
370
+ bindings[element_binding] = nil if element_binding && !bindings.has_key?(element_binding)
371
+ end
372
+ bindings.keys
373
+ end
374
+
375
+ def traverse_custom_types(api, marshaler, bindings, &block)
376
+ api.api_methods.each do |name, method|
377
+ expects, returns = method.expects, method.returns
378
+ expects.each{ |type| traverse_type(marshaler, type, bindings, &block) if type.custom? } if expects
379
+ returns.each{ |type| traverse_type(marshaler, type, bindings, &block) if type.custom? } if returns
380
+ end
381
+ end
382
+
383
+ def traverse_type(marshaler, type, bindings, &block)
384
+ binding = marshaler.register_type(type)
385
+ return if bindings.has_key?(binding)
386
+ bindings[binding] = nil
387
+ yield binding
388
+ if type.array?
389
+ yield marshaler.register_type(type.element_type)
390
+ type = type.element_type
391
+ end
392
+ type.each_member{ |name, type| traverse_type(marshaler, type, bindings, &block) } if type.structured?
393
+ end
394
+ end
395
+ end
396
+ end
397
+ end