reidiculous-actionwebservice-client 3.0.4

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 (179) hide show
  1. data/CHANGELOG +320 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +381 -0
  4. data/Rakefile +180 -0
  5. data/TODO +32 -0
  6. data/lib/action_web_service.rb +71 -0
  7. data/lib/action_web_service/api.rb +297 -0
  8. data/lib/action_web_service/base.rb +38 -0
  9. data/lib/action_web_service/casting.rb +149 -0
  10. data/lib/action_web_service/client.rb +3 -0
  11. data/lib/action_web_service/client/base.rb +28 -0
  12. data/lib/action_web_service/client/soap_client.rb +113 -0
  13. data/lib/action_web_service/client/xmlrpc_client.rb +58 -0
  14. data/lib/action_web_service/container.rb +3 -0
  15. data/lib/action_web_service/container/action_controller_container.rb +93 -0
  16. data/lib/action_web_service/container/delegated_container.rb +86 -0
  17. data/lib/action_web_service/container/direct_container.rb +69 -0
  18. data/lib/action_web_service/dispatcher.rb +2 -0
  19. data/lib/action_web_service/dispatcher/abstract.rb +207 -0
  20. data/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +379 -0
  21. data/lib/action_web_service/invocation.rb +202 -0
  22. data/lib/action_web_service/protocol.rb +4 -0
  23. data/lib/action_web_service/protocol/abstract.rb +115 -0
  24. data/lib/action_web_service/protocol/discovery.rb +37 -0
  25. data/lib/action_web_service/protocol/soap_protocol.rb +176 -0
  26. data/lib/action_web_service/protocol/soap_protocol/marshaler.rb +242 -0
  27. data/lib/action_web_service/protocol/xmlrpc_protocol.rb +122 -0
  28. data/lib/action_web_service/scaffolding.rb +281 -0
  29. data/lib/action_web_service/soap/attachment.rb +107 -0
  30. data/lib/action_web_service/soap/baseData.rb +942 -0
  31. data/lib/action_web_service/soap/element.rb +258 -0
  32. data/lib/action_web_service/soap/encodingstyle/aspDotNetHandler.rb +213 -0
  33. data/lib/action_web_service/soap/encodingstyle/handler.rb +100 -0
  34. data/lib/action_web_service/soap/encodingstyle/literalHandler.rb +226 -0
  35. data/lib/action_web_service/soap/encodingstyle/soapHandler.rb +582 -0
  36. data/lib/action_web_service/soap/generator.rb +268 -0
  37. data/lib/action_web_service/soap/header/handler.rb +57 -0
  38. data/lib/action_web_service/soap/header/handlerset.rb +70 -0
  39. data/lib/action_web_service/soap/header/simplehandler.rb +44 -0
  40. data/lib/action_web_service/soap/httpconfigloader.rb +119 -0
  41. data/lib/action_web_service/soap/mapping.rb +10 -0
  42. data/lib/action_web_service/soap/mapping/factory.rb +355 -0
  43. data/lib/action_web_service/soap/mapping/mapping.rb +381 -0
  44. data/lib/action_web_service/soap/mapping/registry.rb +541 -0
  45. data/lib/action_web_service/soap/mapping/rubytypeFactory.rb +475 -0
  46. data/lib/action_web_service/soap/mapping/typeMap.rb +50 -0
  47. data/lib/action_web_service/soap/mapping/wsdlencodedregistry.rb +280 -0
  48. data/lib/action_web_service/soap/mapping/wsdlliteralregistry.rb +418 -0
  49. data/lib/action_web_service/soap/marshal.rb +59 -0
  50. data/lib/action_web_service/soap/mimemessage.rb +240 -0
  51. data/lib/action_web_service/soap/netHttpClient.rb +190 -0
  52. data/lib/action_web_service/soap/parser.rb +251 -0
  53. data/lib/action_web_service/soap/processor.rb +66 -0
  54. data/lib/action_web_service/soap/property.rb +333 -0
  55. data/lib/action_web_service/soap/rpc/cgistub.rb +206 -0
  56. data/lib/action_web_service/soap/rpc/driver.rb +254 -0
  57. data/lib/action_web_service/soap/rpc/element.rb +325 -0
  58. data/lib/action_web_service/soap/rpc/httpserver.rb +129 -0
  59. data/lib/action_web_service/soap/rpc/proxy.rb +497 -0
  60. data/lib/action_web_service/soap/rpc/router.rb +594 -0
  61. data/lib/action_web_service/soap/rpc/rpc.rb +25 -0
  62. data/lib/action_web_service/soap/rpc/soaplet.rb +162 -0
  63. data/lib/action_web_service/soap/rpc/standaloneServer.rb +43 -0
  64. data/lib/action_web_service/soap/soap.rb +140 -0
  65. data/lib/action_web_service/soap/streamHandler.rb +229 -0
  66. data/lib/action_web_service/soap/wsdlDriver.rb +575 -0
  67. data/lib/action_web_service/struct.rb +64 -0
  68. data/lib/action_web_service/support/class_inheritable_options.rb +28 -0
  69. data/lib/action_web_service/support/signature_types.rb +227 -0
  70. data/lib/action_web_service/test_invoke.rb +110 -0
  71. data/lib/action_web_service/version.rb +9 -0
  72. data/lib/action_web_service/wsdl/binding.rb +65 -0
  73. data/lib/action_web_service/wsdl/data.rb +64 -0
  74. data/lib/action_web_service/wsdl/definitions.rb +250 -0
  75. data/lib/action_web_service/wsdl/documentation.rb +32 -0
  76. data/lib/action_web_service/wsdl/import.rb +80 -0
  77. data/lib/action_web_service/wsdl/importer.rb +38 -0
  78. data/lib/action_web_service/wsdl/info.rb +39 -0
  79. data/lib/action_web_service/wsdl/message.rb +54 -0
  80. data/lib/action_web_service/wsdl/operation.rb +130 -0
  81. data/lib/action_web_service/wsdl/operationBinding.rb +108 -0
  82. data/lib/action_web_service/wsdl/param.rb +85 -0
  83. data/lib/action_web_service/wsdl/parser.rb +163 -0
  84. data/lib/action_web_service/wsdl/part.rb +52 -0
  85. data/lib/action_web_service/wsdl/port.rb +84 -0
  86. data/lib/action_web_service/wsdl/portType.rb +73 -0
  87. data/lib/action_web_service/wsdl/service.rb +61 -0
  88. data/lib/action_web_service/wsdl/soap/address.rb +40 -0
  89. data/lib/action_web_service/wsdl/soap/binding.rb +49 -0
  90. data/lib/action_web_service/wsdl/soap/body.rb +56 -0
  91. data/lib/action_web_service/wsdl/soap/cgiStubCreator.rb +76 -0
  92. data/lib/action_web_service/wsdl/soap/classDefCreator.rb +314 -0
  93. data/lib/action_web_service/wsdl/soap/classDefCreatorSupport.rb +126 -0
  94. data/lib/action_web_service/wsdl/soap/clientSkeltonCreator.rb +78 -0
  95. data/lib/action_web_service/wsdl/soap/complexType.rb +161 -0
  96. data/lib/action_web_service/wsdl/soap/data.rb +42 -0
  97. data/lib/action_web_service/wsdl/soap/definitions.rb +149 -0
  98. data/lib/action_web_service/wsdl/soap/driverCreator.rb +95 -0
  99. data/lib/action_web_service/wsdl/soap/element.rb +28 -0
  100. data/lib/action_web_service/wsdl/soap/fault.rb +56 -0
  101. data/lib/action_web_service/wsdl/soap/header.rb +86 -0
  102. data/lib/action_web_service/wsdl/soap/headerfault.rb +56 -0
  103. data/lib/action_web_service/wsdl/soap/mappingRegistryCreator.rb +92 -0
  104. data/lib/action_web_service/wsdl/soap/methodDefCreator.rb +228 -0
  105. data/lib/action_web_service/wsdl/soap/operation.rb +122 -0
  106. data/lib/action_web_service/wsdl/soap/servantSkeltonCreator.rb +67 -0
  107. data/lib/action_web_service/wsdl/soap/standaloneServerStubCreator.rb +85 -0
  108. data/lib/action_web_service/wsdl/soap/wsdl2ruby.rb +176 -0
  109. data/lib/action_web_service/wsdl/types.rb +43 -0
  110. data/lib/action_web_service/wsdl/wsdl.rb +23 -0
  111. data/lib/action_web_service/wsdl/xmlSchema/all.rb +69 -0
  112. data/lib/action_web_service/wsdl/xmlSchema/annotation.rb +34 -0
  113. data/lib/action_web_service/wsdl/xmlSchema/any.rb +56 -0
  114. data/lib/action_web_service/wsdl/xmlSchema/attribute.rb +127 -0
  115. data/lib/action_web_service/wsdl/xmlSchema/choice.rb +69 -0
  116. data/lib/action_web_service/wsdl/xmlSchema/complexContent.rb +92 -0
  117. data/lib/action_web_service/wsdl/xmlSchema/complexType.rb +139 -0
  118. data/lib/action_web_service/wsdl/xmlSchema/content.rb +96 -0
  119. data/lib/action_web_service/wsdl/xmlSchema/data.rb +80 -0
  120. data/lib/action_web_service/wsdl/xmlSchema/element.rb +154 -0
  121. data/lib/action_web_service/wsdl/xmlSchema/enumeration.rb +36 -0
  122. data/lib/action_web_service/wsdl/xmlSchema/import.rb +65 -0
  123. data/lib/action_web_service/wsdl/xmlSchema/importer.rb +87 -0
  124. data/lib/action_web_service/wsdl/xmlSchema/include.rb +54 -0
  125. data/lib/action_web_service/wsdl/xmlSchema/length.rb +35 -0
  126. data/lib/action_web_service/wsdl/xmlSchema/parser.rb +166 -0
  127. data/lib/action_web_service/wsdl/xmlSchema/pattern.rb +36 -0
  128. data/lib/action_web_service/wsdl/xmlSchema/schema.rb +143 -0
  129. data/lib/action_web_service/wsdl/xmlSchema/sequence.rb +69 -0
  130. data/lib/action_web_service/wsdl/xmlSchema/simpleContent.rb +65 -0
  131. data/lib/action_web_service/wsdl/xmlSchema/simpleExtension.rb +54 -0
  132. data/lib/action_web_service/wsdl/xmlSchema/simpleRestriction.rb +73 -0
  133. data/lib/action_web_service/wsdl/xmlSchema/simpleType.rb +73 -0
  134. data/lib/action_web_service/wsdl/xmlSchema/unique.rb +34 -0
  135. data/lib/action_web_service/wsdl/xmlSchema/xsd2ruby.rb +107 -0
  136. data/lib/action_web_service/xsd/charset.rb +187 -0
  137. data/lib/action_web_service/xsd/codegen.rb +12 -0
  138. data/lib/action_web_service/xsd/codegen/classdef.rb +203 -0
  139. data/lib/action_web_service/xsd/codegen/commentdef.rb +34 -0
  140. data/lib/action_web_service/xsd/codegen/gensupport.rb +166 -0
  141. data/lib/action_web_service/xsd/codegen/methoddef.rb +63 -0
  142. data/lib/action_web_service/xsd/codegen/moduledef.rb +191 -0
  143. data/lib/action_web_service/xsd/datatypes.rb +1269 -0
  144. data/lib/action_web_service/xsd/datatypes1999.rb +20 -0
  145. data/lib/action_web_service/xsd/iconvcharset.rb +33 -0
  146. data/lib/action_web_service/xsd/mapping.rb +42 -0
  147. data/lib/action_web_service/xsd/namedelements.rb +95 -0
  148. data/lib/action_web_service/xsd/ns.rb +140 -0
  149. data/lib/action_web_service/xsd/qname.rb +78 -0
  150. data/lib/action_web_service/xsd/xmlparser.rb +61 -0
  151. data/lib/action_web_service/xsd/xmlparser/parser.rb +96 -0
  152. data/lib/action_web_service/xsd/xmlparser/rexmlparser.rb +54 -0
  153. data/lib/action_web_service/xsd/xmlparser/xmlparser.rb +50 -0
  154. data/lib/action_web_service/xsd/xmlparser/xmlscanner.rb +147 -0
  155. data/lib/actionwebservice.rb +1 -0
  156. data/setup.rb +1379 -0
  157. data/test/abstract_client.rb +183 -0
  158. data/test/abstract_dispatcher.rb +548 -0
  159. data/test/abstract_unit.rb +45 -0
  160. data/test/api_test.rb +103 -0
  161. data/test/apis/auto_load_api.rb +3 -0
  162. data/test/apis/broken_auto_load_api.rb +2 -0
  163. data/test/base_test.rb +42 -0
  164. data/test/casting_test.rb +95 -0
  165. data/test/client_soap_test.rb +156 -0
  166. data/test/client_xmlrpc_test.rb +153 -0
  167. data/test/container_test.rb +73 -0
  168. data/test/dispatcher_action_controller_soap_test.rb +139 -0
  169. data/test/dispatcher_action_controller_xmlrpc_test.rb +59 -0
  170. data/test/fixtures/db_definitions/mysql.sql +8 -0
  171. data/test/fixtures/db_definitions/sqlite3.sql +8 -0
  172. data/test/fixtures/users.yml +12 -0
  173. data/test/gencov +3 -0
  174. data/test/invocation_test.rb +185 -0
  175. data/test/run +6 -0
  176. data/test/scaffolded_controller_test.rb +146 -0
  177. data/test/struct_test.rb +52 -0
  178. data/test/test_invoke_test.rb +112 -0
  179. metadata +265 -0
