axtro-actionwebservice 2.3.5.1.20101118142125
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 +335 -0
- data/MIT-LICENSE +21 -0
- data/README +381 -0
- data/Rakefile +184 -0
- data/TODO +32 -0
- data/examples/googlesearch/README +143 -0
- data/examples/googlesearch/autoloading/google_search_api.rb +51 -0
- data/examples/googlesearch/autoloading/google_search_controller.rb +58 -0
- data/examples/googlesearch/delegated/google_search_service.rb +109 -0
- data/examples/googlesearch/delegated/search_controller.rb +8 -0
- data/examples/googlesearch/direct/google_search_api.rb +51 -0
- data/examples/googlesearch/direct/search_controller.rb +59 -0
- data/examples/metaWeblog/README +17 -0
- data/examples/metaWeblog/apis/blogger_api.rb +61 -0
- data/examples/metaWeblog/apis/blogger_service.rb +35 -0
- data/examples/metaWeblog/apis/meta_weblog_api.rb +68 -0
- data/examples/metaWeblog/apis/meta_weblog_service.rb +49 -0
- data/examples/metaWeblog/controllers/xmlrpc_controller.rb +17 -0
- data/generators/web_service/USAGE +28 -0
- data/generators/web_service/templates/api_definition.rb +6 -0
- data/generators/web_service/templates/controller.rb +9 -0
- data/generators/web_service/templates/functional_test.rb +20 -0
- data/generators/web_service/web_service_generator.rb +30 -0
- data/lib/action_web_service.rb +61 -0
- data/lib/action_web_service/acts_as_web_service.rb +26 -0
- data/lib/action_web_service/api.rb +298 -0
- data/lib/action_web_service/base.rb +39 -0
- data/lib/action_web_service/casting.rb +160 -0
- data/lib/action_web_service/client.rb +4 -0
- data/lib/action_web_service/client/base.rb +29 -0
- data/lib/action_web_service/client/soap_client.rb +114 -0
- data/lib/action_web_service/client/xmlrpc_client.rb +59 -0
- data/lib/action_web_service/container.rb +4 -0
- data/lib/action_web_service/container/action_controller_container.rb +94 -0
- 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.rb +3 -0
- data/lib/action_web_service/dispatcher/abstract.rb +209 -0
- data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +397 -0
- data/lib/action_web_service/invocation.rb +203 -0
- data/lib/action_web_service/protocol.rb +5 -0
- data/lib/action_web_service/protocol/abstract.rb +113 -0
- data/lib/action_web_service/protocol/discovery.rb +38 -0
- data/lib/action_web_service/protocol/soap_protocol.rb +177 -0
- data/lib/action_web_service/protocol/soap_protocol/marshaler.rb +243 -0
- data/lib/action_web_service/protocol/soap_protocol/marshaler.rb~ +243 -0
- data/lib/action_web_service/protocol/xmlrpc_protocol.rb +124 -0
- data/lib/action_web_service/scaffolding.rb +282 -0
- data/lib/action_web_service/simple.rb +54 -0
- data/lib/action_web_service/string_to_datetime_for_soap.rb +17 -0
- data/lib/action_web_service/struct.rb +69 -0
- data/lib/action_web_service/support/class_inheritable_options.rb +27 -0
- data/lib/action_web_service/support/signature_types.rb +262 -0
- data/lib/action_web_service/templates/scaffolds/layout.html.erb +65 -0
- data/lib/action_web_service/templates/scaffolds/methods.html.erb +6 -0
- data/lib/action_web_service/templates/scaffolds/parameters.html.erb +29 -0
- data/lib/action_web_service/templates/scaffolds/result.html.erb +30 -0
- data/lib/action_web_service/test_invoke.rb +111 -0
- data/lib/action_web_service/version.rb +11 -0
- data/lib/action_web_service/version.rb~ +10 -0
- data/lib/actionwebservice.rb +2 -0
- data/setup.rb +1380 -0
- data/test/abstract_client.rb +185 -0
- data/test/abstract_dispatcher.rb +550 -0
- data/test/abstract_unit.rb +44 -0
- data/test/api_test.rb +103 -0
- data/test/apis/auto_load_api.rb +4 -0
- data/test/apis/broken_auto_load_api.rb +3 -0
- data/test/base_test.rb +43 -0
- data/test/casting_test.rb +96 -0
- data/test/client_soap_test.rb +157 -0
- data/test/client_xmlrpc_test.rb +155 -0
- data/test/container_test.rb +76 -0
- data/test/dispatcher_action_controller_soap_test.rb +147 -0
- data/test/dispatcher_action_controller_xmlrpc_test.rb +60 -0
- data/test/fixtures/db_definitions/mysql.sql +8 -0
- data/test/fixtures/db_definitions/sqlite3.sql +8 -0
- data/test/fixtures/users.yml +12 -0
- data/test/gencov +3 -0
- data/test/invocation_test.rb +187 -0
- data/test/run +6 -0
- data/test/scaffolded_controller_test.rb +148 -0
- data/test/struct_test.rb +85 -0
- data/test/test_invoke_test.rb +114 -0
- metadata +167 -0
@@ -0,0 +1,203 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module ActionWebService # :nodoc:
|
3
|
+
module Invocation # :nodoc:
|
4
|
+
class InvocationError < ActionWebService::ActionWebServiceError # :nodoc:
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.included(base) # :nodoc:
|
8
|
+
base.extend(ClassMethods)
|
9
|
+
base.send(:include, ActionWebService::Invocation::InstanceMethods)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Invocation interceptors provide a means to execute custom code before
|
13
|
+
# and after method invocations on ActionWebService::Base objects.
|
14
|
+
#
|
15
|
+
# When running in _Direct_ dispatching mode, ActionController filters
|
16
|
+
# should be used for this functionality instead.
|
17
|
+
#
|
18
|
+
# The semantics of invocation interceptors are the same as ActionController
|
19
|
+
# filters, and accept the same parameters and options.
|
20
|
+
#
|
21
|
+
# A _before_ interceptor can also cancel execution by returning +false+,
|
22
|
+
# or returning a <tt>[false, "cancel reason"]</tt> array if it wishes to supply
|
23
|
+
# a reason for canceling the request.
|
24
|
+
#
|
25
|
+
# === Example
|
26
|
+
#
|
27
|
+
# class CustomService < ActionWebService::Base
|
28
|
+
# before_invocation :intercept_add, :only => [:add]
|
29
|
+
#
|
30
|
+
# def add(a, b)
|
31
|
+
# a + b
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# private
|
35
|
+
# def intercept_add
|
36
|
+
# return [false, "permission denied"] # cancel it
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# Options:
|
41
|
+
# [<tt>:except</tt>] A list of methods for which the interceptor will NOT be called
|
42
|
+
# [<tt>:only</tt>] A list of methods for which the interceptor WILL be called
|
43
|
+
module ClassMethods
|
44
|
+
# Appends the given +interceptors+ to be called
|
45
|
+
# _before_ method invocation.
|
46
|
+
def append_before_invocation(*interceptors, &block)
|
47
|
+
conditions = extract_conditions!(interceptors)
|
48
|
+
interceptors << block if block_given?
|
49
|
+
add_interception_conditions(interceptors, conditions)
|
50
|
+
append_interceptors_to_chain("before", interceptors)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Prepends the given +interceptors+ to be called
|
54
|
+
# _before_ method invocation.
|
55
|
+
def prepend_before_invocation(*interceptors, &block)
|
56
|
+
conditions = extract_conditions!(interceptors)
|
57
|
+
interceptors << block if block_given?
|
58
|
+
add_interception_conditions(interceptors, conditions)
|
59
|
+
prepend_interceptors_to_chain("before", interceptors)
|
60
|
+
end
|
61
|
+
|
62
|
+
alias :before_invocation :append_before_invocation
|
63
|
+
|
64
|
+
# Appends the given +interceptors+ to be called
|
65
|
+
# _after_ method invocation.
|
66
|
+
def append_after_invocation(*interceptors, &block)
|
67
|
+
conditions = extract_conditions!(interceptors)
|
68
|
+
interceptors << block if block_given?
|
69
|
+
add_interception_conditions(interceptors, conditions)
|
70
|
+
append_interceptors_to_chain("after", interceptors)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Prepends the given +interceptors+ to be called
|
74
|
+
# _after_ method invocation.
|
75
|
+
def prepend_after_invocation(*interceptors, &block)
|
76
|
+
conditions = extract_conditions!(interceptors)
|
77
|
+
interceptors << block if block_given?
|
78
|
+
add_interception_conditions(interceptors, conditions)
|
79
|
+
prepend_interceptors_to_chain("after", interceptors)
|
80
|
+
end
|
81
|
+
|
82
|
+
alias :after_invocation :append_after_invocation
|
83
|
+
|
84
|
+
def before_invocation_interceptors # :nodoc:
|
85
|
+
read_inheritable_attribute("before_invocation_interceptors")
|
86
|
+
end
|
87
|
+
|
88
|
+
def after_invocation_interceptors # :nodoc:
|
89
|
+
read_inheritable_attribute("after_invocation_interceptors")
|
90
|
+
end
|
91
|
+
|
92
|
+
def included_intercepted_methods # :nodoc:
|
93
|
+
read_inheritable_attribute("included_intercepted_methods") || {}
|
94
|
+
end
|
95
|
+
|
96
|
+
def excluded_intercepted_methods # :nodoc:
|
97
|
+
read_inheritable_attribute("excluded_intercepted_methods") || {}
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
def append_interceptors_to_chain(condition, interceptors)
|
102
|
+
write_inheritable_array("#{condition}_invocation_interceptors", interceptors)
|
103
|
+
end
|
104
|
+
|
105
|
+
def prepend_interceptors_to_chain(condition, interceptors)
|
106
|
+
interceptors = interceptors + read_inheritable_attribute("#{condition}_invocation_interceptors")
|
107
|
+
write_inheritable_attribute("#{condition}_invocation_interceptors", interceptors)
|
108
|
+
end
|
109
|
+
|
110
|
+
def extract_conditions!(interceptors)
|
111
|
+
return nil unless interceptors.last.is_a? Hash
|
112
|
+
interceptors.pop
|
113
|
+
end
|
114
|
+
|
115
|
+
def add_interception_conditions(interceptors, conditions)
|
116
|
+
return unless conditions
|
117
|
+
included, excluded = conditions[:only], conditions[:except]
|
118
|
+
write_inheritable_hash("included_intercepted_methods", condition_hash(interceptors, included)) && return if included
|
119
|
+
write_inheritable_hash("excluded_intercepted_methods", condition_hash(interceptors, excluded)) if excluded
|
120
|
+
end
|
121
|
+
|
122
|
+
def condition_hash(interceptors, *methods)
|
123
|
+
interceptors.inject({}) {|hash, interceptor| hash.merge(interceptor => methods.flatten.map {|method| method.to_s})}
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
module InstanceMethods # :nodoc:
|
128
|
+
def self.included(base)
|
129
|
+
base.class_eval do
|
130
|
+
alias_method_chain :perform_invocation, :interception
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def perform_invocation_with_interception(method_name, params, &block)
|
135
|
+
return if before_invocation(method_name, params, &block) == false
|
136
|
+
return_value = perform_invocation_without_interception(method_name, params)
|
137
|
+
after_invocation(method_name, params, return_value)
|
138
|
+
return_value
|
139
|
+
end
|
140
|
+
|
141
|
+
def perform_invocation(method_name, params)
|
142
|
+
send(method_name, *params)
|
143
|
+
end
|
144
|
+
|
145
|
+
def before_invocation(name, args, &block)
|
146
|
+
call_interceptors(self.class.before_invocation_interceptors, [name, args], &block)
|
147
|
+
end
|
148
|
+
|
149
|
+
def after_invocation(name, args, result)
|
150
|
+
call_interceptors(self.class.after_invocation_interceptors, [name, args, result])
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
def call_interceptors(interceptors, interceptor_args, &block)
|
156
|
+
if interceptors and not interceptors.empty?
|
157
|
+
interceptors.each do |interceptor|
|
158
|
+
next if method_exempted?(interceptor, interceptor_args[0].to_s)
|
159
|
+
result = case
|
160
|
+
when interceptor.is_a?(Symbol)
|
161
|
+
self.send(interceptor, *interceptor_args)
|
162
|
+
when interceptor_block?(interceptor)
|
163
|
+
interceptor.call(self, *interceptor_args)
|
164
|
+
when interceptor_class?(interceptor)
|
165
|
+
interceptor.intercept(self, *interceptor_args)
|
166
|
+
else
|
167
|
+
raise(
|
168
|
+
InvocationError,
|
169
|
+
"Interceptors need to be either a symbol, proc/method, or a class implementing a static intercept method"
|
170
|
+
)
|
171
|
+
end
|
172
|
+
reason = nil
|
173
|
+
if result.is_a?(Array)
|
174
|
+
reason = result[1] if result[1]
|
175
|
+
result = result[0]
|
176
|
+
end
|
177
|
+
if result == false
|
178
|
+
block.call(reason) if block && reason
|
179
|
+
return false
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def interceptor_block?(interceptor)
|
186
|
+
interceptor.respond_to?("call") && (interceptor.arity == 3 || interceptor.arity == -1)
|
187
|
+
end
|
188
|
+
|
189
|
+
def interceptor_class?(interceptor)
|
190
|
+
interceptor.respond_to?("intercept")
|
191
|
+
end
|
192
|
+
|
193
|
+
def method_exempted?(interceptor, method_name)
|
194
|
+
case
|
195
|
+
when self.class.included_intercepted_methods[interceptor]
|
196
|
+
!self.class.included_intercepted_methods[interceptor].include?(method_name)
|
197
|
+
when self.class.excluded_intercepted_methods[interceptor]
|
198
|
+
self.class.excluded_intercepted_methods[interceptor].include?(method_name)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module ActionWebService # :nodoc:
|
3
|
+
module Protocol # :nodoc:
|
4
|
+
class ProtocolError < ActionWebServiceError # :nodoc:
|
5
|
+
end
|
6
|
+
|
7
|
+
class AbstractProtocol # :nodoc:
|
8
|
+
def setup(controller)
|
9
|
+
end
|
10
|
+
|
11
|
+
def decode_action_pack_request(action_pack_request)
|
12
|
+
end
|
13
|
+
|
14
|
+
def encode_action_pack_request(service_name, public_method_name, raw_body, options={})
|
15
|
+
klass = options[:request_class] || SimpleActionPackRequest
|
16
|
+
request = klass.new({})
|
17
|
+
request.request_parameters['action'] = service_name.to_s
|
18
|
+
request.env['RAW_POST_DATA'] = raw_body
|
19
|
+
request.env['REQUEST_METHOD'] = 'POST'
|
20
|
+
request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
|
21
|
+
request
|
22
|
+
end
|
23
|
+
|
24
|
+
def decode_request(raw_request, service_name, protocol_options={})
|
25
|
+
end
|
26
|
+
|
27
|
+
def encode_request(method_name, params, param_types)
|
28
|
+
end
|
29
|
+
|
30
|
+
def decode_response(raw_response)
|
31
|
+
end
|
32
|
+
|
33
|
+
def encode_response(method_name, return_value, return_type, protocol_options={})
|
34
|
+
end
|
35
|
+
|
36
|
+
def protocol_client(api, protocol_name, endpoint_uri, options)
|
37
|
+
end
|
38
|
+
|
39
|
+
def register_api(api)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Request # :nodoc:
|
44
|
+
attr :protocol
|
45
|
+
attr_accessor :method_name
|
46
|
+
attr_accessor :method_params
|
47
|
+
attr :service_name
|
48
|
+
attr_accessor :api
|
49
|
+
attr_accessor :api_method
|
50
|
+
attr :protocol_options
|
51
|
+
|
52
|
+
def initialize(protocol, method_name, method_params, service_name, api=nil, api_method=nil, protocol_options=nil)
|
53
|
+
@protocol = protocol
|
54
|
+
@method_name = method_name
|
55
|
+
@method_params = method_params
|
56
|
+
@service_name = service_name
|
57
|
+
@api = api
|
58
|
+
@api_method = api_method
|
59
|
+
@protocol_options = protocol_options || {}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class Response # :nodoc:
|
64
|
+
attr :body
|
65
|
+
attr :content_type
|
66
|
+
attr :return_value
|
67
|
+
|
68
|
+
def initialize(body, content_type, return_value)
|
69
|
+
@body = body
|
70
|
+
@content_type = content_type
|
71
|
+
@return_value = return_value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class SimpleActionPackRequest < ActionController::Request # :nodoc:
|
76
|
+
def initialize(env = {})
|
77
|
+
@env = env
|
78
|
+
@qparams = {}
|
79
|
+
@rparams = {}
|
80
|
+
@cookies = {}
|
81
|
+
reset_session
|
82
|
+
end
|
83
|
+
|
84
|
+
def query_parameters
|
85
|
+
@qparams
|
86
|
+
end
|
87
|
+
|
88
|
+
def request_parameters
|
89
|
+
@rparams
|
90
|
+
end
|
91
|
+
|
92
|
+
def env
|
93
|
+
@env
|
94
|
+
end
|
95
|
+
|
96
|
+
def host
|
97
|
+
''
|
98
|
+
end
|
99
|
+
|
100
|
+
def cookies
|
101
|
+
@cookies
|
102
|
+
end
|
103
|
+
|
104
|
+
def session
|
105
|
+
@session
|
106
|
+
end
|
107
|
+
|
108
|
+
def reset_session
|
109
|
+
@session = {}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module ActionWebService # :nodoc:
|
3
|
+
module Protocol # :nodoc:
|
4
|
+
module Discovery # :nodoc:
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
base.send(:include, ActionWebService::Protocol::Discovery::InstanceMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods # :nodoc:
|
11
|
+
def register_protocol(klass)
|
12
|
+
write_inheritable_array("web_service_protocols", [klass])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module InstanceMethods # :nodoc:
|
17
|
+
private
|
18
|
+
def discover_web_service_request(action_pack_request)
|
19
|
+
(self.class.read_inheritable_attribute("web_service_protocols") || []).each do |protocol|
|
20
|
+
protocol = protocol.create(self)
|
21
|
+
request = protocol.decode_action_pack_request(action_pack_request)
|
22
|
+
return request unless request.nil?
|
23
|
+
end
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_web_service_client(api, protocol_name, endpoint_uri, options)
|
28
|
+
(self.class.read_inheritable_attribute("web_service_protocols") || []).each do |protocol|
|
29
|
+
protocol = protocol.create(self)
|
30
|
+
client = protocol.protocol_client(api, protocol_name, endpoint_uri, options)
|
31
|
+
return client unless client.nil?
|
32
|
+
end
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'action_web_service/protocol/soap_protocol/marshaler'
|
3
|
+
require 'soap/streamHandler'
|
4
|
+
require 'action_web_service/client/soap_client'
|
5
|
+
|
6
|
+
module ActionWebService # :nodoc:
|
7
|
+
module API # :nodoc:
|
8
|
+
class Base # :nodoc:
|
9
|
+
def self.soap_client(endpoint_uri, options={})
|
10
|
+
ActionWebService::Client::Soap.new self, endpoint_uri, options
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Protocol # :nodoc:
|
16
|
+
module Soap # :nodoc:
|
17
|
+
def self.included(base)
|
18
|
+
base.register_protocol(SoapProtocol)
|
19
|
+
base.class_inheritable_option(:wsdl_service_name)
|
20
|
+
base.class_inheritable_option(:wsdl_namespace)
|
21
|
+
end
|
22
|
+
|
23
|
+
class SoapProtocol < AbstractProtocol # :nodoc:
|
24
|
+
AWSEncoding = 'UTF-8'
|
25
|
+
XSDEncoding = 'UTF8'
|
26
|
+
|
27
|
+
attr :marshaler
|
28
|
+
|
29
|
+
def initialize(namespace=nil)
|
30
|
+
namespace ||= 'urn:ActionWebService'
|
31
|
+
@marshaler = SoapMarshaler.new namespace
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.create(controller)
|
35
|
+
SoapProtocol.new(controller.wsdl_namespace)
|
36
|
+
end
|
37
|
+
|
38
|
+
def decode_action_pack_request(action_pack_request)
|
39
|
+
return nil unless soap_action = has_valid_soap_action?(action_pack_request)
|
40
|
+
service_name = action_pack_request.parameters['action']
|
41
|
+
input_encoding = parse_charset(action_pack_request.env['HTTP_CONTENT_TYPE'])
|
42
|
+
protocol_options = {
|
43
|
+
:soap_action => soap_action,
|
44
|
+
:charset => input_encoding
|
45
|
+
}
|
46
|
+
decode_request(action_pack_request.raw_post, service_name, protocol_options)
|
47
|
+
end
|
48
|
+
|
49
|
+
def encode_action_pack_request(service_name, public_method_name, raw_body, options={})
|
50
|
+
request = super
|
51
|
+
request.env['HTTP_SOAPACTION'] = '/soap/%s/%s' % [service_name, public_method_name]
|
52
|
+
request
|
53
|
+
end
|
54
|
+
|
55
|
+
def decode_request(raw_request, service_name, protocol_options={})
|
56
|
+
envelope = SOAP::Processor.unmarshal(raw_request, :charset => protocol_options[:charset])
|
57
|
+
unless envelope
|
58
|
+
raise ProtocolError, "Failed to parse SOAP request message"
|
59
|
+
end
|
60
|
+
request = envelope.body.request
|
61
|
+
method_name = request.elename.name
|
62
|
+
params = request.collect{ |k, v| marshaler.soap_to_ruby(request[k]) }
|
63
|
+
Request.new(self, method_name, params, service_name, nil, nil, protocol_options)
|
64
|
+
end
|
65
|
+
|
66
|
+
def encode_request(method_name, params, param_types)
|
67
|
+
param_types.each{ |type| marshaler.register_type(type) } if param_types
|
68
|
+
qname = XSD::QName.new(marshaler.namespace, method_name)
|
69
|
+
param_def = []
|
70
|
+
if param_types
|
71
|
+
params = param_types.zip(params).map do |type, param|
|
72
|
+
param_def << ['in', type.name, marshaler.lookup_type(type).mapping]
|
73
|
+
[type.name, marshaler.ruby_to_soap(param)]
|
74
|
+
end
|
75
|
+
else
|
76
|
+
params = []
|
77
|
+
end
|
78
|
+
request = SOAP::RPC::SOAPMethodRequest.new(qname, param_def)
|
79
|
+
request.set_param(params)
|
80
|
+
envelope = create_soap_envelope(request)
|
81
|
+
SOAP::Processor.marshal(envelope)
|
82
|
+
end
|
83
|
+
|
84
|
+
def decode_response(raw_response)
|
85
|
+
envelope = SOAP::Processor.unmarshal(raw_response)
|
86
|
+
unless envelope
|
87
|
+
raise ProtocolError, "Failed to parse SOAP request message"
|
88
|
+
end
|
89
|
+
method_name = envelope.body.request.elename.name
|
90
|
+
return_value = envelope.body.response
|
91
|
+
return_value = marshaler.soap_to_ruby(return_value) unless return_value.nil?
|
92
|
+
[method_name, return_value]
|
93
|
+
end
|
94
|
+
|
95
|
+
def encode_response(method_name, return_value, return_type, protocol_options={})
|
96
|
+
if return_type
|
97
|
+
return_binding = marshaler.register_type(return_type)
|
98
|
+
marshaler.annotate_arrays(return_binding, return_value)
|
99
|
+
end
|
100
|
+
qname = XSD::QName.new(marshaler.namespace, method_name)
|
101
|
+
if return_value.nil?
|
102
|
+
response = SOAP::RPC::SOAPMethodResponse.new(qname, nil)
|
103
|
+
else
|
104
|
+
if return_value.is_a?(Exception)
|
105
|
+
detail = SOAP::Mapping::SOAPException.new(return_value)
|
106
|
+
response = SOAP::SOAPFault.new(
|
107
|
+
SOAP::SOAPQName.new('%s:%s' % [SOAP::SOAPNamespaceTag, 'Server']),
|
108
|
+
SOAP::SOAPString.new(return_value.to_s),
|
109
|
+
SOAP::SOAPString.new(self.class.name),
|
110
|
+
marshaler.ruby_to_soap(detail))
|
111
|
+
else
|
112
|
+
if return_type
|
113
|
+
param_def = [['retval', 'return', marshaler.lookup_type(return_type).mapping]]
|
114
|
+
response = SOAP::RPC::SOAPMethodResponse.new(qname, param_def)
|
115
|
+
response.retval = marshaler.ruby_to_soap(return_value)
|
116
|
+
else
|
117
|
+
response = SOAP::RPC::SOAPMethodResponse.new(qname, nil)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
envelope = create_soap_envelope(response)
|
122
|
+
|
123
|
+
# FIXME: This is not thread-safe, but StringFactory_ in SOAP4R only
|
124
|
+
# reads target encoding from the XSD::Charset.encoding variable.
|
125
|
+
# This is required to ensure $KCODE strings are converted
|
126
|
+
# correctly to UTF-8 for any values of $KCODE.
|
127
|
+
previous_encoding = XSD::Charset.encoding
|
128
|
+
XSD::Charset.encoding = XSDEncoding
|
129
|
+
response_body = SOAP::Processor.marshal(envelope, :charset => AWSEncoding)
|
130
|
+
XSD::Charset.encoding = previous_encoding
|
131
|
+
|
132
|
+
Response.new(response_body, "text/xml; charset=#{AWSEncoding}", return_value)
|
133
|
+
end
|
134
|
+
|
135
|
+
def protocol_client(api, protocol_name, endpoint_uri, options={})
|
136
|
+
return nil unless protocol_name == :soap
|
137
|
+
ActionWebService::Client::Soap.new(api, endpoint_uri, options)
|
138
|
+
end
|
139
|
+
|
140
|
+
def register_api(api)
|
141
|
+
api.api_methods.each do |name, method|
|
142
|
+
method.expects.each{ |type| marshaler.register_type(type) } if method.expects
|
143
|
+
method.returns.each{ |type| marshaler.register_type(type) } if method.returns
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
def has_valid_soap_action?(request)
|
149
|
+
return nil unless request.method == :post
|
150
|
+
soap_action = request.env['HTTP_SOAPACTION']
|
151
|
+
return nil unless soap_action
|
152
|
+
soap_action = soap_action.dup
|
153
|
+
soap_action.gsub!(/^"/, '')
|
154
|
+
soap_action.gsub!(/"$/, '')
|
155
|
+
soap_action.strip!
|
156
|
+
return nil if soap_action.empty?
|
157
|
+
soap_action
|
158
|
+
end
|
159
|
+
|
160
|
+
def create_soap_envelope(body)
|
161
|
+
header = SOAP::SOAPHeader.new
|
162
|
+
body = SOAP::SOAPBody.new(body)
|
163
|
+
SOAP::SOAPEnvelope.new(header, body)
|
164
|
+
end
|
165
|
+
|
166
|
+
def parse_charset(content_type)
|
167
|
+
return AWSEncoding if content_type.nil?
|
168
|
+
if /^text\/xml(?:\s*;\s*charset=([^"]+|"[^"]+"))$/i =~ content_type
|
169
|
+
$1
|
170
|
+
else
|
171
|
+
AWSEncoding
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|