actionwebservice 0.5.0 → 0.6.0
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.
- data/{ChangeLog → CHANGELOG} +20 -0
- data/README +45 -1
- data/Rakefile +12 -10
- data/TODO +8 -9
- data/lib/action_web_service.rb +10 -6
- data/lib/action_web_service/api.rb +1 -2
- data/lib/action_web_service/api/{abstract.rb → base.rb} +14 -71
- data/lib/action_web_service/base.rb +0 -3
- data/lib/action_web_service/client/base.rb +1 -12
- data/lib/action_web_service/client/soap_client.rb +49 -17
- data/lib/action_web_service/client/xmlrpc_client.rb +20 -15
- data/lib/action_web_service/container.rb +3 -85
- data/lib/action_web_service/{api/action_controller.rb → container/action_controller_container.rb} +2 -2
- data/lib/action_web_service/container/delegated_container.rb +87 -0
- data/lib/action_web_service/container/direct_container.rb +70 -0
- data/lib/action_web_service/dispatcher/abstract.rb +100 -102
- data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +199 -137
- data/lib/action_web_service/protocol.rb +1 -1
- data/lib/action_web_service/protocol/abstract.rb +14 -112
- data/lib/action_web_service/protocol/discovery.rb +37 -0
- data/lib/action_web_service/protocol/soap_protocol.rb +32 -458
- data/lib/action_web_service/protocol/xmlrpc_protocol.rb +29 -149
- data/lib/action_web_service/struct.rb +2 -5
- data/lib/action_web_service/test_invoke.rb +130 -0
- data/lib/action_web_service/vendor/ws.rb +4 -0
- data/lib/action_web_service/vendor/ws/common.rb +8 -0
- data/lib/action_web_service/vendor/ws/encoding.rb +3 -0
- data/lib/action_web_service/vendor/ws/encoding/abstract.rb +26 -0
- data/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb +90 -0
- data/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb +53 -0
- data/lib/action_web_service/vendor/ws/marshaling.rb +3 -0
- data/lib/action_web_service/vendor/ws/marshaling/abstract.rb +17 -0
- data/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb +277 -0
- data/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb +116 -0
- data/lib/action_web_service/vendor/ws/types.rb +162 -0
- data/test/abstract_client.rb +8 -11
- data/test/abstract_dispatcher.rb +370 -0
- data/test/abstract_unit.rb +1 -0
- data/test/api_test.rb +18 -1
- data/test/apis/auto_load_api.rb +3 -0
- data/test/apis/broken_auto_load_api.rb +2 -0
- data/test/client_soap_test.rb +16 -3
- data/test/client_xmlrpc_test.rb +16 -4
- data/test/container_test.rb +28 -8
- data/test/dispatcher_action_controller_soap_test.rb +106 -0
- data/test/dispatcher_action_controller_xmlrpc_test.rb +44 -0
- data/test/gencov +1 -1
- data/test/invocation_test.rb +39 -3
- data/test/run +4 -4
- data/test/test_invoke_test.rb +77 -0
- data/test/ws/abstract_encoding.rb +68 -0
- data/test/ws/abstract_unit.rb +13 -0
- data/test/ws/gencov +3 -0
- data/test/ws/run +5 -0
- data/test/ws/soap_marshaling_test.rb +91 -0
- data/test/ws/soap_rpc_encoding_test.rb +47 -0
- data/test/ws/types_test.rb +41 -0
- data/test/ws/xmlrpc_encoding_test.rb +34 -0
- metadata +48 -19
- data/lib/action_web_service/protocol/registry.rb +0 -55
- data/lib/action_web_service/support/signature.rb +0 -100
- data/test/abstract_soap.rb +0 -58
- data/test/dispatcher_action_controller_test.rb +0 -186
- data/test/protocol_registry_test.rb +0 -53
- data/test/protocol_soap_test.rb +0 -252
- data/test/protocol_xmlrpc_test.rb +0 -147
@@ -1,126 +1,28 @@
|
|
1
1
|
module ActionWebService # :nodoc:
|
2
2
|
module Protocol # :nodoc:
|
3
|
-
|
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
|
6
|
+
class Request # :nodoc:
|
89
7
|
attr :protocol
|
90
|
-
attr :
|
8
|
+
attr :method_name
|
9
|
+
attr :method_params
|
10
|
+
attr :service_name
|
91
11
|
|
92
|
-
|
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
|
-
@
|
100
|
-
@
|
101
|
-
@
|
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
|
115
|
-
attr :
|
116
|
-
attr :
|
117
|
-
|
118
|
-
attr_accessor :content_type
|
20
|
+
class Response # :nodoc:
|
21
|
+
attr :body
|
22
|
+
attr :content_type
|
119
23
|
|
120
|
-
def initialize(
|
121
|
-
|
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
|
-
|
12
|
-
|
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
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
service_name =
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
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
|
90
|
-
|
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
|
117
|
-
|
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
|
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
|