@@ -0,0 +1,38 @@
1
+ module ActionWebService # :nodoc:
2
+ class ActionWebServiceError < StandardError # :nodoc:
3
+ end
4
+
5
+ # An Action Web Service object implements a specified API.
6
+ #
7
+ # Used by controllers operating in _Delegated_ dispatching mode.
8
+ #
9
+ # ==== Example
10
+ #
11
+ # class PersonService < ActionWebService::Base
12
+ # web_service_api PersonAPI
13
+ #
14
+ # def find_person(criteria)
15
+ # Person.find(:all) [...]
16
+ # end
17
+ #
18
+ # def delete_person(id)
19
+ # Person.find_by_id(id).destroy
20
+ # end
21
+ # end
22
+ #
23
+ # class PersonAPI < ActionWebService::API::Base
24
+ # api_method :find_person, :expects => [SearchCriteria], :returns => [[Person]]
25
+ # api_method :delete_person, :expects => [:int]
26
+ # end
27
+ #
28
+ # class SearchCriteria < ActionWebService::Struct
29
+ # member :firstname, :string
30
+ # member :lastname, :string
31
+ # member :email, :string
32
+ # end
33
+ class Base
34
+ # Whether to report exceptions back to the caller in the protocol's exception
35
+ # format
36
+ class_inheritable_option :web_service_exception_reporting, true
37
+ end
38
+ end
@@ -0,0 +1,149 @@
1
+ require 'time'
2
+ require 'date'
3
+ require 'xmlrpc/datetime'
4
+
5
+ module ActionWebService # :nodoc:
6
+ module Casting # :nodoc:
7
+ class CastingError < ActionWebServiceError # :nodoc:
8
+ end
9
+
10
+ # Performs casting of arbitrary values into the correct types for the signature
11
+ class BaseCaster # :nodoc:
12
+ def initialize(api_method)
13
+ @api_method = api_method
14
+ end
15
+
16
+ # Coerces the parameters in +params+ (an Enumerable) into the types
17
+ # this method expects
18
+ def cast_expects(params)
19
+ self.class.cast_expects(@api_method, params)
20
+ end
21
+
22
+ # Coerces the given +return_value+ into the type returned by this
23
+ # method
24
+ def cast_returns(return_value)
25
+ self.class.cast_returns(@api_method, return_value)
26
+ end
27
+
28
+ class << self
29
+ include ActionWebService::SignatureTypes
30
+
31
+ def cast_expects(api_method, params) # :nodoc:
32
+ return [] if api_method.expects.nil?
33
+ api_method.expects.zip(params).map{ |type, param| cast(param, type) }
34
+ end
35
+
36
+ def cast_returns(api_method, return_value) # :nodoc:
37
+ return nil if api_method.returns.nil?
38
+ cast(return_value, api_method.returns[0])
39
+ end
40
+
41
+ def cast(value, signature_type) # :nodoc:
42
+ return value if signature_type.nil? # signature.length != params.length
43
+ return nil if value.nil?
44
+ # XMLRPC protocol doesn't support nil values. It uses false instead.
45
+ # It should never happen for SOAP.
46
+ if signature_type.structured? && value.equal?(false)
47
+ return nil
48
+ end
49
+ unless signature_type.array? || signature_type.structured?
50
+ return value if canonical_type(value.class) == signature_type.type
51
+ end
52
+ if signature_type.array?
53
+ unless value.respond_to?(:entries) && !value.is_a?(String)
54
+ raise CastingError, "Don't know how to cast #{value.class} into #{signature_type.type.inspect}"
55
+ end
56
+ value.entries.map do |entry|
57
+ cast(entry, signature_type.element_type)
58
+ end
59
+ elsif signature_type.structured?
60
+ cast_to_structured_type(value, signature_type)
61
+ elsif !signature_type.custom?
62
+ cast_base_type(value, signature_type)
63
+ end
64
+ end
65
+
66
+ def cast_base_type(value, signature_type) # :nodoc:
67
+ # This is a work-around for the fact that XML-RPC special-cases DateTime values into its own DateTime type
68
+ # in order to support iso8601 dates. This doesn't work too well for us, so we'll convert it into a Time,
69
+ # with the caveat that we won't be able to handle pre-1970 dates that are sent to us.
70
+ #
71
+ # See http://dev.rubyonrails.com/ticket/2516
72
+ value = value.to_time if value.is_a?(XMLRPC::DateTime)
73
+
74
+ case signature_type.type
75
+ when :int
76
+ Integer(value)
77
+ when :string
78
+ value.to_s
79
+ when :base64
80
+ if value.is_a?(ActionWebService::Base64)
81
+ value
82
+ else
83
+ ActionWebService::Base64.new(value.to_s)
84
+ end
85
+ when :bool
86
+ return false if value.nil?
87
+ return value if value == true || value == false
88
+ case value.to_s.downcase
89
+ when '1', 'true', 'y', 'yes'
90
+ true
91
+ when '0', 'false', 'n', 'no'
92
+ false
93
+ else
94
+ raise CastingError, "Don't know how to cast #{value.class} into Boolean"
95
+ end
96
+ when :float
97
+ Float(value)
98
+ when :decimal
99
+ BigDecimal(value.to_s)
100
+ when :time
101
+ value = "%s/%s/%s %s:%s:%s" % value.values_at(*%w[2 3 1 4 5 6]) if value.kind_of?(Hash)
102
+ if value.kind_of?(Time)
103
+ value
104
+ elsif value.kind_of?(DateTime)
105
+ value.to_time
106
+ else
107
+ Time.parse(value.to_s)
108
+ end
109
+ when :date
110
+ value = "%s/%s/%s" % value.values_at(*%w[2 3 1]) if value.kind_of?(Hash)
111
+ value.kind_of?(Date) ? value : Date.parse(value.to_s)
112
+ when :datetime
113
+ value = "%s/%s/%s %s:%s:%s" % value.values_at(*%w[2 3 1 4 5 6]) if value.kind_of?(Hash)
114
+ value.kind_of?(DateTime) ? value : DateTime.parse(value.to_s)
115
+ end
116
+ end
117
+
118
+ def cast_to_structured_type(value, signature_type) # :nodoc:
119
+ obj = nil
120
+ # if the canonical classes are the same or if the given value is of
121
+ # a type that is derived from the signature_type do not attempt to
122
+ # "cast" the value into the signature_type as it's already good to go
123
+ obj = (
124
+ canonical_type(value.class) == canonical_type(signature_type.type) or
125
+ derived_from?(signature_type.type, value.class)
126
+ ) ? value : signature_type.type_class.new
127
+ if value.respond_to?(:each_pair)
128
+ klass = signature_type.type_class
129
+ value.each_pair do |name, val|
130
+ type = klass.respond_to?(:member_type) ? klass.member_type(name) : nil
131
+ val = cast(val, type) if type
132
+ # See http://dev.rubyonrails.com/ticket/3567
133
+ val = val.to_time if val.is_a?(XMLRPC::DateTime)
134
+ obj.__send__("#{name}=", val) if obj.respond_to?(name)
135
+ end
136
+ elsif value.respond_to?(:attributes)
137
+ signature_type.each_member do |name, type|
138
+ val = value.__send__(name)
139
+ obj.__send__("#{name}=", cast(val, type)) if obj.respond_to?(name)
140
+ end
141
+ else
142
+ raise CastingError, "Don't know how to cast #{value.class} to #{signature_type.type_class}"
143
+ end
144
+ obj
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,3 @@
1
+ require 'action_web_service/client/base'
2
+ require 'action_web_service/client/soap_client'
3
+ require 'action_web_service/client/xmlrpc_client'
@@ -0,0 +1,28 @@
1
+ module ActionWebService # :nodoc:
2
+ module Client # :nodoc:
3
+ class ClientError < StandardError # :nodoc:
4
+ end
5
+
6
+ class Base # :nodoc:
7
+ def initialize(api, endpoint_uri)
8
+ @api = api
9
+ @endpoint_uri = endpoint_uri
10
+ end
11
+
12
+ def method_missing(name, *args) # :nodoc:
13
+ call_name = method_name(name)
14
+ return super(name, *args) if call_name.nil?
15
+ self.perform_invocation(call_name, args)
16
+ end
17
+
18
+ private
19
+ def method_name(name)
20
+ if @api.has_api_method?(name.to_sym)
21
+ name.to_s
22
+ elsif @api.has_public_api_method?(name.to_s)
23
+ @api.api_method_name(name.to_s).to_s
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,113 @@
1
+ require 'action_web_service/soap/rpc/driver'
2
+ require 'uri'
3
+
4
+ module ActionWebService # :nodoc:
5
+ module Client # :nodoc:
6
+
7
+ # Implements SOAP client support (using RPC encoding for the messages).
8
+ #
9
+ # ==== Example Usage
10
+ #
11
+ # class PersonAPI < ActionWebService::API::Base
12
+ # api_method :find_all, :returns => [[Person]]
13
+ # end
14
+ #
15
+ # soap_client = ActionWebService::Client::Soap.new(PersonAPI, "http://...")
16
+ # persons = soap_client.find_all
17
+ #
18
+ class Soap < Base
19
+ # provides access to the underlying soap driver
20
+ attr_reader :driver
21
+
22
+ # Creates a new web service client using the SOAP RPC protocol.
23
+ #
24
+ # +api+ must be an ActionWebService::API::Base derivative, and
25
+ # +endpoint_uri+ must point at the relevant URL to which protocol requests
26
+ # will be sent with HTTP POST.
27
+ #
28
+ # Valid options:
29
+ # [<tt>:namespace</tt>] If the remote server has used a custom namespace to
30
+ # declare its custom types, you can specify it here. This would
31
+ # be the namespace declared with a [WebService(Namespace = "http://namespace")] attribute
32
+ # in .NET, for example.
33
+ # [<tt>:driver_options</tt>] If you want to supply any custom SOAP RPC driver
34
+ # options, you can provide them as a Hash here
35
+ #
36
+ # The <tt>:driver_options</tt> option can be used to configure the backend SOAP
37
+ # RPC driver. An example of configuring the SOAP backend to do
38
+ # client-certificate authenticated SSL connections to the server:
39
+ #
40
+ # opts = {}
41
+ # opts['protocol.http.ssl_config.verify_mode'] = 'OpenSSL::SSL::VERIFY_PEER'
42
+ # opts['protocol.http.ssl_config.client_cert'] = client_cert_file_path
43
+ # opts['protocol.http.ssl_config.client_key'] = client_key_file_path
44
+ # opts['protocol.http.ssl_config.ca_file'] = ca_cert_file_path
45
+ # client = ActionWebService::Client::Soap.new(api, 'https://some/service', :driver_options => opts)
46
+ def initialize(api, endpoint_uri, options={})
47
+ super(api, endpoint_uri)
48
+ @namespace = options[:namespace] || 'urn:ActionWebService'
49
+ @driver_options = options[:driver_options] || {}
50
+ @protocol = ActionWebService::Protocol::Soap::SoapProtocol.new @namespace
51
+ @soap_action_base = options[:soap_action_base]
52
+ @soap_action_base ||= URI.parse(endpoint_uri).path
53
+ @driver = create_soap_rpc_driver(api, endpoint_uri)
54
+ @driver_options.each do |name, value|
55
+ @driver.options[name.to_s] = value
56
+ end
57
+ end
58
+
59
+ protected
60
+ def perform_invocation(method_name, args)
61
+ method = @api.api_methods[method_name.to_sym]
62
+ args = method.cast_expects(args.dup) rescue args
63
+ return_value = @driver.send(method_name, *args)
64
+ method.cast_returns(return_value.dup) rescue return_value
65
+ end
66
+
67
+ def soap_action(method_name)
68
+ "#{@soap_action_base}/#{method_name}"
69
+ end
70
+
71
+ private
72
+ def create_soap_rpc_driver(api, endpoint_uri)
73
+ @protocol.register_api(api)
74
+ driver = SoapDriver.new(endpoint_uri, nil)
75
+ driver.mapping_registry = @protocol.marshaler.registry
76
+ api.api_methods.each do |name, method|
77
+ qname = XSD::QName.new(@namespace, method.public_name)
78
+ action = soap_action(method.public_name)
79
+ expects = method.expects
80
+ returns = method.returns
81
+ param_def = []
82
+ if expects
83
+ expects.each do |type|
84
+ type_binding = @protocol.marshaler.lookup_type(type)
85
+ if SOAP::Version >= "1.5.5"
86
+ param_def << ['in', type.name.to_s, [type_binding.type.type_class.to_s]]
87
+ else
88
+ param_def << ['in', type.name, type_binding.mapping]
89
+ end
90
+ end
91
+ end
92
+ if returns
93
+ type_binding = @protocol.marshaler.lookup_type(returns[0])
94
+ if SOAP::Version >= "1.5.5"
95
+ param_def << ['retval', 'return', [type_binding.type.type_class.to_s]]
96
+ else
97
+ param_def << ['retval', 'return', type_binding.mapping]
98
+ end
99
+ end
100
+ driver.add_method(qname, action, method.name.to_s, param_def)
101
+ end
102
+ driver
103
+ end
104
+
105
+ class SoapDriver < SOAP::RPC::Driver # :nodoc:
106
+ def add_method(qname, soapaction, name, param_def)
107
+ @proxy.add_rpc_method(qname, soapaction, name, param_def)
108
+ add_rpc_method_interface(name, param_def)
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,58 @@
1
+ require 'uri'
2
+ require 'xmlrpc/client'
3
+
4
+ module ActionWebService # :nodoc:
5
+ module Client # :nodoc:
6
+
7
+ # Implements XML-RPC client support
8
+ #
9
+ # ==== Example Usage
10
+ #
11
+ # class BloggerAPI < ActionWebService::API::Base
12
+ # inflect_names false
13
+ # api_method :getRecentPosts, :returns => [[Blog::Post]]
14
+ # end
15
+ #
16
+ # blog = ActionWebService::Client::XmlRpc.new(BloggerAPI, "http://.../RPC", :handler_name => "blogger")
17
+ # posts = blog.getRecentPosts
18
+ class XmlRpc < Base
19
+
20
+ # Creates a new web service client using the XML-RPC protocol.
21
+ #
22
+ # +api+ must be an ActionWebService::API::Base derivative, and
23
+ # +endpoint_uri+ must point at the relevant URL to which protocol requests
24
+ # will be sent with HTTP POST.
25
+ #
26
+ # Valid options:
27
+ # [<tt>:handler_name</tt>] If the remote server defines its services inside special
28
+ # handler (the Blogger API uses a <tt>"blogger"</tt> handler name for example),
29
+ # provide it here, or your method calls will fail
30
+ def initialize(api, endpoint_uri, options={})
31
+ @api = api
32
+ @handler_name = options[:handler_name]
33
+ @protocol = ActionWebService::Protocol::XmlRpc::XmlRpcProtocol.new
34
+ @client = XMLRPC::Client.new2(endpoint_uri, options[:proxy], options[:timeout])
35
+ end
36
+
37
+ protected
38
+ def perform_invocation(method_name, args)
39
+ method = @api.api_methods[method_name.to_sym]
40
+ if method.expects && method.expects.length != args.length
41
+ raise(ArgumentError, "#{method.public_name}: wrong number of arguments (#{args.length} for #{method.expects.length})")
42
+ end
43
+ args = method.cast_expects(args.dup) rescue args
44
+ if method.expects
45
+ method.expects.each_with_index{ |type, i| args[i] = @protocol.value_to_xmlrpc_wire_format(args[i], type) }
46
+ end
47
+ ok, return_value = @client.call2(public_name(method_name), *args)
48
+ return (method.cast_returns(return_value.dup) rescue return_value) if ok
49
+ raise(ClientError, "#{return_value.faultCode}: #{return_value.faultString}")
50
+ end
51
+
52
+ def public_name(method_name)
53
+ public_name = @api.public_api_method_name(method_name)
54
+ @handler_name ? "#{@handler_name}.#{public_name}" : public_name
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ require 'action_web_service/container/direct_container'
2
+ require 'action_web_service/container/delegated_container'
3
+ require 'action_web_service/container/action_controller_container'
@@ -0,0 +1,93 @@
1
+ module ActionWebService # :nodoc:
2
+ module Container # :nodoc:
3
+ module ActionController # :nodoc:
4
+ def self.included(base) # :nodoc:
5
+ class << base
6
+ include ClassMethods
7
+ alias_method_chain :inherited, :api
8
+ alias_method_chain :web_service_api, :require
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+ # Creates a client for accessing remote web services, using the
14
+ # given +protocol+ to communicate with the +endpoint_uri+.
15
+ #
16
+ # ==== Example
17
+ #
18
+ # class MyController < ActionController::Base
19
+ # web_client_api :blogger, :xmlrpc, "http://blogger.com/myblog/api/RPC2", :handler_name => 'blogger'
20
+ # end
21
+ #
22
+ # In this example, a protected method named <tt>blogger</tt> will
23
+ # now exist on the controller, and calling it will return the
24
+ # XML-RPC client object for working with that remote service.
25
+ #
26
+ # +options+ is the set of protocol client specific options (see
27
+ # a protocol client class for details).
28
+ #
29
+ # If your API definition does not exist on the load path with the
30
+ # correct rules for it to be found using +name+, you can pass in
31
+ # the API definition class via +options+, using a key of <tt>:api</tt>
32
+ def web_client_api(name, protocol, endpoint_uri, options={})
33
+ unless method_defined?(name)
34
+ api_klass = options.delete(:api) || require_web_service_api(name)
35
+ class_eval do
36
+ define_method(name) do
37
+ create_web_service_client(api_klass, protocol, endpoint_uri, options)
38
+ end
39
+ protected name
40
+ end
41
+ end
42
+ end
43
+
44
+ def web_service_api_with_require(definition=nil) # :nodoc:
45
+ return web_service_api_without_require if definition.nil?
46
+ case definition
47
+ when String, Symbol
48
+ klass = require_web_service_api(definition)
49
+ else
50
+ klass = definition
51
+ end
52
+ web_service_api_without_require(klass)
53
+ end
54
+
55
+ def require_web_service_api(name) # :nodoc:
56
+ case name
57
+ when String, Symbol
58
+ file_name = name.to_s.underscore + "_api"
59
+ class_name = file_name.camelize
60
+ class_names = [class_name, class_name.sub(/Api$/, 'API')]
61
+ begin
62
+ require_dependency(file_name)
63
+ rescue LoadError => load_error
64
+ requiree = / -- (.*?)(\.rb)?$/.match(load_error.to_s).to_a[1]
65
+ msg = requiree == file_name ? "Missing API definition file in apis/#{file_name}.rb" : "Can't load file: #{requiree}"
66
+ raise LoadError.new(msg).copy_blame!(load_error)
67
+ end
68
+ klass = nil
69
+ class_names.each do |name|
70
+ klass = name.constantize rescue nil
71
+ break unless klass.nil?
72
+ end
73
+ unless klass
74
+ raise(NameError, "neither #{class_names[0]} or #{class_names[1]} found")
75
+ end
76
+ klass
77
+ else
78
+ raise(ArgumentError, "expected String or Symbol argument")
79
+ end
80
+ end
81
+
82
+ private
83
+ def inherited_with_api(child)
84
+ inherited_without_api(child)
85
+ begin child.web_service_api(child.controller_path)
86
+ rescue MissingSourceFile => e
87
+ raise unless e.is_missing?("apis/#{child.controller_path}_api")
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end