actionwebservice 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/{ChangeLog → CHANGELOG} +20 -0
  2. data/README +45 -1
  3. data/Rakefile +12 -10
  4. data/TODO +8 -9
  5. data/lib/action_web_service.rb +10 -6
  6. data/lib/action_web_service/api.rb +1 -2
  7. data/lib/action_web_service/api/{abstract.rb → base.rb} +14 -71
  8. data/lib/action_web_service/base.rb +0 -3
  9. data/lib/action_web_service/client/base.rb +1 -12
  10. data/lib/action_web_service/client/soap_client.rb +49 -17
  11. data/lib/action_web_service/client/xmlrpc_client.rb +20 -15
  12. data/lib/action_web_service/container.rb +3 -85
  13. data/lib/action_web_service/{api/action_controller.rb → container/action_controller_container.rb} +2 -2
  14. data/lib/action_web_service/container/delegated_container.rb +87 -0
  15. data/lib/action_web_service/container/direct_container.rb +70 -0
  16. data/lib/action_web_service/dispatcher/abstract.rb +100 -102
  17. data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +199 -137
  18. data/lib/action_web_service/protocol.rb +1 -1
  19. data/lib/action_web_service/protocol/abstract.rb +14 -112
  20. data/lib/action_web_service/protocol/discovery.rb +37 -0
  21. data/lib/action_web_service/protocol/soap_protocol.rb +32 -458
  22. data/lib/action_web_service/protocol/xmlrpc_protocol.rb +29 -149
  23. data/lib/action_web_service/struct.rb +2 -5
  24. data/lib/action_web_service/test_invoke.rb +130 -0
  25. data/lib/action_web_service/vendor/ws.rb +4 -0
  26. data/lib/action_web_service/vendor/ws/common.rb +8 -0
  27. data/lib/action_web_service/vendor/ws/encoding.rb +3 -0
  28. data/lib/action_web_service/vendor/ws/encoding/abstract.rb +26 -0
  29. data/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb +90 -0
  30. data/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb +53 -0
  31. data/lib/action_web_service/vendor/ws/marshaling.rb +3 -0
  32. data/lib/action_web_service/vendor/ws/marshaling/abstract.rb +17 -0
  33. data/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb +277 -0
  34. data/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb +116 -0
  35. data/lib/action_web_service/vendor/ws/types.rb +162 -0
  36. data/test/abstract_client.rb +8 -11
  37. data/test/abstract_dispatcher.rb +370 -0
  38. data/test/abstract_unit.rb +1 -0
  39. data/test/api_test.rb +18 -1
  40. data/test/apis/auto_load_api.rb +3 -0
  41. data/test/apis/broken_auto_load_api.rb +2 -0
  42. data/test/client_soap_test.rb +16 -3
  43. data/test/client_xmlrpc_test.rb +16 -4
  44. data/test/container_test.rb +28 -8
  45. data/test/dispatcher_action_controller_soap_test.rb +106 -0
  46. data/test/dispatcher_action_controller_xmlrpc_test.rb +44 -0
  47. data/test/gencov +1 -1
  48. data/test/invocation_test.rb +39 -3
  49. data/test/run +4 -4
  50. data/test/test_invoke_test.rb +77 -0
  51. data/test/ws/abstract_encoding.rb +68 -0
  52. data/test/ws/abstract_unit.rb +13 -0
  53. data/test/ws/gencov +3 -0
  54. data/test/ws/run +5 -0
  55. data/test/ws/soap_marshaling_test.rb +91 -0
  56. data/test/ws/soap_rpc_encoding_test.rb +47 -0
  57. data/test/ws/types_test.rb +41 -0
  58. data/test/ws/xmlrpc_encoding_test.rb +34 -0
  59. metadata +48 -19
  60. data/lib/action_web_service/protocol/registry.rb +0 -55
  61. data/lib/action_web_service/support/signature.rb +0 -100
  62. data/test/abstract_soap.rb +0 -58
  63. data/test/dispatcher_action_controller_test.rb +0 -186
  64. data/test/protocol_registry_test.rb +0 -53
  65. data/test/protocol_soap_test.rb +0 -252
  66. data/test/protocol_xmlrpc_test.rb +0 -147
