aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeon Breedt <bitserf@gmail.com>2005-04-02 21:03:36 +0000
committerLeon Breedt <bitserf@gmail.com>2005-04-02 21:03:36 +0000
commitaaea48fe9826b9e5d2d5b92795a297b8f238c58d (patch)
treee7c01c7f95d467f837c1f96d58dac74c3c902610
parentaa09c770e9b5400683be11952673017295246de7 (diff)
downloadrails-aaea48fe9826b9e5d2d5b92795a297b8f238c58d.tar.gz
rails-aaea48fe9826b9e5d2d5b92795a297b8f238c58d.tar.bz2
rails-aaea48fe9826b9e5d2d5b92795a297b8f238c58d.zip
* collapse 'ws' back into protocols, it just added complexity and indirection, and was hard to extend.
* extract casting into seperate support file * ensure casting always does the right thing for return values, should fix interoperability issues with Ecto and possibly other XML-RPC clients * add functional unit tests for scaffolding * represent signature items with classes instead of symbols/Class objects, much more flexible * tweak logging to always show casted versions of parameters and return values, if possible. git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1072 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
-rw-r--r--actionwebservice/CHANGELOG6
-rw-r--r--actionwebservice/Rakefile2
-rw-r--r--actionwebservice/TODO5
-rw-r--r--actionwebservice/lib/action_web_service.rb4
-rw-r--r--actionwebservice/lib/action_web_service/api/base.rb146
-rw-r--r--actionwebservice/lib/action_web_service/casting.rb105
-rw-r--r--actionwebservice/lib/action_web_service/client/soap_client.rb20
-rw-r--r--actionwebservice/lib/action_web_service/client/xmlrpc_client.rb10
-rw-r--r--actionwebservice/lib/action_web_service/dispatcher/abstract.rb40
-rw-r--r--actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb63
-rw-r--r--actionwebservice/lib/action_web_service/protocol/abstract.rb93
-rw-r--r--actionwebservice/lib/action_web_service/protocol/discovery.rb4
-rw-r--r--actionwebservice/lib/action_web_service/protocol/soap_protocol.rb111
-rw-r--r--actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb197
-rw-r--r--actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb55
-rw-r--r--actionwebservice/lib/action_web_service/scaffolding.rb43
-rw-r--r--actionwebservice/lib/action_web_service/struct.rb15
-rw-r--r--actionwebservice/lib/action_web_service/support/signature_types.rb191
-rw-r--r--actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml6
-rw-r--r--actionwebservice/lib/action_web_service/test_invoke.rb37
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws.rb4
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/common.rb8
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/encoding.rb3
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/encoding/abstract.rb26
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb90
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb44
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/marshaling.rb3
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/marshaling/abstract.rb33
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb283
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb143
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/types.rb165
-rw-r--r--actionwebservice/test/abstract_dispatcher.rb96
-rw-r--r--actionwebservice/test/abstract_unit.rb2
-rw-r--r--actionwebservice/test/api_test.rb16
-rw-r--r--actionwebservice/test/casting_test.rb82
-rw-r--r--actionwebservice/test/client_soap_test.rb4
-rw-r--r--actionwebservice/test/client_xmlrpc_test.rb7
-rw-r--r--actionwebservice/test/dispatcher_action_controller_soap_test.rb2
-rw-r--r--actionwebservice/test/dispatcher_action_controller_xmlrpc_test.rb2
-rw-r--r--actionwebservice/test/scaffolded_controller_test.rb67
-rw-r--r--actionwebservice/test/struct_test.rb56
-rw-r--r--actionwebservice/test/test_invoke_test.rb2
-rw-r--r--actionwebservice/test/ws/abstract_encoding.rb68
-rw-r--r--actionwebservice/test/ws/abstract_unit.rb13
-rwxr-xr-xactionwebservice/test/ws/gencov3
-rwxr-xr-xactionwebservice/test/ws/run5
-rw-r--r--actionwebservice/test/ws/soap_marshaling_test.rb97
-rw-r--r--actionwebservice/test/ws/soap_rpc_encoding_test.rb47
-rw-r--r--actionwebservice/test/ws/types_test.rb43
-rw-r--r--actionwebservice/test/ws/xmlrpc_encoding_test.rb34
50 files changed, 1090 insertions, 1511 deletions
diff --git a/actionwebservice/CHANGELOG b/actionwebservice/CHANGELOG
index fc50e0a7b9..ae94240cc3 100644
--- a/actionwebservice/CHANGELOG
+++ b/actionwebservice/CHANGELOG
@@ -1,11 +1,13 @@
*0.7.0* (Unreleased)
-* Remove ActiveRecordSoapMarshallable workaround, see #912 for details
-
* Add scaffolding via ActionController::Base.web_service_scaffold for quick testing using a web browser
+* Remove ActiveRecordSoapMarshallable workaround, see #912 for details
+
* Generalize casting code to be used by both SOAP and XML-RPC (previously, it was only XML-RPC)
+* Ensure return value is properly cast as well, fixes XML-RPC interoperability with Ecto and possibly other clients
+
* Include backtraces in 500 error responses for failed request parsing, and remove "rescue nil" statements obscuring real errors for XML-RPC
diff --git a/actionwebservice/Rakefile b/actionwebservice/Rakefile
index a54d72069f..57940f6b9f 100644
--- a/actionwebservice/Rakefile
+++ b/actionwebservice/Rakefile
@@ -264,4 +264,4 @@ task :release => [:package] do
first_file = false
end
end
-end \ No newline at end of file
+end
diff --git a/actionwebservice/TODO b/actionwebservice/TODO
index cf5c11a795..0ec3b52166 100644
--- a/actionwebservice/TODO
+++ b/actionwebservice/TODO
@@ -2,14 +2,9 @@
- WS Dynamic Scaffolding
* add protocol selection ability
* test with XML-RPC (namespaced method name support)
- * support structured types as input parameters with the input field helper
- update manual for scaffolding and functional testing
-
-= 0.8.0
- - Consumption of WSDL services
= Refactoring
- - Port dispatcher tests to use test_invoke
- Don't have clean way to go from SOAP Class object to the xsd:NAME type
string -- NaHi possibly looking at remedying this situation
diff --git a/actionwebservice/lib/action_web_service.rb b/actionwebservice/lib/action_web_service.rb
index d8dc132313..82be41a327 100644
--- a/actionwebservice/lib/action_web_service.rb
+++ b/actionwebservice/lib/action_web_service.rb
@@ -35,12 +35,12 @@ end
$:.unshift(File.dirname(__FILE__) + "/action_web_service/vendor/")
require 'action_web_service/support/class_inheritable_options'
-require 'action_web_service/vendor/ws'
-
+require 'action_web_service/support/signature_types'
require 'action_web_service/base'
require 'action_web_service/client'
require 'action_web_service/invocation'
require 'action_web_service/api'
+require 'action_web_service/casting'
require 'action_web_service/struct'
require 'action_web_service/container'
require 'action_web_service/protocol'
diff --git a/actionwebservice/lib/action_web_service/api/base.rb b/actionwebservice/lib/action_web_service/api/base.rb
index 03e406cfc3..c9fb9f967f 100644
--- a/actionwebservice/lib/action_web_service/api/base.rb
+++ b/actionwebservice/lib/action_web_service/api/base.rb
@@ -1,8 +1,5 @@
module ActionWebService # :nodoc:
module API # :nodoc:
- class CastingError < ActionWebService::ActionWebServiceError
- end
-
# A web service API class specifies the methods that will be available for
# invocation for an API. It also contains metadata such as the method type
# signature hints.
@@ -31,6 +28,8 @@ module ActionWebService # :nodoc:
private_class_method :new, :allocate
class << self
+ include ActionWebService::SignatureTypes
+
# API methods have a +name+, which must be the Ruby method name to use when
# performing the invocation on the web service object.
#
@@ -70,10 +69,9 @@ module ActionWebService # :nodoc:
expects = canonical_signature(expects)
returns = canonical_signature(returns)
if expects
- expects.each do |param|
- klass = WS::BaseTypes.canonical_param_type_class(param)
- klass = klass[0] if klass.is_a?(Array)
- if klass.ancestors.include?(ActiveRecord::Base) && !allow_active_record_expects
+ expects.each do |type|
+ type = type.element_type if type.is_a?(ArrayType)
+ if type.type_class.ancestors.include?(ActiveRecord::Base) && !allow_active_record_expects
raise(ActionWebServiceError, "ActiveRecord model classes not allowed in :expects")
end
end
@@ -138,16 +136,6 @@ module ActionWebService # :nodoc:
instance
end
- # Creates a dummy API Method instance for the given public method name
- def dummy_public_api_method_instance(public_method_name)
- Method.new(public_method_name.underscore.to_sym, public_method_name, nil, nil)
- end
-
- # Creates a dummy API Method instance for the given method name
- def dummy_api_method_instance(method_name)
- Method.new(method_name, public_api_method_name(method_name), nil, nil)
- end
-
private
def api_public_method_names
read_inheritable_attribute("api_public_method_names") || {}
@@ -159,11 +147,6 @@ module ActionWebService # :nodoc:
raise(ActionWebServiceError, "Unknown options: #{unknown_option_keys}")
end
end
-
- def canonical_signature(signature)
- return nil if signature.nil?
- signature.map{|spec| WS::BaseTypes.canonical_param_type_spec(spec)}
- end
end
end
@@ -180,134 +163,41 @@ module ActionWebService # :nodoc:
@public_name = public_name
@expects = expects
@returns = returns
+ @caster = ActionWebService::Casting::BaseCaster.new(self)
end
# The list of parameter names for this method
def param_names
return [] unless @expects
- i = 0
- @expects.map{ |spec| param_name(spec, i += 1) }
- end
-
- # The name for the given parameter
- def param_name(spec, i=1)
- spec.is_a?(Hash) ? spec.keys.first.to_s : "p#{i}"
- end
-
- # The type of the parameter declared in +spec+. Is either
- # the Class of the parameter, or its canonical name (if its a
- # base type). Typed array specifications will return the type of
- # their elements.
- def param_type(spec)
- spec = spec.values.first if spec.is_a?(Hash)
- param_type = spec.is_a?(Array) ? spec[0] : spec
- WS::BaseTypes::class_to_type_name(param_type) rescue param_type
- end
-
- # The Class of the parameter declared in +spec+.
- def param_class(spec)
- type = param_type(spec)
- type.is_a?(Symbol) ? WS::BaseTypes.type_name_to_class(type) : type
- end
-
- # Registers all types known to this method with the given marshaler
- def register_types(marshaler)
- @expects.each{ |x| marshaler.register_type(x) } if @expects
- @returns.each{ |x| marshaler.register_type(x) } if @returns
+ @expects.map{ |type| type.name }
end
- # Encodes an RPC call for this method. Casting is performed if
- # the <tt>:strict</tt> option is given.
- def encode_rpc_call(marshaler, encoder, params, options={})
- name = options[:method_name] || @public_name
- expects = @expects || []
- returns = @returns || []
- (expects + returns).each { |spec| marshaler.register_type spec }
- (0..(params.length-1)).each do |i|
- spec = expects[i] || params[i].class
- type_binding = marshaler.lookup_type(spec)
- param_info = WS::ParamInfo.create(spec, type_binding, i)
- if options[:strict]
- value = marshaler.cast_outbound_recursive(params[i], spec)
- else
- value = params[i]
- end
- param = WS::Param.new(value, param_info)
- params[i] = marshaler.marshal(param)
- end
- encoder.encode_rpc_call(name, params)
- end
-
- # Encodes an RPC response for this method. Casting is performed if
- # the <tt>:strict</tt> option is given.
- def encode_rpc_response(marshaler, encoder, return_value, options={})
- if !return_value.nil? && @returns
- return_type = @returns[0]
- type_binding = marshaler.register_type(return_type)
- param_info = WS::ParamInfo.create(return_type, type_binding, 0)
- if options[:strict]
- return_value = marshaler.cast_inbound_recursive(return_value, return_type)
- end
- return_value = marshaler.marshal(WS::Param.new(return_value, param_info))
- else
- return_value = nil
- end
- encoder.encode_rpc_response(response_name(encoder), return_value)
- end
-
- # Casts a set of WS::Param values into the appropriate
- # Ruby values
- def cast_expects_ws2ruby(marshaler, params)
- return [] if @expects.nil?
- i = 0
- @expects.map do |spec|
- value = marshaler.cast_inbound_recursive(params[i].value, spec)
- i += 1
- value
- end
- end
-
# Casts a set of Ruby values into the expected Ruby values
- def cast_expects(marshaler, params)
- return [] if @expects.nil?
- i = 0
- @expects.map do |spec|
- value = marshaler.cast_outbound_recursive(params[i], spec)
- i += 1
- value
- end
+ def cast_expects(params)
+ @caster.cast_expects(params)
end
# Cast a Ruby return value into the expected Ruby value
- def cast_returns(marshaler, return_value)
- return nil if @returns.nil?
- marshaler.cast_inbound_recursive(return_value, @returns[0])
+ def cast_returns(return_value)
+ @caster.cast_returns(return_value)
end
# String representation of this method
def to_s
fqn = ""
- fqn << (@returns ? (friendly_param(@returns[0], nil) + " ") : "void ")
+ fqn << (@returns ? (friendly_param(@returns[0], false) + " ") : "void ")
fqn << "#{@public_name}("
- if @expects
- i = 0
- fqn << @expects.map{ |p| friendly_param(p, i+= 1) }.join(", ")
- end
+ fqn << @expects.map{ |p| friendly_param(p) }.join(", ") if @expects
fqn << ")"
fqn
end
private
- def response_name(encoder)
- encoder.is_a?(WS::Encoding::SoapRpcEncoding) ? (@public_name + "Response") : @public_name
- end
-
- def friendly_param(spec, i)
- name = param_name(spec, i)
- type = param_type(spec)
- spec = spec.values.first if spec.is_a?(Hash)
- type = spec.is_a?(Array) ? (type.to_s + "[]") : type.to_s
- i ? (type + " " + name) : type
+ def friendly_param(type, show_name=true)
+ name = type.name.to_s
+ type_type = type.type.to_s
+ str = type.array?? (type_type + '[]') : type_type
+ show_name ? (str + " " + name) : str
end
end
end
diff --git a/actionwebservice/lib/action_web_service/casting.rb b/actionwebservice/lib/action_web_service/casting.rb
new file mode 100644
index 0000000000..ce90c463d8
--- /dev/null
+++ b/actionwebservice/lib/action_web_service/casting.rb
@@ -0,0 +1,105 @@
+require 'time'
+require 'date'
+require 'generator'
+
+module ActionWebService # :nodoc:
+ module Casting # :nodoc:
+ class CastingError < ActionWebServiceError # :nodoc:
+ end
+
+ # Performs casting of arbitrary values into the correct types for the signature
+ class BaseCaster
+ def initialize(api_method)
+ @api_method = api_method
+ end
+
+ # Coerces the parameters in +params+ (an Enumerable) into the types
+ # this method expects
+ def cast_expects(params)
+ self.class.cast_expects(@api_method, params)
+ end
+
+ # Coerces the given +return_value+ into the the type returned by this
+ # method
+ def cast_returns(return_value)
+ self.class.cast_returns(@api_method, return_value)
+ end
+
+ class << self
+ include ActionWebService::SignatureTypes
+
+ def cast_expects(api_method, params) # :nodoc:
+ return [] if api_method.expects.nil?
+ SyncEnumerator.new(params, api_method.expects).map{ |r| cast(r[0], r[1]) }
+ end
+
+ def cast_returns(api_method, return_value) # :nodoc:
+ return nil if api_method.returns.nil?
+ cast(return_value, api_method.returns[0])
+ end
+
+ def cast(value, signature_type) # :nodoc:
+ return value if signature_type.nil? # signature.length != params.length
+ unless signature_type.array?
+ return value if canonical_type(value.class) == signature_type.type
+ end
+ if signature_type.array?
+ unless value.respond_to?(:entries) && !value.is_a?(String)
+ raise CastingError, "Don't know how to cast #{value.class} into #{signature_type.type.inspect}"
+ end
+ value.entries.map do |entry|
+ cast(entry, signature_type.element_type)
+ end
+ elsif signature_type.structured?
+ cast_to_structured_type(value, signature_type)
+ elsif !signature_type.custom?
+ cast_base_type(value, signature_type)
+ end
+ end
+
+ def cast_base_type(value, signature_type) # :nodoc:
+ case signature_type.type
+ when :int
+ Integer(value)
+ when :string
+ value.to_s
+ when :bool
+ return false if value.nil?
+ return value if value == true || value == false
+ case value.to_s.downcase
+ when '1', 'true', 'y', 'yes'
+ true
+ when '0', 'false', 'n', 'no'
+ false
+ else
+ raise CastingError, "Don't know how to cast #{value.class} into Boolean"
+ end
+ when :float
+ Float(value)
+ when :time
+ Time.parse(value.to_s)
+ when :date
+ Date.parse(value.to_s)
+ when :datetime
+ DateTime.parse(value.to_s)
+ end
+ end
+
+ def cast_to_structured_type(value, signature_type) # :nodoc:
+ obj = signature_type.type_class.new
+ if value.respond_to?(:each_pair)
+ klass = signature_type.type_class
+ value.each_pair do |name, val|
+ type = klass.respond_to?(:member_type) ? klass.member_type(name) : nil
+ val = cast(val, type) if type
+ obj.send("#{name}=", val)
+ end
+ else
+ raise CastingError, "Don't know how to cast #{value.class} to #{signature_type.type_class}"
+ end
+ obj
+ end
+ end
+ end
+ end
+end
diff --git a/actionwebservice/lib/action_web_service/client/soap_client.rb b/actionwebservice/lib/action_web_service/client/soap_client.rb
index b9eb0d11ad..c906a71331 100644
--- a/actionwebservice/lib/action_web_service/client/soap_client.rb
+++ b/actionwebservice/lib/action_web_service/client/soap_client.rb
@@ -46,8 +46,7 @@ module ActionWebService # :nodoc:
@type_namespace = options[:type_namespace] || 'urn:ActionWebService'
@method_namespace = options[:method_namespace] || 'urn:ActionWebService'
@driver_options = options[:driver_options] || {}
- @marshaler = WS::Marshaling::SoapMarshaler.new @type_namespace
- @encoder = WS::Encoding::SoapRpcEncoding.new @method_namespace
+ @protocol = ActionWebService::Protocol::Soap::SoapProtocol.new
@soap_action_base = options[:soap_action_base]
@soap_action_base ||= URI.parse(endpoint_uri).path
@driver = create_soap_rpc_driver(api, endpoint_uri)
@@ -59,9 +58,9 @@ module ActionWebService # :nodoc:
protected
def perform_invocation(method_name, args)
method = @api.api_methods[method_name.to_sym]
- args = method.cast_expects(@marshaler, args)
+ args = method.cast_expects(args.dup) rescue args
return_value = @driver.send(method_name, *args)
- method.cast_returns(@marshaler, return_value)
+ method.cast_returns(return_value.dup) rescue return_value
end
def soap_action(method_name)
@@ -70,9 +69,9 @@ module ActionWebService # :nodoc:
private
def create_soap_rpc_driver(api, endpoint_uri)
- api.api_methods.each{ |name, method| method.register_types(@marshaler) }
+ @protocol.register_api(api)
driver = SoapDriver.new(endpoint_uri, nil)
- driver.mapping_registry = @marshaler.registry
+ driver.mapping_registry = @protocol.marshaler.registry
api.api_methods.each do |name, method|
qname = XSD::QName.new(@method_namespace, method.public_name)
action = soap_action(method.public_name)
@@ -81,15 +80,14 @@ module ActionWebService # :nodoc:
param_def = []
i = 0
if expects
- expects.each do |spec|
- param_name = method.param_name(spec, i)
- type_binding = @marshaler.lookup_type(spec)
- param_def << ['in', param_name, type_binding.mapping]
+ expects.each do |type|
+ type_binding = @protocol.marshaler.lookup_type(type)
+ param_def << ['in', type.name, type_binding.mapping]
i += 1
end
end
if returns
- type_binding = @marshaler.lookup_type(returns[0])
+ type_binding = @protocol.marshaler.lookup_type(returns[0])
param_def << ['retval', 'return', type_binding.mapping]
end
driver.add_method(qname, action, method.name.to_s, param_def)
diff --git a/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb b/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb
index e0b7efc864..42b5c5d4f9 100644
--- a/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb
+++ b/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb
@@ -30,20 +30,22 @@ module ActionWebService # :nodoc:
def initialize(api, endpoint_uri, options={})
@api = api
@handler_name = options[:handler_name]
+ @protocol = ActionWebService::Protocol::XmlRpc::XmlRpcProtocol.new
@client = XMLRPC::Client.new2(endpoint_uri, options[:proxy], options[:timeout])
- @marshaler = WS::Marshaling::XmlRpcMarshaler.new
end
protected
def perform_invocation(method_name, args)
method = @api.api_methods[method_name.to_sym]
- method.register_types(@marshaler)
if method.expects && method.expects.length != args.length
raise(ArgumentError, "#{method.public_name}: wrong number of arguments (#{args.length} for #{method.expects.length})")
end
- args = method.cast_expects(@marshaler, args)
+ args = method.cast_expects(args.dup) rescue args
+ if method.expects
+ method.expects.each_with_index{ |type, i| args[i] = @protocol.value_to_xmlrpc_wire_format(args[i], type) }
+ end
ok, return_value = @client.call2(public_name(method_name), *args)
- return method.cast_returns(@marshaler, return_value) if ok
+ return (method.cast_returns(return_value.dup) rescue return_value) if ok
raise(ClientError, "#{return_value.faultCode}: #{return_value.faultString}")
end
diff --git a/actionwebservice/lib/action_web_service/dispatcher/abstract.rb b/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
index 69c3b9de3b..975120212f 100644
--- a/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
+++ b/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
@@ -12,14 +12,6 @@ module ActionWebService # :nodoc:
base.send(:include, ActionWebService::Dispatcher::InstanceMethods)
end
- def self.layered_service_name(public_method_name) # :nodoc:
- if public_method_name =~ /^([^\.]+)\.(.*)$/
- $1
- else
- nil
- end
- end
-
module InstanceMethods # :nodoc:
private
def invoke_web_service_request(protocol_request)
@@ -40,13 +32,7 @@ module ActionWebService # :nodoc:
else
return_value = self.__send__(invocation.api_method.name)
end
- if invocation.api.has_api_method?(invocation.api_method.name)
- api_method = invocation.api_method
- else
- api_method = invocation.api_method.dup
- api_method.instance_eval{ @returns = [ return_value.class ] }
- end
- invocation.protocol.marshal_response(api_method, return_value)
+ web_service_create_response(invocation.protocol, invocation.api, invocation.api_method, return_value)
end
def web_service_delegated_invoke(invocation)
@@ -57,7 +43,7 @@ module ActionWebService # :nodoc:
if cancellation_reason
raise(DispatcherError, "request canceled: #{cancellation_reason}")
end
- invocation.protocol.marshal_response(invocation.api_method, return_value)
+ web_service_create_response(invocation.protocol, invocation.api, invocation.api_method, return_value)
end
def web_service_invocation(request)
@@ -79,6 +65,7 @@ module ActionWebService # :nodoc:
invocation.service = web_service_object(invocation.service_name)
invocation.api = invocation.service.class.web_service_api
end
+ invocation.protocol.register_api(invocation.api)
request.api = invocation.api
if invocation.api.has_public_api_method?(public_method_name)
invocation.api_method = invocation.api.public_api_method_instance(public_method_name)
@@ -89,15 +76,20 @@ module ActionWebService # :nodoc:
invocation.api_method = invocation.api.default_api_method_instance
end
end
+ if invocation.service.nil?
+ raise(DispatcherError, "no service available for service name #{invocation.service_name}")
+ end
unless invocation.service.respond_to?(invocation.api_method.name)
- raise(DispatcherError, "no such method '#{public_method_name}' on API #{invocation.api} (#{invocation.api_method.name})")
+ raise(DispatcherError, "no such method '#{public_method_name}' on API #{invocation.api} (#{invocation.api_method.name})")
end
request.api_method = invocation.api_method
begin
- invocation.method_ordered_params = invocation.api_method.cast_expects_ws2ruby(request.protocol.marshaler, request.method_params)
+ invocation.method_ordered_params = invocation.api_method.cast_expects(request.method_params.dup)
rescue
- invocation.method_ordered_params = request.method_params.map{ |x| x.value }
+ logger.warn "Casting of method parameters failed" unless logger.nil?
+ invocation.method_ordered_params = request.method_params
end
+ request.method_params = invocation.method_ordered_params
invocation.method_named_params = {}
invocation.api_method.param_names.inject(0) do |m, n|
invocation.method_named_params[n] = invocation.method_ordered_params[m]
@@ -106,6 +98,16 @@ module ActionWebService # :nodoc:
invocation
end
+ def web_service_create_response(protocol, api, api_method, return_value)
+ if api.has_api_method?(api_method.name)
+ return_type = api_method.returns ? api_method.returns[0] : nil
+ return_value = api_method.cast_returns(return_value)
+ else
+ return_type = ActionWebService::SignatureTypes.canonical_signature_entry(return_value.class, 0)
+ end
+ protocol.encode_response(api_method.public_name + 'Response', return_value, return_type)
+ end
+
class Invocation # :nodoc:
attr_accessor :protocol
attr_accessor :service_name
diff --git a/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb b/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb
index 0140039c49..a4659e5183 100644
--- a/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb
+++ b/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb
@@ -45,7 +45,6 @@ module ActionWebService # :nodoc:
exception = e
end
if request
- log_request(request, @request.raw_post)
response = nil
exception = nil
bm = Benchmark.measure do
@@ -55,6 +54,7 @@ module ActionWebService # :nodoc:
exception = e
end
end
+ log_request(request, @request.raw_post)
if exception
log_error(exception) unless logger.nil?
send_web_service_error_response(request, exception)
@@ -82,10 +82,10 @@ module ActionWebService # :nodoc:
unless self.class.web_service_exception_reporting
exception = DispatcherError.new("Internal server error (exception raised)")
end
- api_method = request.api_method ? request.api_method.dup : nil
- api_method ||= request.api.dummy_api_method_instance(request.method_name)
- api_method.instance_eval{ @returns = [ exception.class ] }
- response = request.protocol.marshal_response(api_method, exception)
+ api_method = request.api_method
+ public_method_name = api_method ? api_method.public_name : request.method_name
+ return_type = ActionWebService::SignatureTypes.canonical_signature_entry(Exception, 0)
+ response = request.protocol.encode_response(public_method_name + 'Response', exception, return_type)
send_web_service_response(response)
else
if self.class.web_service_exception_reporting
@@ -118,7 +118,14 @@ module ActionWebService # :nodoc:
def log_request(request, body)
unless logger.nil?
name = request.method_name
- params = request.method_params.map{|x| "#{x.info.name}=>#{x.value.inspect}"}
+ api_method = request.api_method
+ params = request.method_params
+ if api_method && api_method.expects
+ i = 0
+ params = api_method.expects.map{ |type| param = "#{type.name}=>#{params[i].inspect}"; i+= 1; param }
+ else
+ params = params.map{ |param| param.inspect }
+ end
service = request.service_name
logger.debug("\nWeb Service Request: #{name}(#{params.join(", ")}) Entrypoint: #{service}")
logger.debug(indent(body))
@@ -127,7 +134,8 @@ module ActionWebService # :nodoc:
def log_response(response, elapsed=nil)
unless logger.nil?
- logger.debug("\nWeb Service Response" + (elapsed ? " (%f):" % elapsed : ":"))
+ elapsed = (elapsed ? " (%f):" % elapsed : ":")
+ logger.debug("\nWeb Service Response" + elapsed + " => #{response.return_value.inspect}")
logger.debug(indent(response.body))
end
end
@@ -171,7 +179,7 @@ module ActionWebService # :nodoc:
namespace = 'urn:ActionWebService'
soap_action_base = "/#{controller_name}"
- marshaler = WS::Marshaling::SoapMarshaler.new(namespace)
+ marshaler = ActionWebService::Protocol::Soap::SoapMarshaler.new(namespace)
apis = {}
case dispatching_mode
when :direct
@@ -208,7 +216,7 @@ module ActionWebService # :nodoc:
xm.xsd(:schema, 'xmlns' => XsdNs, 'targetNamespace' => namespace) do
custom_types.each do |binding|
case
- when binding.is_typed_array?
+ when binding.type.array?
xm.xsd(:complexType, 'name' => binding.type_name) do
xm.xsd(:complexContent) do
xm.xsd(:restriction, 'base' => 'soapenc:Array') do
@@ -217,11 +225,11 @@ module ActionWebService # :nodoc:
end
end
end
- when binding.is_typed_struct?
+ when binding.type.structured?
xm.xsd(:complexType, 'name' => binding.type_name) do
xm.xsd(:all) do
- binding.each_member do |name, spec|
- b = marshaler.register_type(spec)
+ binding.type.each_member do |name, type|
+ b = marshaler.register_type(type)
xm.xsd(:element, 'name' => name, 'type' => b.qualified_type_name('typens'))
end
end
@@ -249,14 +257,8 @@ module ActionWebService # :nodoc:
expects = method.expects
i = 1
expects.each do |type|
- if type.is_a?(Hash)
- param_name = type.keys.shift
- type = type.values.shift
- else
- param_name = "param#{i}"
- end
binding = marshaler.register_type(type)
- xm.part('name' => param_name, 'type' => binding.qualified_type_name('typens'))
+ xm.part('name' => type.name, 'type' => binding.qualified_type_name('typens'))
i += 1
end if expects
end
@@ -340,7 +342,9 @@ module ActionWebService # :nodoc:
def register_api(api, marshaler)
bindings = {}
traverse_custom_types(api, marshaler) do |binding|
- bindings[binding] = nil unless bindings.has_key?(binding.type_class)
+ bindings[binding] = nil unless bindings.has_key?(binding)
+ element_binding = binding.element_binding
+ bindings[binding.element_binding] = nil if element_binding && !bindings.has_key?(element_binding)
end
bindings.keys
end
@@ -348,21 +352,18 @@ module ActionWebService # :nodoc:
def traverse_custom_types(api, marshaler, &block)
api.api_methods.each do |name, method|
expects, returns = method.expects, method.returns
- expects.each{|x| traverse_custom_type_spec(marshaler, x, &block)} if expects
- returns.each{|x| traverse_custom_type_spec(marshaler, x, &block)} if returns
+ expects.each{ |type| traverse_type(marshaler, type, &block) if type.custom? } if expects
+ returns.each{ |type| traverse_type(marshaler, type, &block) if type.custom? } if returns
end
end
- def traverse_custom_type_spec(marshaler, spec, &block)
- binding = marshaler.register_type(spec)
- if binding.is_typed_struct?
- binding.each_member do |name, member_spec|
- traverse_custom_type_spec(marshaler, member_spec, &block)
- end
- elsif binding.is_typed_array?
- traverse_custom_type_spec(marshaler, binding.element_binding.type_class, &block)
+ def traverse_type(marshaler, type, &block)
+ yield marshaler.register_type(type)
+ if type.array?
+ yield marshaler.register_type(type.element_type)
+ type = type.element_type
end
- yield binding
+ type.each_member{ |name, type| traverse_type(marshaler, type, &block) } if type.structured?
end
end
end
diff --git a/actionwebservice/lib/action_web_service/protocol/abstract.rb b/actionwebservice/lib/action_web_service/protocol/abstract.rb
index 0ff4feef84..70b922ce73 100644
--- a/actionwebservice/lib/action_web_service/protocol/abstract.rb
+++ b/actionwebservice/lib/action_web_service/protocol/abstract.rb
@@ -3,22 +3,11 @@ module ActionWebService # :nodoc:
class ProtocolError < ActionWebServiceError # :nodoc:
end
- class AbstractProtocol
- attr :marshaler
- attr :encoder
-
- def unmarshal_request(ap_request)
- end
-
- def marshal_response(method, return_value)
- body = method.encode_rpc_response(marshaler, encoder, return_value)
- Response.new(body, 'text/xml')
+ class AbstractProtocol # :nodoc:
+ def decode_action_pack_request(action_pack_request)
end
- def protocol_client(api, protocol_name, endpoint_uri, options)
- end
-
- def create_action_pack_request(service_name, public_method_name, raw_body, options={})
+ def encode_action_pack_request(service_name, public_method_name, raw_body, options={})
klass = options[:request_class] || SimpleActionPackRequest
request = klass.new
request.request_parameters['action'] = service_name.to_s
@@ -27,50 +16,30 @@ module ActionWebService # :nodoc:
request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
request
end
- end
- class SimpleActionPackRequest < ActionController::AbstractRequest
- def initialize
- @env = {}
- @qparams = {}
- @rparams = {}
- @cookies = {}
- reset_session
+ def decode_request(raw_request, service_name)
end
- def query_parameters
- @qparams
+ def encode_request(method_name, params, param_types)
end
- def request_parameters
- @rparams
+ def decode_response(raw_response)
end
- def env
- @env
- end
-
- def host
- ''
- end
-
- def cookies
- @cookies
+ def encode_response(method_name, return_value, return_type)
end
- def session
- @session
+ def protocol_client(api, protocol_name, endpoint_uri, options)
end
- def reset_session
- @session = {}
+ def register_api(api)
end
end
class Request # :nodoc:
attr :protocol
attr :method_name
- attr :method_params
+ attr_accessor :method_params
attr :service_name
attr_accessor :api
attr_accessor :api_method
@@ -88,10 +57,50 @@ module ActionWebService # :nodoc:
class Response # :nodoc:
attr :body
attr :content_type
+ attr :return_value
- def initialize(body, content_type)
+ def initialize(body, content_type, return_value)
@body = body
@content_type = content_type
+ @return_value = return_value
+ end
+ end
+
+ class SimpleActionPackRequest < ActionController::AbstractRequest # :nodoc:
+ def initialize
+ @env = {}
+ @qparams = {}
+ @rparams = {}
+ @cookies = {}
+ reset_session
+ end
+
+ def query_parameters
+ @qparams
+ end
+
+ def request_parameters
+ @rparams
+ end
+
+ def env
+ @env
+ end
+
+ def host
+ ''
+ end
+
+ def cookies
+ @cookies
+ end
+
+ def session
+ @session
+ end
+
+ def reset_session
+ @session = {}
end
end
end
diff --git a/actionwebservice/lib/action_web_service/protocol/discovery.rb b/actionwebservice/lib/action_web_service/protocol/discovery.rb
index 40875975bf..a911c7d017 100644
--- a/actionwebservice/lib/action_web_service/protocol/discovery.rb
+++ b/actionwebservice/lib/action_web_service/protocol/discovery.rb
@@ -14,10 +14,10 @@ module ActionWebService # :nodoc:
module InstanceMethods # :nodoc:
private
- def discover_web_service_request(ap_request)
+ def discover_web_service_request(action_pack_request)
(self.class.read_inheritable_attribute("web_service_protocols") || []).each do |protocol|
protocol = protocol.new
- request = protocol.unmarshal_request(ap_request)
+ request = protocol.decode_action_pack_request(action_pack_request)
return request unless request.nil?
end
nil
diff --git a/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb b/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
index 5e56748ae3..cc3e90a4cc 100644
--- a/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
+++ b/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
@@ -1,3 +1,5 @@
+require 'action_web_service/protocol/soap_protocol/marshaler'
+
module ActionWebService # :nodoc:
module Protocol # :nodoc:
module Soap # :nodoc:
@@ -7,28 +9,105 @@ module ActionWebService # :nodoc:
end
class SoapProtocol < AbstractProtocol # :nodoc:
- def initialize
- @encoder = WS::Encoding::SoapRpcEncoding.new 'urn:ActionWebService'
- @marshaler = WS::Marshaling::SoapMarshaler.new 'urn:ActionWebService'
+ def marshaler
+ @marshaler ||= SoapMarshaler.new
+ end
+
+ def decode_action_pack_request(action_pack_request)
+ return nil unless has_valid_soap_action?(action_pack_request)
+ service_name = action_pack_request.parameters['action']
+ decode_request(action_pack_request.raw_post, service_name)
+ end
+
+ def encode_action_pack_request(service_name, public_method_name, raw_body, options={})
+ request = super
+ request.env['HTTP_SOAPACTION'] = '/soap/%s/%s' % [service_name, public_method_name]
+ request
end
- def unmarshal_request(ap_request)
- return nil unless has_valid_soap_action?(ap_request)
- method_name, params = @encoder.decode_rpc_call(ap_request.raw_post)
- params = params.map{|x| @marshaler.unmarshal(x)}
- service_name = ap_request.parameters['action']
+ def decode_request(raw_request, service_name)
+ envelope = SOAP::Processor.unmarshal(raw_request)
+ unless envelope
+ raise ProtocolError, "Failed to parse SOAP request message"
+ end
+ request = envelope.body.request
+ method_name = request.elename.name
+ params = request.collect{ |k, v| marshaler.soap_to_ruby(request[k]) }
Request.new(self, method_name, params, service_name)
end
+ def encode_request(method_name, params, param_types)
+ param_types.each{ |type| marshaler.register_type(type) } if param_types
+ qname = XSD::QName.new(marshaler.type_namespace, method_name)
+ param_def = []
+ i = 0
+ if param_types
+ params = params.map do |param|
+ param_type = param_types[i]
+ param_def << ['in', param_type.name, marshaler.lookup_type(param_type).mapping]
+ i += 1
+ [param_type.name, marshaler.ruby_to_soap(param)]
+ end
+ else
+ params = []
+ end
+ request = SOAP::RPC::SOAPMethodRequest.new(qname, param_def)
+ request.set_param(params)
+ envelope = create_soap_envelope(request)
+ SOAP::Processor.marshal(envelope)
+ end
+
+ def decode_response(raw_response)
+ envelope = SOAP::Processor.unmarshal(raw_response)
+ unless envelope
+ raise ProtocolError, "Failed to parse SOAP request message"
+ end
+ method_name = envelope.body.request.elename.name
+ return_value = envelope.body.response
+ return_value = marshaler.soap_to_ruby(return_value) unless return_value.nil?
+ [method_name, return_value]
+ end
+
+ def encode_response(method_name, return_value, return_type)
+ if return_type
+ return_binding = marshaler.register_type(return_type)
+ marshaler.annotate_arrays(return_binding, return_value)
+ end
+ qname = XSD::QName.new(marshaler.type_namespace, method_name)
+ if return_value.nil?
+ response = SOAP::RPC::SOAPMethodResponse.new(qname, nil)
+ else
+ if return_value.is_a?(Exception)
+ detail = SOAP::Mapping::SOAPException.new(return_value)
+ response = SOAP::SOAPFault.new(
+ SOAP::SOAPQName.new('%s:%s' % [SOAP::SOAPNamespaceTag, 'Server']),
+ SOAP::SOAPString.new(return_value.to_s),
+ SOAP::SOAPString.new(self.class.name),
+ marshaler.ruby_to_soap(detail))
+ else
+ if return_type
+ param_def = [['retval', 'return', marshaler.lookup_type(return_type).mapping]]
+ response = SOAP::RPC::SOAPMethodResponse.new(qname, param_def)
+ response.retval = marshaler.ruby_to_soap(return_value)
+ else
+ response = SOAP::RPC::SOAPMethodResponse.new(qname, nil)
+ end
+ end
+ end
+ envelope = create_soap_envelope(response)
+ Response.new(SOAP::Processor.marshal(envelope), 'text/xml', return_value)
+ end
+
def protocol_client(api, protocol_name, endpoint_uri, options={})
return nil unless protocol_name == :soap
ActionWebService::Client::Soap.new(api, endpoint_uri, options)
end
- def create_action_pack_request(service_name, public_method_name, raw_body, options={})
- request = super
- request.env['HTTP_SOAPACTION'] = '/soap/%s/%s' % [service_name, public_method_name]
- request
+ def register_api(api)
+ api.api_methods.each do |name, method|
+ method.expects.each{ |type| marshaler.register_type(type) } if method.expects
+ method.returns.each{ |type| marshaler.register_type(type) } if method.returns
+ end
end
private
@@ -43,7 +122,13 @@ module ActionWebService # :nodoc:
return nil if soap_action.empty?
soap_action
end
- end
+
+ def create_soap_envelope(body)
+ header = SOAP::SOAPHeader.new
+ body = SOAP::SOAPBody.new(body)
+ SOAP::SOAPEnvelope.new(header, body)
+ end
+ end
end
end
end
diff --git a/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb b/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb
new file mode 100644
index 0000000000..5d9a80b007
--- /dev/null
+++ b/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb
@@ -0,0 +1,197 @@
+require 'soap/mapping'
+
+module ActionWebService
+ module Protocol
+ module Soap
+ class SoapMarshaler
+ attr :type_namespace
+ attr :registry
+
+ def initialize(type_namespace=nil)
+ @type_namespace = type_namespace || 'urn:ActionWebService'
+ @registry = SOAP::Mapping::Registry.new
+ @type2binding = {}
+ end
+
+ def soap_to_ruby(obj)
+ SOAP::Mapping.soap2obj(obj, @registry)
+ end
+
+ def ruby_to_soap(obj)
+ SOAP::Mapping.obj2soap(obj, @registry)
+ end
+
+ def register_type(type)
+ return @type2binding[type] if @type2binding.has_key?(type)
+
+ type_class = type.array?? type.element_type.type_class : type.type_class
+ type_type = type.array?? type.element_type : type
+ type_binding = nil
+ if (mapping = @registry.find_mapped_soap_class(type_class) rescue nil)
+ qname = mapping[2] ? mapping[2][:type] : nil
+ qname ||= soap_base_type_name(mapping[0])
+ type_binding = SoapBinding.new(self, qname, type_type, mapping)
+ else
+ qname = XSD::QName.new(@type_namespace, soap_type_name(type_class.name))
+ @registry.add(type_class,
+ SOAP::SOAPStruct,
+ typed_struct_factory(type_class),
+ { :type => qname })
+ mapping = @registry.find_mapped_soap_class(type_class)
+ type_binding = SoapBinding.new(self, qname, type_type, mapping)
+ end
+
+ array_binding = nil
+ if type.array?
+ array_mapping = @registry.find_mapped_soap_class(Array) rescue nil
+ if (array_mapping && !array_mapping[1].is_a?(SoapTypedArrayFactory)) || array_mapping.nil?
+ @registry.set(Array,
+ SOAP::SOAPArray,
+ SoapTypedArrayFactory.new)
+ array_mapping = @registry.find_mapped_soap_class(Array)
+ end
+ qname = XSD::QName.new(@type_namespace, soap_type_name(type.element_type.type_class.name) + 'Array')
+ array_binding = SoapBinding.new(self, qname, type, array_mapping, type_binding)
+ end
+
+ @type2binding[type] = array_binding ? array_binding : type_binding
+ @type2binding[type]
+ end
+ alias :lookup_type :register_type
+
+ def annotate_arrays(binding, value)
+ if binding.type.array?
+ mark_typed_array(value, binding.element_binding.qname)
+ if binding.element_binding.type.custom?
+ value.each do |element|
+ annotate_arrays(binding.element_binding, element)
+ end
+ end
+ elsif binding.type.structured?
+ binding.type.each_member do |name, type|
+ member_binding = register_type(type)
+ member_value = value.respond_to?('[]') ? value[name] : value.send(name)
+ annotate_arrays(member_binding, member_value) if type.custom?
+ end
+ end
+ end
+
+ private
+ def typed_struct_factory(type_class)
+ if Object.const_defined?('ActiveRecord')
+ if type_class.ancestors.include?(ActiveRecord::Base)
+ qname = XSD::QName.new(@type_namespace, soap_type_name(type_class.name))
+ type_class.instance_variable_set('@qname', qname)
+ return SoapActiveRecordStructFactory.new
+ end
+ end
+ SOAP::Mapping::Registry::TypedStructFactory
+ end
+
+ def mark_typed_array(array, qname)
+ (class << array; self; end).class_eval do
+ define_method(:arytype) do
+ qname
+ end
+ end
+ end
+
+ def soap_base_type_name(type)
+ xsd_type = type.ancestors.find{ |c| c.const_defined? 'Type' }
+ xsd_type ? xsd_type.const_get('Type') : XSD::XSDAnySimpleType::Type
+ end
+
+ def soap_type_name(type_name)
+ type_name.gsub(/::/, '..')
+ end
+ end
+
+ class SoapBinding
+ attr :qname
+ attr :type
+ attr :mapping
+ attr :element_binding
+
+ def initialize(marshaler, qname, type, mapping, element_binding=nil)
+ @marshaler = marshaler
+ @qname = qname
+ @type = type
+ @mapping = mapping
+ @element_binding = element_binding
+ end
+
+ def type_name
+ @type.custom? ? @qname.name : nil
+ end
+
+ def qualified_type_name(ns=nil)
+ if @type.custom?
+ "#{ns ? ns : @qname.namespace}:#{@qname.name}"
+ else
+ ns = XSD::NS.new
+ ns.assign(XSD::Namespace, SOAP::XSDNamespaceTag)
+ xsd_klass = mapping[0].ancestors.find{|c| c.const_defined?('Type')}
+ return ns.name(XSD::AnyTypeName) unless xsd_klass
+ ns.name(xsd_klass.const_get('Type'))
+ end
+ end
+
+ def eql?(other)
+ @qname == other.qname
+ end
+ alias :== :eql?
+
+ def hash
+ @qname.hash
+ end
+ end
+
+ class SoapActiveRecordStructFactory < SOAP::Mapping::Factory
+ def obj2soap(soap_class, obj, info, map)
+ unless obj.is_a?(ActiveRecord::Base)
+ return nil
+ end
+ soap_obj = soap_class.new(obj.class.instance_variable_get('@qname'))
+ obj.class.columns.each do |column|
+ key = column.name.to_s
+ value = obj.send(key)
+ soap_obj[key] = SOAP::Mapping._obj2soap(value, map)
+ end
+ soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ unless node.type == obj_class.instance_variable_get('@qname')
+ return false
+ end
+ obj = obj_class.new
+ node.each do |key, value|
+ obj[key] = value.data
+ end
+ obj.instance_variable_set('@new_record', false)
+ return true, obj
+ end
+ end
+
+ class SoapTypedArrayFactory < SOAP::Mapping::Factory
+ def obj2soap(soap_class, obj, info, map)
+ unless obj.respond_to?(:arytype)
+ return nil
+ end
+ soap_obj = soap_class.new(SOAP::ValueArrayName, 1, obj.arytype)
+ mark_marshalled_obj(obj, soap_obj)
+ obj.each do |item|
+ child = SOAP::Mapping._obj2soap(item, map)
+ soap_obj.add(child)
+ end
+ soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ return false
+ end
+ end
+
+ end
+ end
+end
diff --git a/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb b/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb
index f8ff12cfa3..de6c8c8a30 100644
--- a/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb
+++ b/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb
@@ -1,3 +1,5 @@
+require 'xmlrpc/marshal'
+
module ActionWebService # :nodoc:
module Protocol # :nodoc:
module XmlRpc # :nodoc:
@@ -6,22 +8,61 @@ module ActionWebService # :nodoc:
end
class XmlRpcProtocol < AbstractProtocol # :nodoc:
- def initialize
- @encoder = WS::Encoding::XmlRpcEncoding.new
- @marshaler = WS::Marshaling::XmlRpcMarshaler.new
+ def decode_action_pack_request(action_pack_request)
+ service_name = action_pack_request.parameters['action']
+ decode_request(action_pack_request.raw_post, service_name)
end
- def unmarshal_request(ap_request)
- method_name, params = @encoder.decode_rpc_call(ap_request.raw_post)
- params = params.map{|x| @marshaler.unmarshal(x)}
- service_name = ap_request.parameters['action']
+ def decode_request(raw_request, service_name)
+ method_name, params = XMLRPC::Marshal.load_call(raw_request)
Request.new(self, method_name, params, service_name)
end
+ def encode_request(method_name, params, param_types)
+ if param_types
+ params = params.dup
+ param_types.each_with_index{ |type, i| params[i] = value_to_xmlrpc_wire_format(params[i], type) }
+ end
+ XMLRPC::Marshal.dump_call(method_name, *params)
+ end
+
+ def decode_response(raw_response)
+ [nil, XMLRPC::Marshal.load_response(raw_response)]
+ end
+
+ def encode_response(method_name, return_value, return_type)
+ return_value = true if return_value.nil?
+ if return_type
+ return_value = value_to_xmlrpc_wire_format(return_value, return_type)
+ end
+ raw_response = XMLRPC::Marshal.dump_response(return_value)
+ Response.new(raw_response, 'text/xml', return_value)
+ end
+
def protocol_client(api, protocol_name, endpoint_uri, options={})
return nil unless protocol_name == :xmlrpc
ActionWebService::Client::XmlRpc.new(api, endpoint_uri, options)
end
+
+ def value_to_xmlrpc_wire_format(value, value_type)
+ if value_type.array?
+ value.map{ |val| value_to_xmlrpc_wire_format(val, value_type.element_type) }
+ else
+ if value.is_a?(ActionWebService::Struct)
+ struct = {}
+ value.class.members.each do |name, type|
+ struct[name.to_s] = value_to_xmlrpc_wire_format(value[name], type)
+ end
+ struct
+ elsif value.is_a?(ActiveRecord::Base)
+ value.attributes.dup
+ elsif value.is_a?(Exception) && !value.is_a?(XMLRPC::FaultException)
+ XMLRPC::FaultException.new(2, value.message)
+ else
+ value
+ end
+ end
+ end
end
end
end
diff --git a/actionwebservice/lib/action_web_service/scaffolding.rb b/actionwebservice/lib/action_web_service/scaffolding.rb
index e311515fba..0fab01eced 100644
--- a/actionwebservice/lib/action_web_service/scaffolding.rb
+++ b/actionwebservice/lib/action_web_service/scaffolding.rb
@@ -1,9 +1,13 @@
require 'ostruct'
require 'uri'
require 'benchmark'
+require 'pathname'
module ActionWebService
module Scaffolding # :nodoc:
+ class ScaffoldingError < ActionWebServiceError # :nodoc:
+ end
+
def self.append_features(base)
super
base.extend(ClassMethods)
@@ -63,17 +67,32 @@ module ActionWebService
when :xmlrpc
protocol = Protocol::XmlRpc::XmlRpcProtocol.new
end
- cgi = @request.cgi
+ cgi = @request.respond_to?(:cgi) ? @request.cgi : nil
bm = Benchmark.measure do
- @method_request_xml = @scaffold_method.encode_rpc_call(protocol.marshaler, protocol.encoder, @params['method_params'].dup)
- @request = protocol.create_action_pack_request(@scaffold_service.name, @scaffold_method.public_name, @method_request_xml)
+ protocol.register_api(@scaffold_service.api)
+ params = @params['method_params'] ? @params['method_params'].dup : nil
+ params = @scaffold_method.cast_expects(params)
+ @method_request_xml = protocol.encode_request(@scaffold_method.public_name, params, @scaffold_method.expects)
+ @request = protocol.encode_action_pack_request(@scaffold_service.name, @scaffold_method.public_name, @method_request_xml)
dispatch_web_service_request
@method_response_xml = @response.body
- @method_return_value = protocol.marshaler.unmarshal(protocol.encoder.decode_rpc_response(@method_response_xml)[1]).value
+ method_name, obj = protocol.decode_response(@method_response_xml)
+ if obj.respond_to?(:detail) && obj.detail.respond_to?(:cause) && obj.detail.cause.is_a?(Exception)
+ raise obj.detail.cause
+ elsif obj.is_a?(XMLRPC::FaultException)
+ raise obj
+ end
+ @method_return_value = @scaffold_method.cast_returns(obj)
end
@method_elapsed = bm.real
add_instance_variables_to_assigns
- @response = ::ActionController::CgiResponse.new(cgi)
+ template = @response.template
+ if cgi
+ @response = ::ActionController::CgiResponse.new(cgi)
+ else
+ @response = ::ActionController::TestResponse.new
+ end
+ @response.template = template
@performed_render = false
render_#{action_name}_scaffold 'result'
end
@@ -99,20 +118,19 @@ module ActionWebService
end
def scaffold_path(template_name)
- File.dirname(__FILE__) + "/templates/scaffolds/" + template_name + ".rhtml"
+ Pathname.new(File.dirname(__FILE__) + "/templates/scaffolds/" + template_name + ".rhtml").realpath.to_s
end
END
end
end
module Helpers # :nodoc:
- def method_parameter_input_fields(method, param_spec, i)
- klass = method.param_class(param_spec)
- unless WS::BaseTypes.base_type?(klass)
- name = method.param_name(param_spec, i)
+ def method_parameter_input_fields(method, type)
+ name = type.name.to_s
+ type_name = type.type
+ unless type_name.is_a?(Symbol)
raise "Parameter #{name}: Structured/array types not supported in scaffolding input fields yet"
end
- type_name = method.param_type(param_spec)
field_name = "method_params[]"
case type_name
when :int
@@ -168,6 +186,9 @@ module ActionWebService
@name = name.to_s
@object = real_service
@api = @object.class.web_service_api
+ if @api.nil?
+ raise ScaffoldingError, "No web service API attached to #{object.class}"
+ end
@api_methods = {}
@api_methods_full = []
@api.api_methods.each do |name, method|
diff --git a/actionwebservice/lib/action_web_service/struct.rb b/actionwebservice/lib/action_web_service/struct.rb
index d4e2ba9ce6..c5e6346bfa 100644
--- a/actionwebservice/lib/action_web_service/struct.rb
+++ b/actionwebservice/lib/action_web_service/struct.rb
@@ -33,11 +33,20 @@ module ActionWebService
send(name.to_s)
end
+ # Iterates through each member
+ def each_pair(&block)
+ self.class.members.each do |name, type|
+ yield name, type
+ end
+ end
+
class << self
# Creates a structure member with the specified +name+ and +type+. Generates
# accessor methods for reading and writing the member value.
def member(name, type)
- write_inheritable_hash("struct_members", name => WS::BaseTypes.canonical_param_type_class(type))
+ name = name.to_sym
+ type = ActionWebService::SignatureTypes.canonical_signature_entry({ name => type }, 0)
+ write_inheritable_hash("struct_members", name => type)
class_eval <<-END
def #{name}; @#{name}; end
def #{name}=(value); @#{name} = value; end
@@ -47,6 +56,10 @@ module ActionWebService
def members # :nodoc:
read_inheritable_attribute("struct_members") || {}
end
+
+ def member_type(name) # :nodoc:
+ members[name.to_sym]
+ end
end
end
end
diff --git a/actionwebservice/lib/action_web_service/support/signature_types.rb b/actionwebservice/lib/action_web_service/support/signature_types.rb
new file mode 100644
index 0000000000..5c57254bc3
--- /dev/null
+++ b/actionwebservice/lib/action_web_service/support/signature_types.rb
@@ -0,0 +1,191 @@
+module ActionWebService # :nodoc:
+ module SignatureTypes # :nodoc:
+ def canonical_signature(signature)
+ return nil if signature.nil?
+ i = -1
+ signature.map{ |spec| canonical_signature_entry(spec, i += 1) }
+ end
+
+ def canonical_signature_entry(spec, i)
+ name = "param#{i}"
+ if spec.is_a?(Hash)
+ name = spec.keys.first
+ spec = spec.values.first
+ type = spec
+ else
+ type = spec
+ end
+ if spec.is_a?(Array)
+ ArrayType.new(canonical_signature_entry(spec[0], 0), name)
+ else
+ type = canonical_type(type)
+ if type.is_a?(Symbol)
+ BaseType.new(type, name)
+ else
+ StructuredType.new(type, name)
+ end
+ end
+ end
+
+ def canonical_type(type)
+ type_name = symbol_name(type) || class_to_type_name(type)
+ type = type_name || type
+ return canonical_type_name(type) if type.is_a?(Symbol)
+ type
+ end
+
+ def canonical_type_name(name)
+ name = name.to_sym
+ case name
+ when :int, :integer, :fixnum, :bignum
+ :int
+ when :string, :base64
+ :string
+ when :bool, :boolean
+ :bool
+ when :float, :double
+ :float
+ when :time, :timestamp
+ :time
+ when :datetime
+ :datetime
+ when :date
+ :date
+ else
+ raise(TypeError, "#{name} is not a valid base type")
+ end
+ end
+
+ def canonical_type_class(type)
+ type = canonical_type(type)
+ type.is_a?(Symbol) ? type_name_to_class(type) : type
+ end
+
+ def symbol_name(name)
+ return name.to_sym if name.is_a?(Symbol) || name.is_a?(String)
+ nil
+ end
+
+ def class_to_type_name(klass)
+ klass = klass.class unless klass.is_a?(Class)
+ if derived_from?(Integer, klass) || derived_from?(Fixnum, klass) || derived_from?(Bignum, klass)
+ :int
+ elsif klass == String
+ :string
+ elsif klass == TrueClass || klass == FalseClass
+ :bool
+ elsif derived_from?(Float, klass) || derived_from?(Precision, klass) || derived_from?(Numeric, klass)
+ :float
+ elsif klass == Time
+ :time
+ elsif klass == DateTime
+ :datetime
+ elsif klass == Date
+ :date
+ else
+ nil
+ end
+ end
+
+ def type_name_to_class(name)
+ case canonical_type_name(name)
+ when :int
+ Integer
+ when :string
+ String
+ when :bool
+ TrueClass
+ when :float
+ Float
+ when :time
+ Time
+ when :date
+ Date
+ when :datetime
+ DateTime
+ else
+ nil
+ end
+ end
+
+ def derived_from?(ancestor, child)
+ child.ancestors.include?(ancestor)
+ end
+
+ module_function :type_name_to_class
+ module_function :class_to_type_name
+ module_function :symbol_name
+ module_function :canonical_type_class
+ module_function :canonical_type_name
+ module_function :canonical_type
+ module_function :canonical_signature_entry
+ module_function :canonical_signature
+ module_function :derived_from?
+ end
+
+ class BaseType # :nodoc:
+ include SignatureTypes
+
+ attr :type
+ attr :type_class
+ attr :name
+
+ def initialize(type, name)
+ @type = canonical_type(type)
+ @type_class = canonical_type_class(@type)
+ @name = name
+ end
+
+ def custom?
+ false
+ end
+
+ def array?
+ false
+ end
+
+ def structured?
+ false
+ end
+ end
+
+ class ArrayType < BaseType # :nodoc:
+ attr :element_type
+
+ def initialize(element_type, name)
+ super(Array, name)
+ @element_type = element_type
+ end
+
+ def custom?
+ true
+ end
+
+ def array?
+ true
+ end
+ end
+
+ class StructuredType < BaseType # :nodoc:
+ def each_member
+ if @type_class.respond_to?(:members)
+ @type_class.members.each do |name, type|
+ yield name, type
+ end
+ elsif @type_class.respond_to?(:columns)
+ i = 0
+ @type_class.columns.each do |column|
+ yield column.name, canonical_signature_entry(column.klass, i += 1)
+ end
+ end
+ end
+
+ def custom?
+ true
+ end
+
+ def structured?
+ true
+ end
+ end
+end
diff --git a/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml b/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml
index 0516738da6..e62d234c1a 100644
--- a/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml
+++ b/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml
@@ -5,10 +5,10 @@
<%= hidden_field_tag "method", @scaffold_method.public_name %>
<% i = 0 %>
-<% @scaffold_method.expects.each do |spec| %>
+<% @scaffold_method.expects.each do |type| %>
<p>
- <label for="method_params[]"><%= @scaffold_method.param_name(spec, i).camelize %></label><br />
- <%= method_parameter_input_fields(@scaffold_method, spec, i) %>
+ <label for="method_params[]"><%= type.name.to_s.camelize %></label><br />
+ <%= method_parameter_input_fields(@scaffold_method, type) %>
</p>
<% i += 1 %>
<% end %>
diff --git a/actionwebservice/lib/action_web_service/test_invoke.rb b/actionwebservice/lib/action_web_service/test_invoke.rb
index 5d364e4225..c22ca618dc 100644
--- a/actionwebservice/lib/action_web_service/test_invoke.rb
+++ b/actionwebservice/lib/action_web_service/test_invoke.rb
@@ -21,7 +21,7 @@ module Test # :nodoc:
# invoke the specified layered API method on the correct service
def invoke_layered(service_name, method_name, *args)
- if protocol == :soap
+ if protocol.is_a?(ActionWebService::Protocol::Soap::SoapProtocol)
raise "SOAP protocol support for :layered dispatching mode is not available"
end
prepare_request('api', service_name, method_name, *args)
@@ -37,10 +37,10 @@ module Test # :nodoc:
@request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
@request.env['RAW_POST_DATA'] = encode_rpc_call(service_name, api_method_name, *args)
case protocol
- when :soap
+ when ActionWebService::Protocol::Soap::SoapProtocol
soap_action = "/#{@controller.controller_name}/#{service_name}/#{public_method_name(service_name, api_method_name)}"
@request.env['HTTP_SOAPACTION'] = soap_action
- when :xmlrpc
+ when ActionWebService::Protocol::XmlRpc::XmlRpcProtocol
@request.env.delete('HTTP_SOAPACTION')
end
end
@@ -52,19 +52,18 @@ module Test # :nodoc:
when :delegated, :layered
api = @controller.web_service_object(service_name.to_sym).class.web_service_api
end
+ protocol.register_api(api)
method = api.api_methods[api_method_name.to_sym]
- method.register_types(marshaler)
- method.encode_rpc_call(marshaler, encoder, args.dup, :method_name => public_method_name(service_name, api_method_name))
+ protocol.encode_request(public_method_name(service_name, api_method_name), args.dup, method.expects)
end
def decode_rpc_response
- public_method_name, return_value = encoder.decode_rpc_response(@response.body)
- result = marshaler.unmarshal(return_value).value
+ public_method_name, return_value = protocol.decode_response(@response.body)
unless @return_exceptions
- exception = is_exception?(result)
+ exception = is_exception?(return_value)
raise exception if exception
end
- result
+ return_value
end
def public_method_name(service_name, api_method_name)
@@ -86,25 +85,7 @@ module Test # :nodoc:
end
def protocol
- @protocol ||= :soap
- end
-
- def marshaler
- case protocol
- when :soap
- @soap_marshaler ||= WS::Marshaling::SoapMarshaler.new 'urn:ActionWebService'
- when :xmlrpc
- @xmlrpc_marshaler ||= WS::Marshaling::XmlRpcMarshaler.new
- end
- end
-
- def encoder
- case protocol
- when :soap
- @soap_encoder ||= WS::Encoding::SoapRpcEncoding.new 'urn:ActionWebService'
- when :xmlrpc
- @xmlrpc_encoder ||= WS::Encoding::XmlRpcEncoding.new
- end
+ @protocol ||= ActionWebService::Protocol::Soap::SoapProtocol.new
end
def is_exception?(obj)
diff --git a/actionwebservice/lib/action_web_service/vendor/ws.rb b/actionwebservice/lib/action_web_service/vendor/ws.rb
deleted file mode 100644
index 18a32a555e..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'ws/common'
-require 'ws/types'
-require 'ws/marshaling'
-require 'ws/encoding'
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/common.rb b/actionwebservice/lib/action_web_service/vendor/ws/common.rb
deleted file mode 100644
index 4266a7141d..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/common.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-module WS
- class WSError < StandardError
- end
-
- def self.derived_from?(ancestor, child)
- child.ancestors.include?(ancestor)
- end
-end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/encoding.rb b/actionwebservice/lib/action_web_service/vendor/ws/encoding.rb
deleted file mode 100644
index 790317639b..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/encoding.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-require 'ws/encoding/abstract'
-require 'ws/encoding/soap_rpc_encoding'
-require 'ws/encoding/xmlrpc_encoding'
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/encoding/abstract.rb b/actionwebservice/lib/action_web_service/vendor/ws/encoding/abstract.rb
deleted file mode 100644
index 257c7d0993..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/encoding/abstract.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-module WS
- module Encoding
- # Encoders operate on _foreign_ objects. That is, Ruby object
- # instances that are the _marshaling format specific_ representation
- # of objects. In other words, objects that have not yet been marshaled, but
- # are in protocol-specific form (such as an AST or DOM element), and not
- # native Ruby form.
- class AbstractEncoding
- def encode_rpc_call(method_name, params)
- raise NotImplementedError
- end
-
- def decode_rpc_call(obj)
- raise NotImplementedError
- end
-
- def encode_rpc_response(method_name, return_value)
- raise NotImplementedError
- end
-
- def decode_rpc_response(obj)
- raise NotImplementedError
- end
- end
- end
-end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb b/actionwebservice/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb
deleted file mode 100644
index f4d2f5a7d6..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb
+++ /dev/null
@@ -1,90 +0,0 @@
-require 'soap/processor'
-require 'soap/mapping'
-require 'soap/rpc/element'
-
-module WS
- module Encoding
- class SoapRpcError < WSError
- end
-
- class SoapRpcEncoding < AbstractEncoding
- attr_accessor :method_namespace
-
- def initialize(method_namespace='')
- @method_namespace = method_namespace
- end
-
- def encode_rpc_call(method_name, foreign_params)
- qname = create_method_qname(method_name)
- param_def = []
- params = foreign_params.map do |p|
- param_def << ['in', p.param.info.name, p.param.info.data.mapping]
- [p.param.info.name, p.soap_object]
- end
- request = SOAP::RPC::SOAPMethodRequest.new(qname, param_def)
- request.set_param(params)
- envelope = create_soap_envelope(request)
- SOAP::Processor.marshal(envelope)
- end
-
- def decode_rpc_call(obj)
- envelope = SOAP::Processor.unmarshal(obj)
- unless envelope
- raise(SoapRpcError, "Malformed SOAP request")
- end
- request = envelope.body.request
- method_name = request.elename.name
- params = request.collect do |key, value|
- info = ParamInfo.new(key, nil, nil)
- param = Param.new(nil, info)
- Marshaling::SoapForeignObject.new(param, request[key])
- end
- [method_name, params]
- end
-
- def encode_rpc_response(method_name, return_value)
- response = nil
- qname = create_method_qname(method_name)
- if return_value.nil?
- response = SOAP::RPC::SOAPMethodResponse.new(qname, nil)
- else
- param = return_value.param
- soap_object = return_value.soap_object
- param_def = [['retval', 'return', param.info.data.mapping]]
- if soap_object.is_a?(SOAP::SOAPFault)
- response = soap_object
- else
- response = SOAP::RPC::SOAPMethodResponse.new(qname, param_def)
- response.retval = soap_object
- end
- end
- envelope = create_soap_envelope(response)
- SOAP::Processor.marshal(envelope)
- end
-
- def decode_rpc_response(obj)
- envelope = SOAP::Processor.unmarshal(obj)
- unless envelope
- raise(SoapRpcError, "Malformed SOAP response")
- end
- method_name = envelope.body.request.elename.name
- return_value = envelope.body.response
- info = ParamInfo.new('return', nil, nil)
- param = Param.new(nil, info)
- return_value = Marshaling::SoapForeignObject.new(param, return_value)
- [method_name, return_value]
- end
-
- private
- def create_soap_envelope(body)
- header = SOAP::SOAPHeader.new
- body = SOAP::SOAPBody.new(body)
- SOAP::SOAPEnvelope.new(header, body)
- end
-
- def create_method_qname(method_name)
- XSD::QName.new(@method_namespace, method_name)
- end
- end
- end
-end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb b/actionwebservice/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb
deleted file mode 100644
index 4876c08705..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-require 'xmlrpc/marshal'
-
-module WS
- module Encoding
- class XmlRpcEncoding < AbstractEncoding
- def encode_rpc_call(method_name, params)
- XMLRPC::Marshal.dump_call(method_name, *params)
- end
-
- def decode_rpc_call(obj)
- method_name, params = XMLRPC::Marshal.load_call(obj)
- i = 0
- params = params.map do |value|
- param = XmlRpcDecodedParam.new("param#{i}", value)
- i += 1
- param
- end
- [method_name, params]
- end
-
- def encode_rpc_response(method_name, return_value)
- if return_value.nil?
- XMLRPC::Marshal.dump_response(true)
- else
- XMLRPC::Marshal.dump_response(return_value)
- end
- end
-
- def decode_rpc_response(obj)
- return_value = XMLRPC::Marshal.load_response(obj)
- [nil, XmlRpcDecodedParam.new('return', return_value)]
- end
- end
-
- class XmlRpcDecodedParam
- attr :param
-
- def initialize(name, value)
- info = ParamInfo.new(name, value.class)
- @param = Param.new(value, info)
- end
- end
- end
-end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/marshaling.rb b/actionwebservice/lib/action_web_service/vendor/ws/marshaling.rb
deleted file mode 100644
index 3a0a2e8cc1..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/marshaling.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-require 'ws/marshaling/abstract'
-require 'ws/marshaling/soap_marshaling'
-require 'ws/marshaling/xmlrpc_marshaling'
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/abstract.rb b/actionwebservice/lib/action_web_service/vendor/ws/marshaling/abstract.rb
deleted file mode 100644
index e897f62297..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/abstract.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-module WS
- module Marshaling
- class AbstractMarshaler
- def initialize
- @base_type_caster = BaseTypeCaster.new
- end
-
- def marshal(param)
- raise NotImplementedError
- end
-
- def unmarshal(param)
- raise NotImplementedError
- end
-
- def register_type(type)
- nil
- end
- alias :lookup_type :register_type
-
- def cast_inbound_recursive(value, spec)
- raise NotImplementedError
- end
-
- def cast_outbound_recursive(value, spec)
- raise NotImplementedError
- end
-
- attr :base_type_caster
- protected :base_type_caster
- end
- end
-end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb b/actionwebservice/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb
deleted file mode 100644
index 14c8d8401d..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb
+++ /dev/null
@@ -1,283 +0,0 @@
-require 'soap/mapping'
-require 'xsd/ns'
-
-module WS
- module Marshaling
- SoapEncodingNS = 'http://schemas.xmlsoap.org/soap/encoding/'
-
- class SoapError < WSError
- end
-
- class SoapMarshaler < AbstractMarshaler
- attr :registry
- attr_accessor :type_namespace
-
- def initialize(type_namespace='')
- super()
- @type_namespace = type_namespace
- @registry = SOAP::Mapping::Registry.new
- @spec2binding = {}
- end
-
- def marshal(param)
- annotate_arrays(param.info.data, param.value)
- if param.value.is_a?(Exception)
- detail = SOAP::Mapping::SOAPException.new(param.value)
- soap_obj = SOAP::SOAPFault.new(
- SOAP::SOAPQName.new('%s:%s' % [SOAP::SOAPNamespaceTag, 'Server']),
- SOAP::SOAPString.new(param.value.to_s),
- SOAP::SOAPString.new(self.class.name),
- SOAP::Mapping.obj2soap(detail))
- else
- soap_obj = SOAP::Mapping.obj2soap(param.value, @registry)
- end
- SoapForeignObject.new(param, soap_obj)
- end
-
- def unmarshal(obj)
- param = obj.param
- soap_object = obj.soap_object
- soap_type = soap_object ? soap_object.type : nil
- value = soap_object ? SOAP::Mapping.soap2obj(soap_object, @registry) : nil
- param.value = value
- param.info.type = value.class
- mapping = @registry.find_mapped_soap_class(param.info.type) rescue nil
- if soap_type && soap_type.name == 'Array' && soap_type.namespace == SoapEncodingNS
- param.info.data = SoapBinding.new(self, soap_object.arytype, Array, mapping)
- else
- param.info.data = SoapBinding.new(self, soap_type, value.class, mapping)
- end
- param
- end
-
- def register_type(spec)
- if @spec2binding.has_key?(spec)
- return @spec2binding[spec]
- end
-
- klass = BaseTypes.canonical_param_type_class(spec)
- if klass.is_a?(Array)
- type_class = klass[0]
- else
- type_class = klass
- end
-
- type_binding = nil
- if (mapping = @registry.find_mapped_soap_class(type_class) rescue nil)
- qname = mapping[2] ? mapping[2][:type] : nil
- qname ||= soap_base_type_name(mapping[0])
- type_binding = SoapBinding.new(self, qname, type_class, mapping)
- else
- qname = XSD::QName.new(@type_namespace, soap_type_name(type_class.name))
- @registry.add(type_class,
- SOAP::SOAPStruct,
- typed_struct_factory(type_class),
- { :type => qname })
- mapping = @registry.find_mapped_soap_class(type_class)
- type_binding = SoapBinding.new(self, qname, type_class, mapping)
- end
-
- array_binding = nil
- if klass.is_a?(Array)
- array_mapping = @registry.find_mapped_soap_class(Array) rescue nil
- if (array_mapping && !array_mapping[1].is_a?(SoapTypedArrayFactory)) || array_mapping.nil?
- @registry.set(Array,
- SOAP::SOAPArray,
- SoapTypedArrayFactory.new)
- array_mapping = @registry.find_mapped_soap_class(Array)
- end
- qname = XSD::QName.new(@type_namespace, soap_type_name(type_class.name) + 'Array')
- array_binding = SoapBinding.new(self, qname, Array, array_mapping, type_binding)
- end
-
- @spec2binding[spec] = array_binding ? array_binding : type_binding
- @spec2binding[spec]
- end
- alias :lookup_type :register_type
-
- def cast_inbound_recursive(value, spec)
- binding = lookup_type(spec)
- if binding.is_custom_type?
- value
- else
- base_type_caster.cast(value, binding.type_class)
- end
- end
-
- def cast_outbound_recursive(value, spec)
- binding = lookup_type(spec)
- if binding.is_custom_type?
- value
- else
- base_type_caster.cast(value, binding.type_class)
- end
- end
-
- protected
- def annotate_arrays(binding, value)
- if binding.is_typed_array?
- mark_typed_array(value, binding.element_binding.qname)
- if binding.element_binding.is_custom_type?
- value.each do |element|
- annotate_arrays(register_type(element.class), element)
- end
- end
- elsif binding.is_typed_struct?
- if binding.type_class.respond_to?(:members)
- binding.type_class.members.each do |name, spec|
- member_binding = register_type(spec)
- member_value = value.respond_to?('[]') ? value[name] : value.send(name)
- if member_binding.is_custom_type?
- annotate_arrays(member_binding, member_value)
- end
- end
- end
- end
- end
-
- def mark_typed_array(array, qname)
- (class << array; self; end).class_eval do
- define_method(:arytype) do
- qname
- end
- end
- end
-
- def typed_struct_factory(type_class)
- if Object.const_defined?('ActiveRecord')
- if WS.derived_from?(ActiveRecord::Base, type_class)
- qname = XSD::QName.new(@type_namespace, soap_type_name(type_class.name))
- type_class.instance_variable_set('@qname', qname)
- return SoapActiveRecordStructFactory.new
- end
- end
- SOAP::Mapping::Registry::TypedStructFactory
- end
-
- def soap_type_name(type_name)
- type_name.gsub(/::/, '..')
- end
-
- def soap_base_type_name(type)
- xsd_type = type.ancestors.find{|c| c.const_defined? 'Type'}
- xsd_type ? xsd_type.const_get('Type') : XSD::XSDAnySimpleType::Type
- end
- end
-
- class SoapForeignObject
- attr_accessor :param
- attr_accessor :soap_object
-
- def initialize(param, soap_object)
- @param = param
- @soap_object = soap_object
- end
- end
-
- class SoapBinding
- attr :qname
- attr :type_class
- attr :mapping
- attr :element_binding
-
- def initialize(marshaler, qname, type_class, mapping, element_binding=nil)
- @marshaler = marshaler
- @qname = qname
- @type_class = type_class
- @mapping = mapping
- @element_binding = element_binding
- end
-
- def is_custom_type?
- is_typed_array? || is_typed_struct?
- end
-
- def is_typed_array?
- @mapping[1].is_a?(WS::Marshaling::SoapTypedArrayFactory)
- end
-
- def is_typed_struct?
- @mapping[1] == SOAP::Mapping::Registry::TypedStructFactory || \
- @mapping[1].is_a?(WS::Marshaling::SoapActiveRecordStructFactory)
- end
-
- def each_member(&block)
- if is_typed_struct?
- if @mapping[1] == SOAP::Mapping::Registry::TypedStructFactory
- if @type_class.respond_to?(:members)
- @type_class.members.each do |name, spec|
- yield name, spec
- end
- end
- elsif @mapping[1].is_a?(WS::Marshaling::SoapActiveRecordStructFactory)
- @type_class.columns.each do |column|
- yield column.name, column.klass
- end
- end
- end
- end
-
- def type_name
- is_custom_type? ? @qname.name : nil
- end
-
- def qualified_type_name(ns=nil)
- if is_custom_type?
- "#{ns ? ns : @qname.namespace}:#{@qname.name}"
- else
- ns = XSD::NS.new
- ns.assign(XSD::Namespace, SOAP::XSDNamespaceTag)
- xsd_klass = mapping[0].ancestors.find{|c| c.const_defined?('Type')}
- return ns.name(XSD::AnyTypeName) unless xsd_klass
- ns.name(xsd_klass.const_get('Type'))
- end
- end
- end
-
- class SoapActiveRecordStructFactory < SOAP::Mapping::Factory
- def obj2soap(soap_class, obj, info, map)
- unless obj.is_a?(ActiveRecord::Base)
- return nil
- end
- soap_obj = soap_class.new(obj.class.instance_variable_get('@qname'))
- obj.class.columns.each do |column|
- key = column.name.to_s
- value = obj.send(key)
- soap_obj[key] = SOAP::Mapping._obj2soap(value, map)
- end
- soap_obj
- end
-
- def soap2obj(obj_class, node, info, map)
- unless node.type == obj_class.instance_variable_get('@qname')
- return false
- end
- obj = obj_class.new
- node.each do |key, value|
- obj[key] = value.data
- end
- obj.instance_variable_set('@new_record', false)
- return true, obj
- end
- end
-
- class SoapTypedArrayFactory < SOAP::Mapping::Factory
- def obj2soap(soap_class, obj, info, map)
- unless obj.respond_to?(:arytype)
- return nil
- end
- soap_obj = soap_class.new(SOAP::ValueArrayName, 1, obj.arytype)
- mark_marshalled_obj(obj, soap_obj)
- obj.each do |item|
- child = SOAP::Mapping._obj2soap(item, map)
- soap_obj.add(child)
- end
- soap_obj
- end
-
- def soap2obj(obj_class, node, info, map)
- return false
- end
- end
- end
-end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb b/actionwebservice/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb
deleted file mode 100644
index 56cc7597fb..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb
+++ /dev/null
@@ -1,143 +0,0 @@
-module WS
- module Marshaling
- class XmlRpcError < WSError
- end
-
- class XmlRpcMarshaler < AbstractMarshaler
- def initialize
- super()
- @spec2binding = {}
- end
-
- def marshal(param)
- value = param.value
- cast_outbound_recursive(param.value, spec_for(param)) rescue value
- end
-
- def unmarshal(obj)
- obj.param
- end
-
- def typed_unmarshal(obj, spec)
- obj.param.info.data = lookup_type(spec)
- value = obj.param.value
- obj.param.value = cast_inbound_recursive(value, spec) rescue value
- obj.param
- end
-
- def register_type(spec)
- if @spec2binding.has_key?(spec)
- return @spec2binding[spec]
- end
-
- klass = BaseTypes.canonical_param_type_class(spec)
- type_binding = nil
- if klass.is_a?(Array)
- type_binding = XmlRpcArrayBinding.new(klass[0])
- else
- type_binding = XmlRpcBinding.new(klass)
- end
-
- @spec2binding[spec] = type_binding
- end
- alias :lookup_type :register_type
-
- def cast_inbound_recursive(value, spec)
- binding = lookup_type(spec)
- case binding
- when XmlRpcArrayBinding
- value.map{ |x| cast_inbound(x, binding.element_klass) }
- when XmlRpcBinding
- cast_inbound(value, binding.klass)
- end
- end
-
- def cast_outbound_recursive(value, spec)
- binding = lookup_type(spec)
- case binding
- when XmlRpcArrayBinding
- value.map{ |x| cast_outbound(x, binding.element_klass) }
- when XmlRpcBinding
- cast_outbound(value, binding.klass)
- end
- end
-
- private
- def spec_for(param)
- binding = param.info.data
- binding.is_a?(XmlRpcArrayBinding) ? [binding.element_klass] : binding.klass
- end
-
- def cast_inbound(value, klass)
- if BaseTypes.base_type?(klass)
- value = value.to_time if value.is_a?(XMLRPC::DateTime)
- base_type_caster.cast(value, klass)
- elsif value.is_a?(XMLRPC::FaultException)
- value
- elsif klass.ancestors.include?(ActionWebService::Struct)
- obj = klass.new
- klass.members.each do |name, klass|
- name = name.to_s
- obj.send('%s=' % name, cast_inbound_recursive(value[name], klass))
- end
- obj
- else
- obj = klass.new
- if obj.respond_to?(:update)
- obj.update(value)
- else
- value.each do |name, val|
- obj.send('%s=' % name.to_s, val)
- end
- end
- obj
- end
- end
-
- def cast_outbound(value, klass)
- if BaseTypes.base_type?(klass)
- base_type_caster.cast(value, klass)
- elsif value.is_a?(Exception)
- XMLRPC::FaultException.new(2, value.message)
- elsif Object.const_defined?('ActiveRecord') && value.is_a?(ActiveRecord::Base)
- value.attributes
- elsif value.is_a?(ActionWebService::Struct)
- struct = {}
- value.class.members.each do |name, klass|
- name = name.to_s
- struct[name] = cast_outbound_recursive(value[name], klass)
- end
- struct
- else
- struct = {}
- if value.respond_to?(:each_pair)
- value.each_pair{ |key, value| struct[key] = value }
- else
- value.instance_variables.each do |name|
- key = name.sub(/^@/, '')
- struct[key] = value.instance_variable_get(name)
- end
- end
- struct
- end
- end
- end
-
- class XmlRpcBinding
- attr :klass
-
- def initialize(klass)
- @klass = klass
- end
- end
-
- class XmlRpcArrayBinding < XmlRpcBinding
- attr :element_klass
-
- def initialize(element_klass)
- super(Array)
- @element_klass = element_klass
- end
- end
- end
-end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/types.rb b/actionwebservice/lib/action_web_service/vendor/ws/types.rb
deleted file mode 100644
index 88098b5bce..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/types.rb
+++ /dev/null
@@ -1,165 +0,0 @@
-require 'time'
-require 'date'
-
-module WS
- module BaseTypes
- class << self
- def type_name_to_class(name)
- case canonical_type_name(name)
- when :int
- Integer
- when :string
- String
- when :bool
- TrueClass
- when :float
- Float
- when :time
- Time
- when :date
- Date
- end
- end
-
- def class_to_type_name(klass)
- if WS.derived_from?(Integer, klass) || WS.derived_from?(Fixnum, klass) || WS.derived_from?(Bignum, klass)
- :int
- elsif klass == String
- :string
- elsif klass == TrueClass || klass == FalseClass
- :bool
- elsif WS.derived_from?(Float, klass) || WS.derived_from?(Precision, klass) || WS.derived_from?(Numeric, klass)
- :float
- elsif klass == Time || klass == DateTime
- :time
- elsif klass == Date
- :date
- else
- raise(TypeError, "#{klass} is not a valid base type")
- end
- end
-
- def base_type?(klass)
- !(canonical_type_class(klass) rescue nil).nil?
- end
-
- def canonical_type_class(klass)
- type_name_to_class(class_to_type_name(klass))
- end
-
- def canonical_param_type_class(spec)
- klass = spec.is_a?(Hash) ? spec.values[0] : spec
- array_element_class = klass.is_a?(Array) ? klass[0] : nil
- klass = array_element_class ? array_element_class : klass
- klass = type_name_to_class(klass) if klass.is_a?(Symbol) || klass.is_a?(String)
- base_class = canonical_type_class(klass) rescue nil
- klass = base_class unless base_class.nil?
- array_element_class ? [klass] : klass
- end
-
- def canonical_param_type_spec(spec)
- klass = canonical_param_type_class(spec)
- spec.is_a?(Hash) ? {spec.keys[0]=>klass} : klass
- end
-
- def canonical_type_name(name)
- name = name.to_sym
- case name
- when :int, :integer, :fixnum, :bignum
- :int
- when :string, :base64
- :string
- when :bool, :boolean
- :bool
- when :float, :double
- :float
- when :time, :datetime, :timestamp
- :time
- when :date
- :date
- else
- raise(TypeError, "#{name} is not a valid base type")
- end
- end
- end
- end
-
- class Param
- attr_accessor :value
- attr_accessor :info
-
- def initialize(value, info)
- @value = value
- @info = info
- end
- end
-
- class ParamInfo
- attr_accessor :name
- attr_accessor :type
- attr_accessor :data
-
- def initialize(name, type, data=nil)
- @name = name
- @type = type
- @data = data
- end
-
- def self.create(spec, data, index=nil)
- name = spec.is_a?(Hash) ? spec.keys[0].to_s : (index ? "param#{index}" : nil)
- type = BaseTypes.canonical_param_type_class(spec)
- ParamInfo.new(name, type, data)
- end
- end
-
- class BaseTypeCaster
- def initialize
- @handlers = {}
- install_handlers
- end
-
- def cast(value, klass)
- type_class = BaseTypes.canonical_type_class(klass)
- return value unless type_class
- @handlers[type_class].call(value, type_class)
- end
-
- protected
- def install_handlers
- handler = method(:cast_base_type)
- [:int, :string, :bool, :float, :time, :date].each do |name|
- type = BaseTypes.type_name_to_class(name)
- @handlers[type] = handler
- end
- @handlers[Fixnum] = handler
- end
-
- def cast_base_type(value, type_class)
- desired_class = BaseTypes.canonical_type_class(type_class)
- value_class = BaseTypes.canonical_type_class(value.class)
- return value if desired_class == value_class
- desired_name = BaseTypes.class_to_type_name(desired_class)
- case desired_name
- when :int
- Integer(value)
- when :string
- value.to_s
- when :bool
- return false if value.nil?
- int_value = Integer(value) rescue nil
- return true if int_value == 1
- return false if int_value == 0
- value = value.to_s
- return true if value == 'true'
- return false if value == 'false'
- raise(TypeError, "can't convert #{value} to boolean")
- when :float
- Float(value)
- when :time
- Time.parse(value.to_s)
- when :date
- Date.parse(value.to_s)
- end
- end
- end
-end
diff --git a/actionwebservice/test/abstract_dispatcher.rb b/actionwebservice/test/abstract_dispatcher.rb
index 53be05f9f2..4784180518 100644
--- a/actionwebservice/test/abstract_dispatcher.rb
+++ b/actionwebservice/test/abstract_dispatcher.rb
@@ -1,4 +1,5 @@
require File.dirname(__FILE__) + '/abstract_unit'
+require 'stringio'
class ActionController::Base; def rescue_action(e) raise e end; end
@@ -50,8 +51,9 @@ module DispatcherTest
api_method :before_filtered
api_method :after_filtered, :returns => [[:int]]
api_method :struct_return, :returns => [[Node]]
- api_method :struct_pass, :expects => [Person]
+ api_method :struct_pass, :expects => [{:person => Person}]
api_method :base_struct_return, :returns => [[Person]]
+ api_method :hash_struct_return, :returns => [[Person]]
api_method :thrower
api_method :void
end
@@ -202,6 +204,12 @@ module DispatcherTest
p2 = Person.new('id' => 2, 'name' => 'person2')
[p1, p2]
end
+
+ def hash_struct_return
+ p1 = { :id => '1', 'name' => 'test' }
+ p2 = { 'id' => '2', :name => 'person2' }
+ [p1, p2]
+ end
def void
@void_called = @method_params
@@ -234,22 +242,11 @@ module DispatcherCommonTests
assert_equal(50, do_method_call(@direct_controller, 'Add2', 25, 25))
assert_equal(50, @direct_controller.added2)
assert(@direct_controller.void_called == false)
- case @encoder
- when WS::Encoding::SoapRpcEncoding
- assert(do_method_call(@direct_controller, 'Void', 3, 4, 5).nil?)
- when WS::Encoding::XmlRpcEncoding
- assert(do_method_call(@direct_controller, 'Void', 3, 4, 5) == true)
- end
+ assert(do_method_call(@direct_controller, 'Void', 3, 4, 5).nil?)
assert(@direct_controller.void_called == [])
result = do_method_call(@direct_controller, 'BaseStructReturn')
- case @encoder
- when WS::Encoding::SoapRpcEncoding
- assert(result[0].is_a?(DispatcherTest::Person))
- assert(result[1].is_a?(DispatcherTest::Person))
- when WS::Encoding::XmlRpcEncoding
- assert(result[0].is_a?(Hash))
- assert(result[1].is_a?(Hash))
- end
+ assert(result[0].is_a?(DispatcherTest::Person))
+ assert(result[1].is_a?(DispatcherTest::Person))
end
def test_direct_entrypoint
@@ -288,12 +285,7 @@ module DispatcherCommonTests
assert(is_exception?(result))
assert_match(/NonExistentMethod/, exception_message(result))
assert(service.void_called == false)
- case @encoder
- when WS::Encoding::SoapRpcEncoding
- assert(do_method_call(@delegated_controller, 'Void', 3, 4, 5).nil?)
- when WS::Encoding::XmlRpcEncoding
- assert(do_method_call(@delegated_controller, 'Void', 3, 4, 5) == true)
- end
+ assert(do_method_call(@delegated_controller, 'Void', 3, 4, 5).nil?)
assert(service.void_called == [])
end
@@ -302,7 +294,7 @@ module DispatcherCommonTests
controller.class.web_service_exception_reporting = true
send_garbage_request = lambda do
service_name = service_name(controller)
- request = @protocol.create_action_pack_request(service_name, 'broken, method, name!', 'broken request body', :request_class => ActionController::TestRequest)
+ request = @protocol.encode_action_pack_request(service_name, 'broken, method, name!', 'broken request body', :request_class => ActionController::TestRequest)
response = ActionController::TestResponse.new
controller.process(request, response)
# puts response.body
@@ -327,18 +319,10 @@ module DispatcherCommonTests
def test_ar_struct_return
[@direct_controller, @delegated_controller].each do |controller|
result = do_method_call(controller, 'StructReturn')
- case @encoder
- when WS::Encoding::SoapRpcEncoding
- assert(result[0].is_a?(DispatcherTest::Node))
- assert(result[1].is_a?(DispatcherTest::Node))
- assert_equal('node1', result[0].name)
- assert_equal('node2', result[1].name)
- when WS::Encoding::XmlRpcEncoding
- assert(result[0].is_a?(Hash))
- assert(result[1].is_a?(Hash))
- assert_equal('node1', result[0]['name'])
- assert_equal('node2', result[1]['name'])
- end
+ assert(result[0].is_a?(DispatcherTest::Node))
+ assert(result[1].is_a?(DispatcherTest::Node))
+ assert_equal('node1', result[0].name)
+ assert_equal('node2', result[1].name)
end
end
@@ -351,15 +335,26 @@ module DispatcherCommonTests
assert_equal person, @direct_controller.struct_pass_value
assert !person.equal?(@direct_controller.struct_pass_value)
result = do_method_call(@direct_controller, 'StructPass', {'id' => '1', 'name' => 'test'})
- case @encoder
- when WS::Encoding::SoapRpcEncoding
- # We don't cast complex types for SOAP. SOAP clients should have used the WSDL to
- # send the correct types.
- assert_equal({'id' => '1', 'name' => 'test'}, @direct_controller.struct_pass_value)
- when WS::Encoding::XmlRpcEncoding
+ case @protocol
+ when ActionWebService::Protocol::Soap::SoapProtocol
+ assert_equal(person, @direct_controller.struct_pass_value)
+ assert !person.equal?(@direct_controller.struct_pass_value)
+ when ActionWebService::Protocol::XmlRpc::XmlRpcProtocol
assert_equal(person, @direct_controller.struct_pass_value)
assert !person.equal?(@direct_controller.struct_pass_value)
end
+ assert_equal person, do_method_call(@direct_controller, 'HashStructReturn')[0]
+ end
+
+ def test_logging
+ buf = ""
+ ActionController::Base.logger = Logger.new(StringIO.new(buf))
+ test_casting
+ test_garbage_request
+ test_exception_marshaling
+ ActionController::Base.logger = nil
+ assert_match /Web Service Response/, buf
+ assert_match /Web Service Request/, buf
end
protected
@@ -392,20 +387,27 @@ module DispatcherCommonTests
api = container.web_service_object(service_name.to_sym).class.web_service_api
service_name = self.service_name(container)
end
+ @protocol.register_api(api)
method = api.public_api_method_instance(public_method_name)
- method ||= api.dummy_public_api_method_instance(public_method_name)
- # we turn off strict so we can test our own handling of incorrectly typed parameters
- body = method.encode_rpc_call(@marshaler, @encoder, params.dup, :strict => false)
+ virtual = false
+ unless method
+ virtual = true
+ method ||= ActionWebService::API::Method.new(public_method_name.underscore.to_sym, public_method_name, nil, nil)
+ end
+ body = @protocol.encode_request(public_method_name, params.dup, method.expects)
# puts body
- ap_request = protocol.create_action_pack_request(service_name, public_method_name, body, :request_class => ActionController::TestRequest)
+ ap_request = @protocol.encode_action_pack_request(service_name, public_method_name, body, :request_class => ActionController::TestRequest)
ap_response = ActionController::TestResponse.new
container.process(ap_request, ap_response)
# puts ap_response.body
- public_method_name, return_value = @encoder.decode_rpc_response(ap_response.body)
- if @encoder.is_a?(WS::Encoding::SoapRpcEncoding)
+ public_method_name, return_value = @protocol.decode_response(ap_response.body)
+ unless is_exception?(return_value) || virtual
+ return_value = method.cast_returns(return_value)
+ end
+ if @protocol.is_a?(ActionWebService::Protocol::Soap::SoapProtocol)
# http://dev.rubyonrails.com/changeset/920
assert_match(/Response$/, public_method_name) unless public_method_name == "fault"
end
- @marshaler.unmarshal(return_value).value
+ return_value
end
end
diff --git a/actionwebservice/test/abstract_unit.rb b/actionwebservice/test/abstract_unit.rb
index e8304e3790..cbeda66e90 100644
--- a/actionwebservice/test/abstract_unit.rb
+++ b/actionwebservice/test/abstract_unit.rb
@@ -1,5 +1,5 @@
+ENV["RAILS_ENV"] = "test"
$:.unshift(File.dirname(__FILE__) + '/../lib')
-$:.unshift(File.dirname(__FILE__) + '/../lib/action_web_service/vendor')
require 'test/unit'
require 'action_web_service'
diff --git a/actionwebservice/test/api_test.rb b/actionwebservice/test/api_test.rb
index 4a61ae8de7..f6d73866b7 100644
--- a/actionwebservice/test/api_test.rb
+++ b/actionwebservice/test/api_test.rb
@@ -37,17 +37,17 @@ class TC_API < Test::Unit::TestCase
def test_signature_canonicalization
assert_equal(nil, API.api_methods[:void].expects)
assert_equal(nil, API.api_methods[:void].returns)
- assert_equal([String], API.api_methods[:expects_and_returns].expects)
- assert_equal([String], API.api_methods[:expects_and_returns].returns)
- assert_equal([Integer, TrueClass], API.api_methods[:expects].expects)
+ assert_equal([String], API.api_methods[:expects_and_returns].expects.map{|x| x.type_class})
+ assert_equal([String], API.api_methods[:expects_and_returns].returns.map{|x| x.type_class})
+ assert_equal([Integer, TrueClass], API.api_methods[:expects].expects.map{|x| x.type_class})
assert_equal(nil, API.api_methods[:expects].returns)
assert_equal(nil, API.api_methods[:returns].expects)
- assert_equal([Integer, [String]], API.api_methods[:returns].returns)
- assert_equal([{:appkey=>Integer}, {:publish=>TrueClass}], API.api_methods[:named_signature].expects)
+ assert_equal([Integer, [String]], API.api_methods[:returns].returns.map{|x| x.array?? [x.element_type.type_class] : x.type_class})
+ assert_equal([[:appkey, Integer], [:publish, TrueClass]], API.api_methods[:named_signature].expects.map{|x| [x.name, x.type_class]})
assert_equal(nil, API.api_methods[:named_signature].returns)
- assert_equal([Integer, String, TrueClass], API.api_methods[:string_types].expects)
+ assert_equal([Integer, String, TrueClass], API.api_methods[:string_types].expects.map{|x| x.type_class})
assert_equal(nil, API.api_methods[:string_types].returns)
- assert_equal([TrueClass, Integer, String], API.api_methods[:class_types].expects)
+ assert_equal([TrueClass, Integer, String], API.api_methods[:class_types].expects.map{|x| x.type_class})
assert_equal(nil, API.api_methods[:class_types].returns)
end
@@ -75,6 +75,6 @@ class TC_API < Test::Unit::TestCase
end
def test_to_s
- assert_equal 'void Expects(int p1, bool p2)', APITest::API.api_methods[:expects].to_s
+ assert_equal 'void Expects(int param0, bool param1)', APITest::API.api_methods[:expects].to_s
end
end
diff --git a/actionwebservice/test/casting_test.rb b/actionwebservice/test/casting_test.rb
new file mode 100644
index 0000000000..223313564b
--- /dev/null
+++ b/actionwebservice/test/casting_test.rb
@@ -0,0 +1,82 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+
+module CastingTest
+ class API < ActionWebService::API::Base
+ api_method :int, :expects => [:int]
+ api_method :str, :expects => [:string]
+ api_method :bool, :expects => [:bool]
+ api_method :float, :expects => [:float]
+ api_method :time, :expects => [:time]
+ api_method :datetime, :expects => [:datetime]
+ api_method :date, :expects => [:date]
+
+ api_method :int_array, :expects => [[:int]]
+ api_method :str_array, :expects => [[:string]]
+ api_method :bool_array, :expects => [[:bool]]
+ end
+end
+
+class TC_Casting < Test::Unit::TestCase
+ include CastingTest
+
+ def test_base_type_casting_valid
+ assert_equal 10000, cast_expects(:int, '10000')[0]
+ assert_equal '10000', cast_expects(:str, 10000)[0]
+ [1, '1', 'true', 'y', 'yes'].each do |val|
+ assert_equal true, cast_expects(:bool, val)[0]
+ end
+ [0, '0', 'false', 'n', 'no'].each do |val|
+ assert_equal false, cast_expects(:bool, val)[0]
+ end
+ assert_equal 3.14159, cast_expects(:float, '3.14159')[0]
+ now = Time.at(Time.now.tv_sec)
+ casted = cast_expects(:time, now.to_s)[0]
+ assert_equal now, casted
+ now = DateTime.now
+ assert_equal now.to_s, cast_expects(:datetime, now.to_s)[0].to_s
+ today = Date.today
+ assert_equal today, cast_expects(:date, today.to_s)[0]
+ end
+
+ def test_base_type_casting_invalid
+ assert_raises ArgumentError do
+ cast_expects(:int, 'this is not a number')
+ end
+ assert_raises ActionWebService::Casting::CastingError do
+ # neither true or false ;)
+ cast_expects(:bool, 'i always lie')
+ end
+ assert_raises ArgumentError do
+ cast_expects(:float, 'not a float')
+ end
+ assert_raises ArgumentError do
+ cast_expects(:time, '111111111111111111111111111111111')
+ end
+ assert_raises ArgumentError do
+ cast_expects(:datetime, '-1')
+ end
+ assert_raises ArgumentError do
+ cast_expects(:date, '')
+ end
+ end
+
+ def test_array_type_casting
+ assert_equal [1, 2, 3213992, 4], cast_expects(:int_array, ['1', '2', '3213992', '4'])[0]
+ assert_equal ['one', 'two', '5.0', '200', '', 'true'], cast_expects(:str_array, [:one, 'two', 5.0, 200, nil, true])[0]
+ assert_equal [true, false, true, true, false], cast_expects(:bool_array, ['1', nil, 'y', true, 'false'])[0]
+ end
+
+ def test_array_type_casting_failure
+ assert_raises ActionWebService::Casting::CastingError do
+ cast_expects(:bool_array, ['false', 'blahblah'])
+ end
+ assert_raises ArgumentError do
+ cast_expects(:int_array, ['1', '2.021', '4'])
+ end
+ end
+
+ private
+ def cast_expects(method_name, *args)
+ API.api_method_instance(method_name.to_sym).cast_expects([*args])
+ end
+end
diff --git a/actionwebservice/test/client_soap_test.rb b/actionwebservice/test/client_soap_test.rb
index 941a642554..e118b4956e 100644
--- a/actionwebservice/test/client_soap_test.rb
+++ b/actionwebservice/test/client_soap_test.rb
@@ -68,9 +68,7 @@ class TC_ClientSoap < Test::Unit::TestCase
assert_equal([5, 6], @container.value_normal)
assert_equal(5, @client.normal("7", "8"))
assert_equal([7, 8], @container.value_normal)
- assert_raises(TypeError) do
- assert_equal(5, @client.normal(true, false))
- end
+ assert_equal(5, @client.normal(true, false))
end
def test_array_return
diff --git a/actionwebservice/test/client_xmlrpc_test.rb b/actionwebservice/test/client_xmlrpc_test.rb
index 3301113d95..de24d9a975 100644
--- a/actionwebservice/test/client_xmlrpc_test.rb
+++ b/actionwebservice/test/client_xmlrpc_test.rb
@@ -15,6 +15,7 @@ module ClientXmlRpcTest
@controller.process(test_request, response)
res.header['content-type'] = 'text/xml'
res.body = response.body
+ # puts res.body
rescue Exception => e
$stderr.puts e.message
$stderr.puts e.backtrace.join("\n")
@@ -62,9 +63,7 @@ class TC_ClientXmlRpc < Test::Unit::TestCase
assert_equal([5, 6], @container.value_normal)
assert_equal(5, @client.normal("7", "8"))
assert_equal([7, 8], @container.value_normal)
- assert_raises(TypeError) do
- assert_equal(5, @client.normal(true, false))
- end
+ assert_equal(5, @client.normal(true, false))
end
def test_array_return
@@ -91,7 +90,7 @@ class TC_ClientXmlRpc < Test::Unit::TestCase
def test_named_parameters
assert(@container.value_named_parameters.nil?)
- assert_equal(nil, @client.named_parameters("xxx", 7))
+ assert_equal(true, @client.named_parameters("xxx", 7))
assert_equal(["xxx", 7], @container.value_named_parameters)
end
diff --git a/actionwebservice/test/dispatcher_action_controller_soap_test.rb b/actionwebservice/test/dispatcher_action_controller_soap_test.rb
index 76fc6094c2..3d7327be02 100644
--- a/actionwebservice/test/dispatcher_action_controller_soap_test.rb
+++ b/actionwebservice/test/dispatcher_action_controller_soap_test.rb
@@ -23,8 +23,6 @@ class TC_DispatcherActionControllerSoap < Test::Unit::TestCase
include DispatcherCommonTests
def setup
- @encoder = WS::Encoding::SoapRpcEncoding.new 'urn:ActionWebService'
- @marshaler = WS::Marshaling::SoapMarshaler.new 'urn:ActionWebService'
@direct_controller = DirectController.new
@delegated_controller = DelegatedController.new
@virtual_controller = VirtualController.new
diff --git a/actionwebservice/test/dispatcher_action_controller_xmlrpc_test.rb b/actionwebservice/test/dispatcher_action_controller_xmlrpc_test.rb
index c92f270a1b..f1dc992818 100644
--- a/actionwebservice/test/dispatcher_action_controller_xmlrpc_test.rb
+++ b/actionwebservice/test/dispatcher_action_controller_xmlrpc_test.rb
@@ -6,8 +6,6 @@ class TC_DispatcherActionControllerXmlRpc < Test::Unit::TestCase
def setup
@protocol = ActionWebService::Protocol::XmlRpc::XmlRpcProtocol.new
- @encoder = WS::Encoding::XmlRpcEncoding.new
- @marshaler = WS::Marshaling::XmlRpcMarshaler.new
@direct_controller = DirectController.new
@delegated_controller = DelegatedController.new
@layered_controller = LayeredController.new
diff --git a/actionwebservice/test/scaffolded_controller_test.rb b/actionwebservice/test/scaffolded_controller_test.rb
new file mode 100644
index 0000000000..2fa3a6030c
--- /dev/null
+++ b/actionwebservice/test/scaffolded_controller_test.rb
@@ -0,0 +1,67 @@
+require File.dirname(__FILE__) + '/abstract_unit'
+
+ActionController::Routing::Routes.draw do |map|
+ map.connect '', :controller => 'scaffolded'
+end
+
+class ScaffoldPerson < ActionWebService::Struct
+ member :id, :int
+ member :name, :string
+
+ def ==(other)
+ self.id == other.id && self.name == other.name
+ end
+end
+
+class ScaffoldedControllerTestAPI < ActionWebService::API::Base
+ api_method :hello, :expects => [{:integer=>:int}, :string], :returns => [:bool]
+ api_method :bye, :returns => [[ScaffoldPerson]]
+end
+
+class ScaffoldedController < ActionController::Base
+ web_service_api ScaffoldedControllerTestAPI
+ web_service_scaffold :scaffold_invoke
+
+ def hello(int, string)
+ 0
+ end
+
+ def bye
+ [ScaffoldPerson.new(:id => 1, :name => "leon"), ScaffoldPerson.new(:id => 2, :name => "paul")]
+ end
+
+ def rescue_action(e)
+ raise e
+ end
+end
+
+class ScaffoldedControllerTest < Test::Unit::TestCase
+ def setup
+ @controller = ScaffoldedController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ end
+
+ def test_scaffold_invoke
+ get :scaffold_invoke
+ assert_rendered_file 'methods.rhtml'
+ end
+
+ def test_scaffold_invoke_method_params
+ get :scaffold_invoke_method_params, :service => 'scaffolded', :method => 'Hello'
+ assert_rendered_file 'parameters.rhtml'
+ end
+
+ def test_scaffold_invoke_submit_hello
+ post :scaffold_invoke_submit, :service => 'scaffolded', :method => 'Hello', :method_params => ['5', 'hello world']
+ assert_rendered_file 'result.rhtml'
+ assert_equal false, @controller.instance_eval{ @method_return_value }
+ end
+
+ def test_scaffold_invoke_submit_bye
+ post :scaffold_invoke_submit, :service => 'scaffolded', :method => 'Bye'
+ assert_rendered_file 'result.rhtml'
+ persons = [ScaffoldPerson.new(:id => 1, :name => "leon"), ScaffoldPerson.new(:id => 2, :name => "paul")]
+ assert_equal persons, @controller.instance_eval{ @method_return_value }
+ end
+end
diff --git a/actionwebservice/test/struct_test.rb b/actionwebservice/test/struct_test.rb
index e6f1603c73..838cc2569c 100644
--- a/actionwebservice/test/struct_test.rb
+++ b/actionwebservice/test/struct_test.rb
@@ -11,30 +11,44 @@ module StructTest
end
class TC_Struct < Test::Unit::TestCase
+ include StructTest
+
+ def setup
+ @struct = Struct.new(:id => 5,
+ :name => 'hello',
+ :items => ['one', 'two'],
+ :deleted => true,
+ :emails => ['test@test.com'])
+ end
+
def test_members
- assert_equal(5, StructTest::Struct.members.size)
- assert_equal(Integer, StructTest::Struct.members[:id])
- assert_equal(String, StructTest::Struct.members[:name])
- assert_equal([String], StructTest::Struct.members[:items])
- assert_equal(TrueClass, StructTest::Struct.members[:deleted])
- assert_equal([String], StructTest::Struct.members[:emails])
+ assert_equal(5, Struct.members.size)
+ assert_equal(Integer, Struct.members[:id].type_class)
+ assert_equal(String, Struct.members[:name].type_class)
+ assert_equal(String, Struct.members[:items].element_type.type_class)
+ assert_equal(TrueClass, Struct.members[:deleted].type_class)
+ assert_equal(String, Struct.members[:emails].element_type.type_class)
end
def test_initializer_and_lookup
- s = StructTest::Struct.new(:id => 5,
- :name => 'hello',
- :items => ['one', 'two'],
- :deleted => true,
- :emails => ['test@test.com'])
- assert_equal(5, s.id)
- assert_equal('hello', s.name)
- assert_equal(['one', 'two'], s.items)
- assert_equal(true, s.deleted)
- assert_equal(['test@test.com'], s.emails)
- assert_equal(5, s['id'])
- assert_equal('hello', s['name'])
- assert_equal(['one', 'two'], s['items'])
- assert_equal(true, s['deleted'])
- assert_equal(['test@test.com'], s['emails'])
+ assert_equal(5, @struct.id)
+ assert_equal('hello', @struct.name)
+ assert_equal(['one', 'two'], @struct.items)
+ assert_equal(true, @struct.deleted)
+ assert_equal(['test@test.com'], @struct.emails)
+ assert_equal(5, @struct['id'])
+ assert_equal('hello', @struct['name'])
+ assert_equal(['one', 'two'], @struct['items'])
+ assert_equal(true, @struct['deleted'])
+ assert_equal(['test@test.com'], @struct['emails'])
+ end
+
+ def test_each_pair
+ members = {}
+ @struct.each_pair do |name, type|
+ members[name] = type
+ assert ActionWebService::BaseType === type
+ end
+ assert_equal members, Struct.members
end
end
diff --git a/actionwebservice/test/test_invoke_test.rb b/actionwebservice/test/test_invoke_test.rb
index cbfde9c3df..fb992472f4 100644
--- a/actionwebservice/test/test_invoke_test.rb
+++ b/actionwebservice/test/test_invoke_test.rb
@@ -65,7 +65,7 @@ class TestInvokeTest < Test::Unit::TestCase
end
def test_layered_add
- @protocol = :xmlrpc
+ @protocol = ActionWebService::Protocol::XmlRpc::XmlRpcProtocol.new
@controller = TestInvokeLayeredController.new
[:one, :two].each do |service|
assert_equal nil, @controller.web_service_object(service).invoked
diff --git a/actionwebservice/test/ws/abstract_encoding.rb b/actionwebservice/test/ws/abstract_encoding.rb
deleted file mode 100644
index 6032d94c48..0000000000
--- a/actionwebservice/test/ws/abstract_encoding.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-require File.dirname(__FILE__) + '/abstract_unit'
-
-module Nested
- class StructClass
- attr_accessor :name
- attr_accessor :version
-
- def initialize
- @name = 5
- @version = "1.0"
- end
-
- def ==(other)
- @name == other.name && @version == other.version
- end
- end
-end
-
-module EncodingTest
- def setup
- @call_signature = [:int, :bool, :string, :float, [:time], Nested::StructClass]
- @call_params = [1, true, "string", 5.0, [Time.now], Nested::StructClass.new]
- @response_signature = [:string]
- @response_param = "hello world"
- test_setup
- end
-
- def test_abstract
- obj = WS::Encoding::AbstractEncoding.new
- assert_raises(NotImplementedError) do
- obj.encode_rpc_call(nil, nil)
- end
- assert_raises(NotImplementedError) do
- obj.decode_rpc_call(nil)
- end
- assert_raises(NotImplementedError) do
- obj.encode_rpc_response(nil, nil)
- end
- assert_raises(NotImplementedError) do
- obj.decode_rpc_response(nil)
- end
- end
-
- def encode_rpc_call(method_name, signature, params)
- params = params.dup
- (0..(signature.length-1)).each do |i|
- type_binding = @marshaler.register_type(signature[i])
- info = WS::ParamInfo.create(signature[i], type_binding, i)
- params[i] = @marshaler.marshal(WS::Param.new(params[i], info))
- end
- @encoder.encode_rpc_call(method_name, params)
- end
-
- def decode_rpc_call(obj)
- @encoder.decode_rpc_call(obj)
- end
-
- def encode_rpc_response(method_name, signature, param)
- type_binding = @marshaler.register_type(signature[0])
- info = WS::ParamInfo.create(signature[0], type_binding, 0)
- param = @marshaler.marshal(WS::Param.new(param, info))
- @encoder.encode_rpc_response(method_name, param)
- end
-
- def decode_rpc_response(obj)
- @encoder.decode_rpc_response(obj)
- end
-end
diff --git a/actionwebservice/test/ws/abstract_unit.rb b/actionwebservice/test/ws/abstract_unit.rb
deleted file mode 100644
index 5d4f5ce856..0000000000
--- a/actionwebservice/test/ws/abstract_unit.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require 'pathname'
-$:.unshift(Pathname.new(File.dirname(__FILE__)).realpath.to_s + '/../../lib/action_web_service/vendor')
-require 'test/unit'
-require 'ws'
-begin
- require 'active_record'
-rescue LoadError
- begin
- require 'rubygems'
- require_gem 'activerecord', '>= 1.6.0'
- rescue LoadError
- end
-end
diff --git a/actionwebservice/test/ws/gencov b/actionwebservice/test/ws/gencov
deleted file mode 100755
index 144233107a..0000000000
--- a/actionwebservice/test/ws/gencov
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-
-rcov -x '.*_test\.rb,rubygems,abstract_,/run' ./run
diff --git a/actionwebservice/test/ws/run b/actionwebservice/test/ws/run
deleted file mode 100755
index 5c6f8b2bc2..0000000000
--- a/actionwebservice/test/ws/run
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env ruby
-
-Dir[File.join(File.dirname(__FILE__), '*_test.rb')].each do |f|
- require f
-end
diff --git a/actionwebservice/test/ws/soap_marshaling_test.rb b/actionwebservice/test/ws/soap_marshaling_test.rb
deleted file mode 100644
index f350ad1124..0000000000
--- a/actionwebservice/test/ws/soap_marshaling_test.rb
+++ /dev/null
@@ -1,97 +0,0 @@
-require File.dirname(__FILE__) + '/abstract_unit'
-
-module Nested
- class MyClass
- attr_accessor :id
- attr_accessor :name
-
- def initialize(id, name)
- @id = id
- @name = name
- end
-
- def ==(other)
- @id == other.id && @name == other.name
- end
- end
-end
-
-class SoapMarshalingTest < Test::Unit::TestCase
- def setup
- @marshaler = WS::Marshaling::SoapMarshaler.new
- end
-
- def test_abstract
- marshaler = WS::Marshaling::AbstractMarshaler.new
- assert_raises(NotImplementedError) do
- marshaler.marshal(nil)
- end
- assert_raises(NotImplementedError) do
- marshaler.unmarshal(nil)
- end
- assert_equal(nil, marshaler.register_type(nil))
- assert_raises(NotImplementedError) do
- marshaler.cast_inbound_recursive(nil, nil)
- end
- assert_raises(NotImplementedError) do
- marshaler.cast_outbound_recursive(nil, nil)
- end
- end
-
- def test_marshaling
- info = WS::ParamInfo.create(Nested::MyClass, @marshaler.register_type(Nested::MyClass))
- param = WS::Param.new(Nested::MyClass.new(2, "name"), info)
- new_param = @marshaler.unmarshal(@marshaler.marshal(param))
- assert(param == new_param)
- end
-
- def test_exception_marshaling
- info = WS::ParamInfo.create(RuntimeError, @marshaler.register_type(RuntimeError))
- param = WS::Param.new(RuntimeError.new("hello, world"), info)
- new_param = @marshaler.unmarshal(@marshaler.marshal(param))
- assert_equal("hello, world", new_param.value.detail.cause.message)
- end
-
- def test_registration
- type_binding1 = @marshaler.register_type(:int)
- type_binding2 = @marshaler.register_type(:int)
- assert(type_binding1.equal?(type_binding2))
- end
-
- def test_active_record
- if Object.const_defined?('ActiveRecord')
- node_class = Class.new(ActiveRecord::Base) do
- def initialize(*args)
- super(*args)
- @new_record = false
- end
-
- class << self
- def name
- "Node"
- end
-
- def columns(*args)
- [
- ActiveRecord::ConnectionAdapters::Column.new('id', 0, 'int'),
- ActiveRecord::ConnectionAdapters::Column.new('name', nil, 'string'),
- ActiveRecord::ConnectionAdapters::Column.new('email', nil, 'string'),
- ]
- end
-
- def connection
- self
- end
- end
- end
- info = WS::ParamInfo.create(node_class, @marshaler.register_type(node_class), 0)
- ar_obj = node_class.new('name' => 'hello', 'email' => 'test@test.com')
- param = WS::Param.new(ar_obj, info)
- obj = @marshaler.marshal(param)
- param = @marshaler.unmarshal(obj)
- new_ar_obj = param.value
- assert_equal(ar_obj, new_ar_obj)
- assert(!ar_obj.equal?(new_ar_obj))
- end
- end
-end
diff --git a/actionwebservice/test/ws/soap_rpc_encoding_test.rb b/actionwebservice/test/ws/soap_rpc_encoding_test.rb
deleted file mode 100644
index e5dcbfeb1b..0000000000
--- a/actionwebservice/test/ws/soap_rpc_encoding_test.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-require File.dirname(__FILE__) + '/abstract_encoding'
-require 'time'
-
-class SoapRpcEncodingTest < Test::Unit::TestCase
- include EncodingTest
-
- def test_setup
- @encoder = WS::Encoding::SoapRpcEncoding.new
- @marshaler = WS::Marshaling::SoapMarshaler.new
- end
-
- def test_call_encoding_and_decoding
- obj = encode_rpc_call('DecodeMe', @call_signature, @call_params)
- method_name, decoded_params = decode_rpc_call(obj)
- params = decoded_params.map{|x| @marshaler.unmarshal(x).value}
- assert_equal(method_name, 'DecodeMe')
- assert_equal(@call_params[0..3], params[0..3])
- # XXX: DateTime not marshaled correctly yet
- assert_equal(@call_params[5..-1], params[5..-1])
- end
-
- def test_response_encoding_and_decoding_simple
- obj = encode_rpc_response('DecodeMe', @response_signature, @response_param)
- method_name, return_value = decode_rpc_response(obj)
- return_value = @marshaler.unmarshal(return_value).value
- assert_equal('DecodeMe', method_name)
- assert_equal(@response_param, return_value)
- end
-
- def test_response_encoding_and_decoding_struct
- struct = Nested::StructClass.new
- obj = encode_rpc_response('DecodeMe', [Nested::StructClass], struct)
- method_name, return_value = decode_rpc_response(obj)
- return_value = @marshaler.unmarshal(return_value).value
- assert_equal('DecodeMe', method_name)
- assert_equal(struct, return_value)
- end
-
- def test_response_encoding_and_decoding_array
- struct = Nested::StructClass.new
- obj = encode_rpc_response('DecodeMe', [[Nested::StructClass]], [struct])
- method_name, return_value = decode_rpc_response(obj)
- return_value = @marshaler.unmarshal(return_value).value
- assert_equal('DecodeMe', method_name)
- assert_equal([struct], return_value)
- end
-end
diff --git a/actionwebservice/test/ws/types_test.rb b/actionwebservice/test/ws/types_test.rb
deleted file mode 100644
index e66ae65945..0000000000
--- a/actionwebservice/test/ws/types_test.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-require File.dirname(__FILE__) + '/abstract_unit'
-
-class TypesTest < Test::Unit::TestCase
- include WS
-
- def setup
- @caster = BaseTypeCaster.new
- end
-
- def test_base_types
- assert_equal(:int, BaseTypes.canonical_type_name(:integer))
- assert_equal(:int, BaseTypes.canonical_type_name(:fixnum))
- assert_equal(Integer, BaseTypes.type_name_to_class(:bignum))
- assert_equal(Date, BaseTypes.type_name_to_class(:date))
- assert_equal(Time, BaseTypes.type_name_to_class(:timestamp))
- assert_equal(TrueClass, BaseTypes.type_name_to_class(:bool))
- assert_equal(:int, BaseTypes.class_to_type_name(Bignum))
- assert_equal(:bool, BaseTypes.class_to_type_name(FalseClass))
- assert_equal(Integer, BaseTypes.canonical_type_class(Fixnum))
- assert_raises(TypeError) do
- BaseTypes.canonical_type_name(:fake)
- end
- end
-
- def test_casting
- assert_equal(5, @caster.cast("5", Fixnum))
- assert_equal('50.0', @caster.cast(50.0, String))
- assert_equal(true, @caster.cast('true', FalseClass))
- assert_equal(false, @caster.cast('false', TrueClass))
- assert_equal(true, @caster.cast(1, FalseClass))
- assert_equal(false, @caster.cast(0, TrueClass))
- assert_raises(TypeError) do
- @caster.cast('yes', FalseClass)
- end
- assert_equal(3.14159, @caster.cast('3.14159', Float))
- now1 = Time.new
- now2 = @caster.cast("#{now1}", Time)
- assert_equal(now1.tv_sec, now2.tv_sec)
- date1 = Date.parse('2004-01-01')
- date2 = @caster.cast("#{date1}", Date)
- assert_equal(date1, date2)
- end
-end
diff --git a/actionwebservice/test/ws/xmlrpc_encoding_test.rb b/actionwebservice/test/ws/xmlrpc_encoding_test.rb
deleted file mode 100644
index 45aaa901bd..0000000000
--- a/actionwebservice/test/ws/xmlrpc_encoding_test.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require File.dirname(__FILE__) + '/abstract_encoding'
-require 'time'
-
-class XmlRpcEncodingTest < Test::Unit::TestCase
- include EncodingTest
-
- def test_setup
- @encoder = WS::Encoding::XmlRpcEncoding.new
- @marshaler = WS::Marshaling::XmlRpcMarshaler.new
- end
-
- def test_typed_call_encoding_and_decoding
- obj = encode_rpc_call('DecodeMe', @call_signature, @call_params)
- method_name, params = decode_rpc_call(obj)
- (0..(@call_signature.length-1)).each do |i|
- params[i] = @marshaler.typed_unmarshal(params[i], @call_signature[i]).value
- end
- assert_equal(method_name, 'DecodeMe')
- assert_equal(@call_params[0..3], params[0..3])
- assert_equal(@call_params[5..-1], params[5..-1])
- end
-
- def test_untyped_call_encoding_and_decoding
- obj = encode_rpc_call('DecodeMe', @call_signature, @call_params)
- method_name, params = decode_rpc_call(obj)
- (0..(@call_signature.length-1)).each do |i|
- params[i] = @marshaler.unmarshal(params[i]).value
- end
- assert_equal(method_name, 'DecodeMe')
- assert_equal(@call_params[0..3], params[0..3])
- assert_equal(@call_params[5].name, params[5]['name'])
- assert_equal(@call_params[5].version, params[5]['version'])
- end
-end