keeguon-actionwebservice 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. data/CHANGELOG +335 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +381 -0
  4. data/Rakefile +184 -0
  5. data/TODO +32 -0
  6. data/examples/googlesearch/README +143 -0
  7. data/examples/googlesearch/autoloading/google_search_api.rb +51 -0
  8. data/examples/googlesearch/autoloading/google_search_controller.rb +58 -0
  9. data/examples/googlesearch/delegated/google_search_service.rb +109 -0
  10. data/examples/googlesearch/delegated/search_controller.rb +8 -0
  11. data/examples/googlesearch/direct/google_search_api.rb +51 -0
  12. data/examples/googlesearch/direct/search_controller.rb +59 -0
  13. data/examples/metaWeblog/README +17 -0
  14. data/examples/metaWeblog/apis/blogger_api.rb +61 -0
  15. data/examples/metaWeblog/apis/blogger_service.rb +35 -0
  16. data/examples/metaWeblog/apis/meta_weblog_api.rb +68 -0
  17. data/examples/metaWeblog/apis/meta_weblog_service.rb +49 -0
  18. data/examples/metaWeblog/controllers/xmlrpc_controller.rb +17 -0
  19. data/generators/web_service/USAGE +28 -0
  20. data/generators/web_service/templates/api_definition.rb +6 -0
  21. data/generators/web_service/templates/controller.rb +9 -0
  22. data/generators/web_service/templates/functional_test.rb +20 -0
  23. data/generators/web_service/web_service_generator.rb +30 -0
  24. data/lib/action_web_service/acts_as_web_service.rb +26 -0
  25. data/lib/action_web_service/api.rb +298 -0
  26. data/lib/action_web_service/base.rb +39 -0
  27. data/lib/action_web_service/casting.rb +160 -0
  28. data/lib/action_web_service/client/base.rb +29 -0
  29. data/lib/action_web_service/client/soap_client.rb +114 -0
  30. data/lib/action_web_service/client/xmlrpc_client.rb +59 -0
  31. data/lib/action_web_service/client.rb +4 -0
  32. data/lib/action_web_service/container/action_controller_container.rb +94 -0
  33. data/lib/action_web_service/container/delegated_container.rb +87 -0
  34. data/lib/action_web_service/container/direct_container.rb +70 -0
  35. data/lib/action_web_service/container.rb +4 -0
  36. data/lib/action_web_service/dispatcher/abstract.rb +209 -0
  37. data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +420 -0
  38. data/lib/action_web_service/dispatcher.rb +3 -0
  39. data/lib/action_web_service/invocation.rb +203 -0
  40. data/lib/action_web_service/protocol/abstract.rb +113 -0
  41. data/lib/action_web_service/protocol/discovery.rb +38 -0
  42. data/lib/action_web_service/protocol/soap_protocol/marshaler.rb +243 -0
  43. data/lib/action_web_service/protocol/soap_protocol.rb +181 -0
  44. data/lib/action_web_service/protocol/xmlrpc_protocol.rb +124 -0
  45. data/lib/action_web_service/protocol.rb +5 -0
  46. data/lib/action_web_service/scaffolding.rb +282 -0
  47. data/lib/action_web_service/simple.rb +54 -0
  48. data/lib/action_web_service/string_to_datetime_for_soap.rb +17 -0
  49. data/lib/action_web_service/struct.rb +69 -0
  50. data/lib/action_web_service/support/class_inheritable_options.rb +27 -0
  51. data/lib/action_web_service/support/signature_types.rb +262 -0
  52. data/lib/action_web_service/templates/scaffolds/layout.html.erb +65 -0
  53. data/lib/action_web_service/templates/scaffolds/methods.html.erb +6 -0
  54. data/lib/action_web_service/templates/scaffolds/parameters.html.erb +29 -0
  55. data/lib/action_web_service/templates/scaffolds/result.html.erb +30 -0
  56. data/lib/action_web_service/test_invoke.rb +111 -0
  57. data/lib/action_web_service/version.rb +10 -0
  58. data/lib/action_web_service.rb +61 -0
  59. data/lib/actionwebservice.rb +2 -0
  60. data/setup.rb +1380 -0
  61. data/test/abstract_client.rb +185 -0
  62. data/test/abstract_dispatcher.rb +550 -0
  63. data/test/abstract_unit.rb +44 -0
  64. data/test/api_test.rb +103 -0
  65. data/test/apis/auto_load_api.rb +4 -0
  66. data/test/apis/broken_auto_load_api.rb +3 -0
  67. data/test/base_test.rb +43 -0
  68. data/test/casting_test.rb +96 -0
  69. data/test/client_soap_test.rb +157 -0
  70. data/test/client_xmlrpc_test.rb +155 -0
  71. data/test/container_test.rb +76 -0
  72. data/test/dispatcher_action_controller_soap_test.rb +147 -0
  73. data/test/dispatcher_action_controller_xmlrpc_test.rb +60 -0
  74. data/test/fixtures/db_definitions/mysql.sql +8 -0
  75. data/test/fixtures/db_definitions/sqlite3.sql +8 -0
  76. data/test/fixtures/users.yml +12 -0
  77. data/test/gencov +3 -0
  78. data/test/invocation_test.rb +187 -0
  79. data/test/run +6 -0
  80. data/test/scaffolded_controller_test.rb +148 -0
  81. data/test/struct_test.rb +85 -0
  82. data/test/test_invoke_test.rb +114 -0
  83. metadata +175 -0