@@ -1,4 +1,4 @@
1
1
  require 'action_web_service/protocol/abstract'
2
- require 'action_web_service/protocol/registry'
2
+ require 'action_web_service/protocol/discovery'
3
3
  require 'action_web_service/protocol/soap_protocol'
4
4
  require 'action_web_service/protocol/xmlrpc_protocol'
@@ -1,126 +1,28 @@
1
1
  module ActionWebService # :nodoc:
2
2
  module Protocol # :nodoc:
3
- CheckedMessage = :checked
4
- UncheckedMessage = :unchecked
5
-
6
- class ProtocolError < ActionWebService::ActionWebServiceError # :nodoc:
7
- end
8
-
9
- class AbstractProtocol # :nodoc:
10
- attr :container_class
11
-
12
- def initialize(container_class)
13
- @container_class = container_class
14
- end
15
-
16
- def unmarshal_request(protocol_request)
17
- raise NotImplementedError
18
- end
19
-
20
- def marshal_response(protocol_request, return_value)
21
- raise NotImplementedError
22
- end
23
-
24
- def marshal_exception(exception)
25
- raise NotImplementedError
26
- end
27
-
28
- def self.create_protocol_request(container_class, action_pack_request)
29
- nil
30
- end
31
-
32
- def self.create_protocol_client(api, protocol_name, endpoint_uri, options)
33
- nil
34
- end
35
- end
36
-
37
- class AbstractProtocolMessage # :nodoc:
38
- attr_accessor :signature
39
- attr_accessor :return_signature
40
- attr_accessor :type
41
- attr :options
42
-
43
- def initialize(options={})
44
- @signature = @return_signature = nil
45
- @options = options
46
- @type = @options[:type] || CheckedMessage
47
- end
48
-
49
- def signature=(value)
50
- return if value.nil?
51
- @signature = []
52
- value.each do |klass|
53
- if klass.is_a?(Hash)
54
- @signature << klass.values.shift
55
- else
56
- @signature << klass
57
- end
58
- end
59
- @signature
60
- end
61
-
62
- def checked?
63
- @type == CheckedMessage
64
- end
65
-
66
- def check_parameter_types(values, signature)
67
- return unless checked? && signature
68
- unless signature.length == values.length
69
- raise(ProtocolError, "Signature and parameter lengths mismatch")
70
- end
71
- (1..signature.length).each do |i|
72
- check_compatibility(signature[i-1], values[i-1].class)
73
- end
74
- end
75
-
76
- def check_compatibility(expected_class, received_class)
77
- return if \
78
- (expected_class == TrueClass or expected_class == FalseClass) and \
79
- (received_class == TrueClass or received_class == FalseClass)
80
- unless received_class.ancestors.include?(expected_class) or \
81
- expected_class.ancestors.include?(received_class)
82
- raise(ProtocolError, "value of type #{received_class.name} is not " +
83
- "compatible with expected type #{expected_class.name}")
84
- end
85
- end
3
+ class ProtocolError < ActionWebServiceError # :nodoc:
86
4
  end
87
5
 
88
- class ProtocolRequest < AbstractProtocolMessage # :nodoc:
6
+ class Request # :nodoc:
89
7
  attr :protocol
90
- attr :raw_body
8
+ attr :method_name
9
+ attr :method_params
10
+ attr :service_name
91
11
 
92
- attr_accessor :web_service_name
93
- attr_accessor :public_method_name
94
- attr_accessor :content_type
95
-
96
- def initialize(protocol, raw_body, web_service_name, public_method_name, content_type, options={})
97
- super(options)
12
+ def initialize(protocol, method_name, method_params, service_name)
98
13
  @protocol = protocol
99
- @raw_body = raw_body
100
- @web_service_name = web_service_name
101
- @public_method_name = public_method_name
102
- @content_type = content_type
103
- end
104
-
105
- def unmarshal
106
- @protocol.unmarshal_request(self)
107
- end
108
-
109
- def marshal(return_value)
110
- @protocol.marshal_response(self, return_value)
14
+ @method_name = method_name
15
+ @method_params = method_params
16
+ @service_name = service_name
111
17
  end
112
18
  end
113
19
 
114
- class ProtocolResponse < AbstractProtocolMessage # :nodoc:
115
- attr :protocol
116
- attr :raw_body
117
-
118
- attr_accessor :content_type
20
+ class Response # :nodoc:
21
+ attr :body
22
+ attr :content_type
119
23
 
120
- def initialize(protocol, raw_body, content_type, options={})
121
- super(options)
122
- @protocol = protocol
123
- @raw_body = raw_body
24
+ def initialize(body, content_type)
25
+ @body = body
124
26
  @content_type = content_type
125
27
  end
126
28
  end
@@ -0,0 +1,37 @@
1
+ module ActionWebService # :nodoc:
2
+ module Protocol # :nodoc:
3
+ module Discovery # :nodoc:
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ base.send(:include, ActionWebService::Protocol::Discovery::InstanceMethods)
7
+ end
8
+
9
+ module ClassMethods # :nodoc:
10
+ def register_protocol(klass)
11
+ write_inheritable_array("web_service_protocols", [klass])
12
+ end
13
+ end
14
+
15
+ module InstanceMethods # :nodoc:
16
+ private
17
+ def discover_web_service_request(ap_request)
18
+ (self.class.read_inheritable_attribute("web_service_protocols") || []).each do |protocol|
19
+ protocol = protocol.new
20
+ request = protocol.unmarshal_request(ap_request)
21
+ return request unless request.nil?
22
+ end
23
+ nil
24
+ end
25
+
26
+ def create_web_service_client(api, protocol_name, endpoint_uri, options)
27
+ (self.class.read_inheritable_attribute("web_service_protocols") || []).each do |protocol|
28
+ protocol = protocol.new
29
+ client = protocol.protocol_client(api, protocol_name, endpoint_uri, options)
30
+ return client unless client.nil?
31
+ end
32
+ nil
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,127 +1,49 @@
1
- require 'soap/processor'
2
- require 'soap/mapping'
3
- require 'soap/rpc/element'
4
- require 'xsd/datatypes'
5
- require 'xsd/ns'
6
- require 'singleton'
7
-
8
1
  module ActionWebService # :nodoc:
9
2
  module Protocol # :nodoc:
10
3
  module Soap # :nodoc:
11
- class ProtocolError < ActionWebService::ActionWebServiceError # :nodoc:
12
- end
13
-
14
- def self.append_features(base) # :nodoc:
15
- super
16
- base.register_protocol(HeaderAndBody, SoapProtocol)
17
- base.extend(ClassMethods)
18
- base.wsdl_service_name('ActionWebService')
19
- end
20
-
21
- module ClassMethods
22
- # Specifies the WSDL service name to use when generating WSDL. Highly
23
- # recommended that you set this value, or code generators may generate
24
- # classes with very generic names.
25
- #
26
- # === Example
27
- # class MyController < ActionController::Base
28
- # wsdl_service_name 'MyService'
29
- # end
30
- def wsdl_service_name(name)
31
- write_inheritable_attribute("soap_mapper", SoapMapper.new("urn:#{name}"))
32
- end
33
-
34
- def soap_mapper # :nodoc:
35
- read_inheritable_attribute("soap_mapper")
36
- end
4
+ def self.included(base)
5
+ base.register_protocol(SoapProtocol)
6
+ base.class_inheritable_option(:wsdl_service_name)
37
7
  end