@@ -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 < Rack::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,243 @@
1
+ # encoding: UTF-8
2
+ require 'soap/mapping'
3
+
4
+ # hack to improve the .Net interoperability
5
+ class SOAP::Mapping::Object
6
+ def each_pair
7
+ self.__xmlele.each { |n, v| yield n.name, v.to_s }
8
+ end
9
+ end
10
+
11
+ module ActionWebService
12
+ module Protocol
13
+ module Soap
14
+ # Workaround for SOAP4R return values changing
15
+ class Registry < SOAP::Mapping::Registry
16
+ if SOAP::Version >= "1.5.4"
17
+ def find_mapped_soap_class(obj_class)
18
+ return @map.instance_eval { @obj2soap[obj_class][0] }
19
+ end
20
+
21
+ def find_mapped_obj_class(soap_class)
22
+ return @map.instance_eval { @soap2obj[soap_class][0] }
23
+ end
24
+ end
25
+ end
26
+
27
+ class SoapMarshaler
28
+ attr :namespace
29
+ attr :registry
30
+
31
+ def initialize(namespace=nil)
32
+ @namespace = namespace || 'urn:ActionWebService'
33
+ @registry = Registry.new
34
+ @type2binding = {}
35
+ register_static_factories
36
+ end
37
+
38
+ def soap_to_ruby(obj)
39
+ SOAP::Mapping.soap2obj(obj, @registry)
40
+ end
41
+
42
+ def ruby_to_soap(obj)
43
+ soap = SOAP::Mapping.obj2soap(obj, @registry)
44
+ soap.elename = XSD::QName.new if SOAP::Version >= "1.5.5" && soap.elename == XSD::QName::EMPTY
45
+ soap
46
+ end
47
+
48
+ def register_type(type)
49
+ return @type2binding[type] if @type2binding.has_key?(type)
50
+
51
+ if type.array?
52
+ array_mapping = @registry.find_mapped_soap_class(Array)
53
+ qname = XSD::QName.new(@namespace, soap_type_name(type.element_type.type_class.name) + 'Array')
54
+ element_type_binding = register_type(type.element_type)
55
+ @type2binding[type] = SoapBinding.new(self, qname, type, array_mapping, element_type_binding)
56
+ elsif (mapping = @registry.find_mapped_soap_class(type.type_class) rescue nil)
57
+ qname = mapping[2] ? mapping[2][:type] : nil
58
+ qname ||= soap_base_type_name(mapping[0])
59
+ @type2binding[type] = SoapBinding.new(self, qname, type, mapping)
60
+ else
61
+ qname = XSD::QName.new(@namespace, soap_type_name(type.type_class.name))
62
+ @registry.add(type.type_class,
63
+ SOAP::SOAPStruct,
64
+ typed_struct_factory(type.type_class),
65
+ { :type => qname })
66
+ mapping = @registry.find_mapped_soap_class(type.type_class)
67
+ @type2binding[type] = SoapBinding.new(self, qname, type, mapping)
68
+ end
69
+
70
+ if type.structured?
71
+ type.each_member do |m_name, m_type|
72
+ register_type(m_type)
73
+ end
74
+ end
75
+
76
+ @type2binding[type]
77
+ end
78
+ alias :lookup_type :register_type
79
+
80
+ def annotate_arrays(binding, value)
81
+ if value.nil?
82
+ return
83
+ elsif binding.type.array?
84
+ mark_typed_array(value, binding.element_binding.qname)
85
+ if binding.element_binding.type.custom?
86
+ value.each do |element|
87
+ annotate_arrays(binding.element_binding, element)
88
+ end
89
+ end
90
+ elsif binding.type.structured?
91
+ binding.type.each_member do |name, type|
92
+ member_binding = register_type(type)
93
+ member_value = value.respond_to?('[]') ? value[name] : value.send(name)
94
+ annotate_arrays(member_binding, member_value) if type.custom?
95
+ end
96
+ end
97
+ end
98
+
99
+ private
100
+ def typed_struct_factory(type_class)
101
+ if Object.const_defined?('ActiveRecord')
102
+ if type_class.ancestors.include?(ActiveRecord::Base)
103
+ qname = XSD::QName.new(@namespace, soap_type_name(type_class.name))
104
+ type_class.instance_variable_set('@qname', qname)
105
+ return SoapActiveRecordStructFactory.new
106
+ end
107
+ end
108
+ SOAP::Mapping::Registry::TypedStructFactory
109
+ end
110
+
111
+ def mark_typed_array(array, qname)
112
+ (class << array; self; end).class_eval do
113
+ define_method(:arytype) do
114
+ qname
115
+ end
116
+ end
117
+ end
118
+
119
+ def soap_base_type_name(type)
120
+ xsd_type = type.ancestors.find{ |c| c.const_defined? 'Type' }
121
+ xsd_type ? xsd_type.const_get('Type') : XSD::XSDAnySimpleType::Type
122
+ end
123
+
124
+ def soap_type_name(type_name)
125
+ type_name.gsub(/::/, '..')
126
+ end
127
+
128
+ def register_static_factories
129
+ @registry.add(ActionWebService::Base64, SOAP::SOAPBase64, SoapBase64Factory.new, nil)
130
+ mapping = @registry.find_mapped_soap_class(ActionWebService::Base64)
131
+ @type2binding[ActionWebService::Base64] =
132
+ SoapBinding.new(self, SOAP::SOAPBase64::Type, ActionWebService::Base64, mapping)
133
+ @registry.add(Array, SOAP::SOAPArray, SoapTypedArrayFactory.new, nil)
134
+ @registry.add(::BigDecimal, SOAP::SOAPDouble, SOAP::Mapping::Registry::BasetypeFactory, {:derived_class => true})
135
+ end
136
+ end
137
+
138
+ class SoapBinding
139
+ attr :qname
140
+ attr :type
141
+ attr :mapping
142
+ attr :element_binding
143
+
144
+ def initialize(marshaler, qname, type, mapping, element_binding=nil)
145
+ @marshaler = marshaler
146
+ @qname = qname
147
+ @type = type
148
+ @mapping = mapping
149
+ @element_binding = element_binding
150
+ end
151
+
152
+ def type_name
153
+ @type.custom? ? @qname.name : nil
154
+ end
155
+
156
+ def qualified_type_name(ns=nil)
157
+ if @type.custom?
158
+ "#{ns ? ns : @qname.namespace}:#{@qname.name}"
159
+ else
160
+ ns = XSD::NS.new
161
+ ns.assign(XSD::Namespace, SOAP::XSDNamespaceTag)
162
+ ns.assign(SOAP::EncodingNamespace, "soapenc")
163
+ xsd_klass = mapping[0].ancestors.find{|c| c.const_defined?('Type')}
164
+ return ns.name(XSD::AnyTypeName) unless xsd_klass
165
+ ns.name(xsd_klass.const_get('Type'))
166
+ end
167
+ end
168
+
169
+ def eql?(other)
170
+ @qname == other.qname
171
+ end
172
+ alias :== :eql?
173
+
174
+ def hash
175
+ @qname.hash
176
+ end
177
+ end
178
+
179
+ class SoapActiveRecordStructFactory < SOAP::Mapping::Factory
180
+ def obj2soap(soap_class, obj, info, map)
181
+ unless obj.is_a?(ActiveRecord::Base)
182
+ return nil
183
+ end
184
+ soap_obj = soap_class.new(obj.class.instance_variable_get('@qname'))
185
+ obj.class.columns.each do |column|
186
+ key = column.name.to_s
187
+ value = obj.send(key)
188
+ soap_obj[key] = SOAP::Mapping._obj2soap(value, map)
189
+ end
190
+ soap_obj
191
+ end
192
+
193
+ def soap2obj(obj_class, node, info, map)
194
+ unless node.type == obj_class.instance_variable_get('@qname')
195
+ return false
196
+ end
197
+ obj = obj_class.new
198
+ node.each do |key, value|
199
+ obj[key] = value.data
200
+ end
201
+ obj.instance_variable_set('@new_record', false)
202
+ return true, obj
203
+ end
204
+ end
205
+
206
+ class SoapTypedArrayFactory < SOAP::Mapping::Factory
207
+ def obj2soap(soap_class, obj, info, map)
208
+ unless obj.respond_to?(:arytype)
209
+ return nil
210
+ end
211
+ soap_obj = soap_class.new(SOAP::ValueArrayName, 1, obj.arytype)
212
+ mark_marshalled_obj(obj, soap_obj)
213
+ obj.each do |item|
214
+ child = SOAP::Mapping._obj2soap(item, map)
215
+ soap_obj.add(child)
216
+ end
217
+ soap_obj
218
+ end
219
+
220
+ def soap2obj(obj_class, node, info, map)
221
+ return false
222
+ end
223
+ end
224
+
225
+ class SoapBase64Factory < SOAP::Mapping::Factory
226
+ def obj2soap(soap_class, obj, info, map)
227
+ unless obj.is_a?(ActionWebService::Base64)
228
+ return nil
229
+ end
230
+ return soap_class.new(obj)
231
+ end
232
+
233
+ def soap2obj(obj_class, node, info, map)
234
+ unless node.type == SOAP::SOAPBase64::Type
235
+ return false
236
+ end
237
+ return true, obj_class.new(node.string)
238
+ end
239
+ end
240
+
241
+ end
242
+ end
243
+ end
@@ -0,0 +1,181 @@
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
+ if return_value.respond_to?(:to_soap_fault)
106
+ response = return_value.to_soap_fault
107
+ else
108
+ detail = SOAP::Mapping::SOAPException.new(return_value)
109
+ response = SOAP::SOAPFault.new(
110
+ SOAP::SOAPQName.new('%s:%s' % [SOAP::SOAPNamespaceTag, 'Server']),
111
+ SOAP::SOAPString.new(return_value.to_s),
112
+ SOAP::SOAPString.new(self.class.name),
113
+ marshaler.ruby_to_soap(detail))
114
+ end
115
+ else
116
+ if return_type
117
+ param_def = [['retval', 'return', marshaler.lookup_type(return_type).mapping]]
118
+ response = SOAP::RPC::SOAPMethodResponse.new(qname, param_def)
119
+ response.retval = marshaler.ruby_to_soap(return_value)
120
+ else
121
+ response = SOAP::RPC::SOAPMethodResponse.new(qname, nil)
122
+ end
123
+ end
124
+ end
125
+ envelope = create_soap_envelope(response)
126
+
127
+ # FIXME: This is not thread-safe, but StringFactory_ in SOAP4R only
128
+ # reads target encoding from the XSD::Charset.encoding variable.
129
+ # This is required to ensure $KCODE strings are converted
130
+ # correctly to UTF-8 for any values of $KCODE.
131
+ previous_encoding = XSD::Charset.encoding
132
+ XSD::Charset.encoding = XSDEncoding
133
+ response_body = SOAP::Processor.marshal(envelope, :charset => AWSEncoding)
134
+ XSD::Charset.encoding = previous_encoding
135
+
136
+ Response.new(response_body, "text/xml; charset=#{AWSEncoding}", return_value)
137
+ end
138
+
139
+ def protocol_client(api, protocol_name, endpoint_uri, options={})
140
+ return nil unless protocol_name == :soap
141
+ ActionWebService::Client::Soap.new(api, endpoint_uri, options)
142
+ end
143
+
144
+ def register_api(api)
145
+ api.api_methods.each do |name, method|
146
+ method.expects.each{ |type| marshaler.register_type(type) } if method.expects
147
+ method.returns.each{ |type| marshaler.register_type(type) } if method.returns
148
+ end
149
+ end
150
+
151
+ private
152
+ def has_valid_soap_action?(request)
153
+ return nil unless request.method == 'POST'
154
+ soap_action = request.env['HTTP_SOAPACTION']
155
+ return nil unless soap_action
156
+ soap_action = soap_action.dup
157
+ soap_action.gsub!(/^"/, '')
158
+ soap_action.gsub!(/"$/, '')
159
+ soap_action.strip!
160
+ return nil if soap_action.empty?
161
+ soap_action
162
+ end
163
+
164
+ def create_soap_envelope(body)
165
+ header = SOAP::SOAPHeader.new
166
+ body = SOAP::SOAPBody.new(body)
167
+ SOAP::SOAPEnvelope.new(header, body)
168
+ end
169
+
170
+ def parse_charset(content_type)
171
+ return AWSEncoding if content_type.nil?
172
+ if /^text\/xml(?:\s*;\s*charset=([^"]+|"[^"]+"))$/i =~ content_type
173
+ $1
174
+ else
175
+ AWSEncoding
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,124 @@
1
+ # encoding: UTF-8
2
+ require 'xmlrpc/marshal'
3
+ require 'action_web_service/client/xmlrpc_client'
4
+
5
+ module XMLRPC # :nodoc:
6
+ class FaultException # :nodoc:
7
+ alias :message :faultString
8
+ end
9
+
10
+ class Create
11
+ def wrong_type(value)
12
+ if BigDecimal === value
13
+ [true, value.to_f]
14
+ else
15
+ false
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ module ActionWebService # :nodoc:
22
+ module API # :nodoc:
23
+ class Base # :nodoc:
24
+ def self.xmlrpc_client(endpoint_uri, options={})
25
+ ActionWebService::Client::XmlRpc.new self, endpoint_uri, options
26
+ end
27
+ end
28
+ end
29
+
30
+ module Protocol # :nodoc:
31
+ module XmlRpc # :nodoc:
32
+ def self.included(base)
33
+ base.register_protocol(XmlRpcProtocol)
34
+ end
35
+
36
+ class XmlRpcProtocol < AbstractProtocol # :nodoc:
37
+ def self.create(controller)
38
+ XmlRpcProtocol.new
39
+ end
40
+
41
+ def decode_action_pack_request(action_pack_request)
42
+ service_name = action_pack_request.parameters['action']
43
+ decode_request(action_pack_request.raw_post, service_name)
44
+ end
45
+
46
+ def decode_request(raw_request, service_name)
47
+ method_name, params = XMLRPC::Marshal.load_call(raw_request)
48
+ Request.new(self, method_name, params, service_name)
49
+ rescue
50
+ return nil
51
+ end
52
+
53
+ def encode_request(method_name, params, param_types)
54
+ if param_types
55
+ params = params.dup
56
+ param_types.each_with_index{ |type, i| params[i] = value_to_xmlrpc_wire_format(params[i], type) }
57
+ end
58
+ XMLRPC::Marshal.dump_call(method_name, *params)
59
+ end
60
+
61
+ def decode_response(raw_response)
62
+ [nil, XMLRPC::Marshal.load_response(raw_response)]
63
+ end
64
+
65
+ def encode_response(method_name, return_value, return_type, protocol_options={})
66
+ if return_value && return_type
67
+ return_value = value_to_xmlrpc_wire_format(return_value, return_type)
68
+ end
69
+ return_value = false if return_value.nil?
70
+ raw_response = XMLRPC::Marshal.dump_response(return_value)
71
+ Response.new(raw_response, 'text/xml', return_value)
72
+ end
73
+
74
+ def encode_multicall_response(responses, protocol_options={})
75
+ result = responses.map do |return_value, return_type|
76
+ if return_value && return_type
77
+ return_value = value_to_xmlrpc_wire_format(return_value, return_type)
78
+ return_value = [return_value] unless return_value.nil?
79
+ end
80
+ return_value = false if return_value.nil?
81
+ return_value
82
+ end
83
+ raw_response = XMLRPC::Marshal.dump_response(result)
84
+ Response.new(raw_response, 'text/xml', result)
85
+ end
86
+
87
+ def protocol_client(api, protocol_name, endpoint_uri, options={})
88
+ return nil unless protocol_name == :xmlrpc
89
+ ActionWebService::Client::XmlRpc.new(api, endpoint_uri, options)
90
+ end
91
+
92
+ def value_to_xmlrpc_wire_format(value, value_type)
93
+ if value_type.array?
94
+ value.map{ |val| value_to_xmlrpc_wire_format(val, value_type.element_type) }
95
+ else
96
+ if value.is_a?(ActionWebService::Struct)
97
+ struct = {}
98
+ value.class.members.each do |name, type_options|
99
+ type, options = type_options
100
+ member_value = value[name]
101
+ next if member_value.nil?
102
+ struct[name.to_s] = value_to_xmlrpc_wire_format(member_value, type)
103
+ end
104
+ struct
105
+ elsif value.is_a?(ActiveRecord::Base)
106
+ struct = {}
107
+ value.attributes.each do |key, member_value|
108
+ next if member_value.nil?
109
+ struct[key.to_s] = member_value
110
+ end
111
+ struct
112
+ elsif value.is_a?(ActionWebService::Base64)
113
+ XMLRPC::Base64.new(value)
114
+ elsif value.is_a?(Exception) && !value.is_a?(XMLRPC::FaultException)
115
+ XMLRPC::FaultException.new(2, value.message)
116
+ else
117
+ value
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,5 @@
1
+ # encoding: UTF-8
2
+ require 'action_web_service/protocol/abstract'
3
+ require 'action_web_service/protocol/discovery'
4
+ require 'action_web_service/protocol/soap_protocol'
5
+ require 'action_web_service/protocol/xmlrpc_protocol'