38
-
39
- class SoapProtocol < AbstractProtocol # :nodoc:
40
- attr :mapper
41
-
42
- def initialize(mapper)
43
- @mapper = mapper
44
- end
45
-
46
- def self.create_protocol_request(container_class, action_pack_request)
47
- soap_action = extract_soap_action(action_pack_request)
48
- return nil unless soap_action
49
- service_name = action_pack_request.parameters['action']
50
- public_method_name = soap_action.gsub(/^[\/]+/, '').split(/[\/]+/)[-1]
51
- content_type = action_pack_request.env['HTTP_CONTENT_TYPE']
52
- content_type ||= 'text/xml'
53
- protocol = SoapProtocol.new(container_class.soap_mapper)
54
- ProtocolRequest.new(protocol,
55
- action_pack_request.raw_post,
56
- service_name.to_sym,
57
- public_method_name,
58
- content_type)
59
- end
60
-
61
- def self.create_protocol_client(api, protocol_name, endpoint_uri, options)
62
- return nil unless protocol_name.to_s.downcase.to_sym == :soap
63
- ActionWebService::Client::Soap.new(api, endpoint_uri, options)
64
- end
65
-
66
- def unmarshal_request(protocol_request)
67
- unmarshal = lambda do
68
- envelope = SOAP::Processor.unmarshal(protocol_request.raw_body)
69
- request = envelope.body.request
70
- values = request.collect{|k, v| request[k]}
71
- soap_to_ruby_array(values)
72
- end
73
- signature = protocol_request.signature
74
- if signature
75
- map_signature_types(signature)
76
- values = unmarshal.call
77
- signature = signature.map{|x|mapper.lookup(x).ruby_klass}
78
- protocol_request.check_parameter_types(values, signature)
79
- values
8
+
9
+ class SoapProtocol # :nodoc:
10
+ def initialize
11
+ @encoder = WS::Encoding::SoapRpcEncoding.new 'urn:ActionWebService'
12
+ @marshaler = WS::Marshaling::SoapMarshaler.new 'urn:ActionWebService'
13
+ end
14
+
15
+ def unmarshal_request(ap_request)
16
+ return nil unless has_valid_soap_action?(ap_request)
17
+ method_name, params = @encoder.decode_rpc_call(ap_request.raw_post)
18
+ params = params.map{|x| @marshaler.unmarshal(x)}
19
+ service_name = ap_request.parameters['action']
20
+ Request.new(self, method_name, params, service_name)
21
+ end
22
+
23
+ def marshal_response(method_name, return_value, signature_type)
24
+ if !return_value.nil? && signature_type
25
+ type_binding = @marshaler.register_type(signature_type)
26
+ info = WS::ParamInfo.create(signature_type, type_binding, 0)
27
+ return_value = @marshaler.marshal(WS::Param.new(return_value, info))
80
28
  else
81
- if protocol_request.checked?
82
- []
83
- else
84
- unmarshal.call
85
- end
29
+ return_value = nil
86
30
  end
31
+ body = @encoder.encode_rpc_response(method_name, return_value)
32
+ Response.new(body, 'text/xml')
87
33
  end
88
34
 
89
- def marshal_response(protocol_request, return_value)
90
- marshal = lambda do |signature|
91
- mapping = mapper.lookup(signature[0])
92
- return_value = fixup_array_types(mapping, return_value)
93
- signature = signature.map{|x|mapper.lookup(x).ruby_klass}
94
- protocol_request.check_parameter_types([return_value], signature)
95
- param_def = [['retval', 'return', mapping.registry_mapping]]
96
- [param_def, ruby_to_soap(return_value)]
97
- end
98
- signature = protocol_request.return_signature
99
- param_def = nil
100
- if signature
101
- param_def, return_value = marshal.call(signature)
102
- else
103
- if protocol_request.checked?
104
- param_def, return_value = nil, nil
105
- else
106
- param_def, return_value = marshal.call([return_value.class])
107
- end
108
- end
109
- qname = XSD::QName.new(mapper.custom_namespace,
110
- protocol_request.public_method_name)
111
- response = SOAP::RPC::SOAPMethodResponse.new(qname, param_def)
112
- response.retval = return_value unless return_value.nil?
113
- ProtocolResponse.new(self, create_response(response), 'text/xml')
35
+ def register_signature_type(spec)
36
+ @marshaler.register_type(spec)
114
37
  end
115
38
 
116
- def marshal_exception(exc)
117
- ProtocolResponse.new(self, create_exception_response(exc), 'text/xml')
39
+ def protocol_client(api, protocol_name, endpoint_uri, options)
40
+ return nil unless protocol_name == :soap
41
+ ActionWebService::Client::Soap.new(api, endpoint_uri, options)
118
42
  end
119
43
 
120
44
  private
121
- def self.extract_soap_action(request)
45
+ def has_valid_soap_action?(request)
122
46
  return nil unless request.method == :post
123
- content_type = request.env['HTTP_CONTENT_TYPE'] || 'text/xml'
124
- return nil unless content_type
125
47
  soap_action = request.env['HTTP_SOAPACTION']
126
48
  return nil unless soap_action
127
49
  soap_action.gsub!(/^"/, '')
@@ -130,355 +52,7 @@ module ActionWebService # :nodoc:
130
52
  return nil if soap_action.empty?
131
53
  soap_action
132
54
  end
133
-
134
- def fixup_array_types(mapping, obj)
135
- mapping.each_attribute do |name, type, attr_mapping|
136
- if attr_mapping.custom_type?
137
- attr_obj = obj.send(name)
138
- new_obj = fixup_array_types(attr_mapping, attr_obj)
139
- obj.send("#{name}=", new_obj) unless new_obj.equal?(attr_obj)
140
- end
141
- end
142
- if mapping.is_a?(SoapArrayMapping)
143
- obj = mapping.ruby_klass.new(obj)
144
- # man, this is going to be slow for big arrays :(
145
- (1..obj.size).each do |i|
146
- i -= 1
147
- obj[i] = fixup_array_types(mapping.element_mapping, obj[i])
148
- end
149
- else
150
- if !mapping.generated_klass.nil? && mapping.generated_klass.respond_to?(:members)
151
- # have to map the publically visible structure of the class
152
- new_obj = mapping.generated_klass.new
153
- mapping.generated_klass.members.each do |name, klass|
154
- new_obj.send("#{name}=", obj.send(name))
155
- end
156
- obj = new_obj
157
- end
158
- end
159
- obj
160
- end
161
-
162
- def map_signature_types(types)
163
- types.collect{|type| mapper.map(type)}
164
- end
165
-
166
- def create_response(body)
167
- header = SOAP::SOAPHeader.new
168
- body = SOAP::SOAPBody.new(body)
169
- envelope = SOAP::SOAPEnvelope.new(header, body)
170
- SOAP::Processor.marshal(envelope)
171
- end
172
-
173
- def create_exception_response(exc)
174
- detail = SOAP::Mapping::SOAPException.new(exc)
175
- body = SOAP::SOAPFault.new(
176
- SOAP::SOAPString.new('Server'),
177
- SOAP::SOAPString.new(exc.to_s),
178
- SOAP::SOAPString.new(self.class.name),
179
- SOAP::Mapping.obj2soap(detail))
180
- create_response(body)
181
- end
182
-
183
- def ruby_to_soap(obj)
184
- SOAP::Mapping.obj2soap(obj, mapper.registry)
185
- end
186
-
187
- def soap_to_ruby(obj)
188
- SOAP::Mapping.soap2obj(obj, mapper.registry)
189
- end
190
-
191
- def soap_to_ruby_array(array)
192
- array.map{|x| soap_to_ruby(x)}
193
- end
194
- end
195
-
196
- class SoapMapper # :nodoc:
197
- attr :registry
198
- attr :custom_namespace
199
- attr :custom_types
200
-
201
- def initialize(custom_namespace)
202
- @custom_namespace = custom_namespace
203
- @registry = SOAP::Mapping::Registry.new
204
- @klass2map = {}
205
- @custom_types = {}
206
- @ar2klass = {}
207
55
  end
208
-
209
- def lookup(klass)
210
- lookup_klass = klass.is_a?(Array) ? klass[0] : klass
211
- generated_klass = nil
212
- unless lookup_klass.respond_to?(:ancestors)
213
- raise(ProtocolError, "expected parameter type definition to be a Class")
214
- end
215
- if lookup_klass.ancestors.include?(ActiveRecord::Base)
216
- generated_klass = @ar2klass.has_key?(klass) ? @ar2klass[klass] : nil
217
- klass = generated_klass if generated_klass
218
- end
219
- return @klass2map[klass] if @klass2map.has_key?(klass)
220
-
221
- custom_type = false
222
-
223
- ruby_klass = select_class(lookup_klass)
224
- generated_klass = @ar2klass[lookup_klass] if @ar2klass.has_key?(lookup_klass)
225
- type_name = ruby_klass.name
226
-
227
- # Array signatures generate a double-mapping and require generation
228
- # of an Array subclass to represent the mapping in the SOAP
229
- # registry
230
- array_klass = nil
231
- if klass.is_a?(Array)
232
- array_klass = Class.new(Array) do
233
- module_eval <<-END
234
- def self.name
235
- "#{type_name}Array"
236
- end
237
- END
238
- end
239
- end
240
-
241
- mapping = @registry.find_mapped_soap_class(ruby_klass) rescue nil
242
- unless mapping
243
- # Custom structured type, generate a mapping
244
- info = { :type => XSD::QName.new(@custom_namespace, type_name) }
245
- @registry.add(ruby_klass,
246
- SOAP::SOAPStruct,
247
- SOAP::Mapping::Registry::TypedStructFactory,
248
- info)
249
- mapping = ensure_mapped(ruby_klass)
250
- custom_type = true
251
- end
252
-
253
- array_mapping = nil
254
- if array_klass
255
- # Typed array always requires a custom type. The info of the array
256
- # is the info of its element type (in mapping[2]), falling back
257
- # to SOAP base types.
258
- info = mapping[2]
259
- info ||= {}
260
- info[:type] ||= soap_base_type_qname(mapping[0])
261
- @registry.add(array_klass,
262
- SOAP::SOAPArray,
263
- SOAP::Mapping::Registry::TypedArrayFactory,
264
- info)
265
- array_mapping = ensure_mapped(array_klass)
266
- end
267
-
268
- if array_mapping
269
- @klass2map[ruby_klass] = SoapMapping.new(self,
270
- type_name,
271
- ruby_klass,
272
- generated_klass,
273
- mapping[0],
274
- mapping,
275
- custom_type)
276
- @klass2map[klass] = SoapArrayMapping.new(self,
277
- type_name,
278
- array_klass,
279
- array_mapping[0],
280
- array_mapping,
281
- @klass2map[ruby_klass])
282
- @custom_types[klass] = @klass2map[klass]
283
- @custom_types[ruby_klass] = @klass2map[ruby_klass] if custom_type
284
- else
285
- @klass2map[klass] = SoapMapping.new(self,
286
- type_name,
287
- ruby_klass,
288
- generated_klass,
289
- mapping[0],
290
- mapping,
291
- custom_type)
292
- @custom_types[klass] = @klass2map[klass] if custom_type
293
- end
294
-
295
- @klass2map[klass]
296
- end
297
- alias :map :lookup
298
-
299
- def map_container_services(container, &block)
300
- dispatching_mode = container.web_service_dispatching_mode
301
- web_services = nil
302
- case dispatching_mode
303
- when :direct
304
- api = container.class.web_service_api
305
- if container.respond_to?(:controller_class_name)
306
- web_service_name = container.controller_class_name.sub(/Controller$/, '').underscore
307
- else
308
- web_service_name = container.class.name.demodulize.underscore
309
- end
310
- web_services = { web_service_name => api }
311
- when :delegated
312
- web_services = {}
313
- container.class.web_services.each do |web_service_name, web_service_info|
314
- begin
315
- object = container.web_service_object(web_service_name)
316
- rescue Exception => e
317
- raise(ProtocolError, "failed to retrieve web service object for web service '#{web_service_name}': #{e.message}")
318
- end
319
- web_services[web_service_name] = object.class.web_service_api
320
- end
321
- end
322
- web_services.each do |web_service_name, api|
323
- if api.nil?
324
- raise(ProtocolError, "no web service API set while in :#{dispatching_mode} mode")
325
- end
326
- map_api(api) do |api_methods|
327
- yield web_service_name, api, api_methods if block_given?
328
- end
329
- end
330
- end
331
-
332
- def map_api(api, &block)
333
- lookup_proc = lambda do |klass|
334
- mapping = lookup(klass)
335
- custom_mapping = nil
336
- if mapping.respond_to?(:element_mapping)
337
- custom_mapping = mapping.element_mapping
338
- else
339
- custom_mapping = mapping
340
- end
341
- if custom_mapping && custom_mapping.custom_type?
342
- # What gives? This is required so that structure types
343
- # referenced only by structures (and not signatures) still
344
- # have a custom type mapping in the registry (needed for WSDL
345
- # generation).
346
- custom_mapping.each_attribute{}
347
- end
348
- mapping
349
- end
350
- api_methods = block.nil?? nil : {}
351
- api.api_methods.each do |method_name, method_info|
352
- expects = method_info[:expects]
353
- expects_signature = nil
354
- if expects
355
- expects_signature = block ? [] : nil
356
- expects.each do |klass|
357
- lookup_klass = nil
358
- if klass.is_a?(Hash)
359
- lookup_klass = lookup_proc.call(klass.values[0])
360
- expects_signature << {klass.keys[0]=>lookup_klass} if block
361
- else
362
- lookup_klass = lookup_proc.call(klass)
363
- expects_signature << lookup_klass if block
364
- end
365
- end
366
- end
367
- returns = method_info[:returns]
368
- returns_signature = returns ? returns.map{|klass| lookup_proc.call(klass)} : nil
369
- if block
370
- api_methods[method_name] = {
371
- :expects => expects_signature,
372
- :returns => returns_signature
373
- }
374
- end
375
- end
376
- yield api_methods if block
377
- end
378
-
379
- private
380
- def select_class(klass)
381
- return Integer if klass == Fixnum
382
- if klass.ancestors.include?(ActiveRecord::Base)
383
- new_klass = Class.new(ActionWebService::Struct)
384
- new_klass.class_eval <<-EOS
385
- def self.name
386
- "#{klass.name}"
387
- end
388
- EOS
389
- klass.columns.each do |column|
390
- next if column.klass.nil?
391
- new_klass.send(:member, column.name.to_sym, column.klass)
392
- end
393
- @ar2klass[klass] = new_klass
394
- return new_klass
395
- end
396
- klass
397
- end
398
-
399
- def ensure_mapped(klass)
400
- mapping = @registry.find_mapped_soap_class(klass) rescue nil
401
- raise(ProtocolError, "failed to register #{klass.name}") unless mapping
402
- mapping
403
- end
404
-
405
- def soap_base_type_qname(base_type)
406
- xsd_type = base_type.ancestors.find{|c| c.const_defined? 'Type'}
407
- xsd_type ? xsd_type.const_get('Type') : XSD::XSDAnySimpleType::Type
408
- end
409
- end
410
-
411
- class SoapMapping # :nodoc:
412
- attr :ruby_klass
413
- attr :generated_klass
414
- attr :soap_klass
415
- attr :registry_mapping
416
-
417
- def initialize(mapper, type_name, ruby_klass, generated_klass, soap_klass, registry_mapping,
418
- custom_type=false)
419
- @mapper = mapper
420
- @type_name = type_name
421
- @ruby_klass = ruby_klass
422
- @generated_klass = generated_klass
423
- @soap_klass = soap_klass
424
- @registry_mapping = registry_mapping
425
- @custom_type = custom_type
426
- end
427
-
428
- def type_name
429
- @type_name
430
- end
431
-
432
- def custom_type?
433
- @custom_type
434
- end
435
-
436
- def qualified_type_name
437
- name = type_name
438
- if custom_type?
439
- "typens:#{name}"
440
- else
441
- xsd_type_for(@soap_klass)
442
- end
443
- end
444
-
445
- def each_attribute(&block)
446
- if @ruby_klass.respond_to?(:members)
447
- @ruby_klass.members.each do |name, klass|
448
- name = name.to_s
449
- mapping = @mapper.lookup(klass)
450
- yield name, mapping.qualified_type_name, mapping
451
- end
452
- end
453
- end
454
-
455
- def is_xsd_type?(klass)
456
- klass.ancestors.include?(XSD::NSDBase)
457
- end
458
-
459
- def xsd_type_for(klass)
460
- ns = XSD::NS.new
461
- ns.assign(XSD::Namespace, SOAP::XSDNamespaceTag)
462
- xsd_klass = klass.ancestors.find{|c| c.const_defined?('Type')}
463
- return ns.name(XSD::AnyTypeName) unless xsd_klass
464
- ns.name(xsd_klass.const_get('Type'))
465
- end
466
- end
467
-
468
- class SoapArrayMapping < SoapMapping # :nodoc:
469
- attr :element_mapping
470
-
471
- def initialize(mapper, type_name, ruby_klass, soap_klass, registry_mapping, element_mapping)
472
- super(mapper, type_name, ruby_klass, nil, soap_klass, registry_mapping, true)
473
- @element_mapping = element_mapping
474
- end
475
-
476
- def type_name
477
- super + "Array"
478
- end
479
-
480
- def each_attribute(&block); end
481
- end
482
56
  end
483
57
  end
484
58
  end